Skip to content

licensing: âncora ML-DSA embutida ausente e híbrido ainda opcional no guard (canon: Ed25519 + ML-DSA obrigatório) #2042

Closed

Description

@FabioLeitao

Contexto

Canon do operador (repetido várias vezes): a licença do Boar e de todo o roster bestial é híbrida Ed25519 + ML-DSA-65, obrigatória — é o modo mínimo de licença, não uma opção. Em 2026-10-05 um levantamento dos verificadores mostrou onde o data-boar ainda não cumpre isso. Estado verificado via gh api em DataBoar/data-boar@main, não pelo clone local.

O que existe hoje

  1. Âncora ML-DSA ausente. core/licensing/ traz só license-pub-v1.pem (Ed25519). guard.py carrega a âncora por trust_anchor.load_embedded_mldsa_anchor_pem(), que não tem arquivo para ler. Os consumidores irmãos já documentam essa espera: faithful-ferret (trust_anchor.clj: "data-boar main does not ship license-mldsa-pub-v1.pem") e sage-remora (trust_anchor.clj, mesma frase). O resultado nos dois foi um verificador que recusava ou degradava, até que cada um vendorizou a chave por conta própria.
  2. Híbrido opcional no verify/guard. core/licensing/guard.py::_token_has_mldsa_claim diz no docstring: "only an absent key selects Ed25519-only verification". Token sem dbmldsa_sig verifica só com Ed25519. verify.py descreve o claim como "Optional hybrid PQC claim".

Âncora canônica (já em uso)

  • ~/.keys/data-boar/golden-mldsa.pub = keen-platypus/go/kp-license-check/trust/golden-mldsa.pub, sha256 37faef8ff167cf01a0fc6a2bc8b7cfcac6bfe5651360051b1eb00a0a60fa85b8.
  • Cadeia verificada em 2026-10-05 com kp-license-check -verify-cross-sign: OK Ed25519 signs ML-DSA-65 pubkey e OK ML-DSA-65 signs Ed25519 pubkey (PKIX DER).
  • O kp-license-check já é obrigatório (verifyTokenHybridRequired). O sage-remora está na branch fix/hybrid-license-required (commit d474be2, sem push) e o faithful-ferret recebe a mesma correção.

Escopo proposto (cada item é um commit)

  • Vendorizar core/licensing/license-mldsa-pub-v1.pem = a chave canônica acima, com teste que fixa o sha256.
  • dbmldsa_sig ausente deixa de selecionar Ed25519-only: token sem a claim é inválido. null, vazio e não-string já falham fechado.
  • Âncora ausente = falha fechada, sem cair para Ed25519.
  • Atualizar docs e docstrings que descrevem o híbrido como opcional.

Cuidado de compatibilidade

Tornar o híbrido obrigatório rejeita licenças emitidas só com Ed25519 (por exemplo os .lic curtos antigos). O release 1.7.4 GA já saiu com o híbrido opcional, então isso é mudança de comportamento para 1.8.x. Precisa de nota no CHANGELOG e de um caminho de reemissão. O emissor de dev tem issue própria (ver "Relacionado").

Fora de escopo

Rotação de chave. O contrato de rotação (attestation assinada pelas duas âncoras) já existe e não muda.

Relacionado

Épico #1462 (crypto agility + hybrid PQC). KP#375 (Remora recusava o JWT híbrido por falta da âncora). Emissor de dev sem ML-DSA: issue irmã.

Verifique antes de implementar: gh api repos/DataBoar/data-boar/contents/core/licensing/guard.py (as linhas citadas acima) — não confiar no clone local.

Activity

  1. FabioLeitao commented on Oct 20, 2026

    @FabioLeitao
    CollaboratorAuthor

    Atualização de escopo (auditoria, tom recomendatório) — verificado contra origin/main @ 9fdd2434, 2026-10-19.

    Canon confirmado pelo operador: toda licença é híbrida Ed25519 + ML-DSA-65, sem modo opcional. Não há decisão pendente aqui; o que resta é fechar o que a main ainda não cumpre.

    Já feito na main (marcar no escopo):

    Ainda aberto (confirmar por símbolo com git grep -n, as linhas mudaram):

    • core/licensing/guard.py::_token_has_mldsa_claim — o docstring ainda diz que só a chave ausente seleciona verificação Ed25519-only; core/licensing/verify.py::decode_license_jwt_hybrid e o comentário de CLAIM_MLDSA_SIG ("Optional hybrid PQC claim") descrevem o híbrido como opcional. Token sem a claim precisa ser inválido, e âncora ausente também falha fechada (sem queda para Ed25519).
    • Docs/docstrings que chamam o híbrido de opcional (inclui LICENSING_SPEC).
    • CHANGELOG + caminho de reemissão: o 1.7.4 GA saiu com o híbrido opcional, então licenças só-Ed25519 deixam de valer em 1.8.x.

    Recomendações:

    1. Teste vermelho primeiro: token sem dbmldsa_sig recusado; depois a correção.
    2. A âncora de teste do licensing: emissor de licença de dev (issue_dev_license_jwt.py) não emite ML-DSA — quebra o Maestro quando o híbrido for obrigatório #2043 não pode virar override de chave crua em produção (o security(licensing): cross-signed key rotation, no raw key override #1994 removeu isso de propósito). Só em build/ambiente de teste, como o -tags licensetest do kp-license-check.
    3. Mesmo padrão já aplicado em sage-remora (I would like to try to change the default availability of the reports menu (currently to every one logged in), to a more controled way, probably via a permission flag to an specific role or group of users... #86) e faithful-ferret (Docs detect host 64903 #53).
    4. Marco sugerido: v1.8.0. licensing: âncora ML-DSA embutida ausente e híbrido ainda opcional no guard (canon: Ed25519 + ML-DSA obrigatório) #2042 e licensing: emissor de licença de dev (issue_dev_license_jwt.py) não emite ML-DSA — quebra o Maestro quando o híbrido for obrigatório #2043 andam juntas (o Maestro quebra se só uma entrar). Quantas PRs: decisão do operador; minha recomendação é uma só para as duas, ou commits separados dentro do PR de hardening.
    5. Closes só quando os critérios de aceite forem cumpridos de fato.

    Rodapé: comentário gerado por Claude (auditor RO), sem alteração de código.

  2. FabioLeitao commented on Oct 20, 2026

    @FabioLeitao
    CollaboratorAuthor

    Resolvida pela PR #2114 (merge 87f1fe0). Commit 0c0adbb: em modo enforced, dbmldsa_sig é obrigatório e âncora ML-DSA ausente falha fechada. Testes em tests/test_decode_license_jwt_hybrid_invalid_mldsa_claim.py: test_license_guard_missing_mldsa_anchor_is_invalid e a rejeição hybrid_claim_required. Verificação via Robin segue em homing-robin#75, fora deste escopo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions