Pular para conteúdo

AUR-563: tutoriais executaveis da cadeia de suprimentos

O que entrega

  • Cinco tutoriais em docs/tutorials/ (pt-BR), linkados da pagina inicial (docs/index.md, secao Cadeia de suprimentos) e do indice docs/tutorials/README.md: sast, sbom-dependency-track, assinatura, xbom, dados-de-analise.
  • As demonstracoes em demo/tutoriais/<tutorial>/ (run.sh com uma fase por caso, expected/, out/ da execucao real, repositorios-exemplo).
  • demo/tutoriais/_lib/cadeia.sh (arquivo novo em _lib; o tutorial.sh do AUR-561 nao foi alterado): le o images.lock do guia corporativo (AUR-554) em vez de copiar digests (cad_lock, cad_pull, cad_bins, cad_run).
  • tests/acceptance/AUR-563.sh: all, AC-001..AC-004, AC-002-MUT-001; seletor desconhecido sai 64.

Decisoes

  • Mesmo contrato do AUR-561. Blocos <!-- arquivo: PATH --> identicos aos arquivos; <!-- saida: caso --> com linhas literais do out/; --check por grep -F; linhas RESULTADO: sao conclusao do script.
  • Nenhum digest digitado a mao. O unico lugar com digests e demo/gate-corporativo/images.lock; compose.yml do Dependency-Track usa ${DTRACK_IMAGE}/${POSTGRES_IMAGE} exportados pelo run.sh a partir dele. O Semgrep e o da imagem do produto (versao de .board/bootstrap/locks/scanners.yml).
  • Provedor sempre fixture; aurumcode sempre na imagem do produto, com --user "$(id -u):$(id -g)". Rede: none, exceto sbom-dependency-track (--network host: o gate so aceita https ou IP de loopback) e dados-de-analise (um servidor falso que atende como a API do GitHub dentro do mesmo container, com CA de demonstracao gerado a cada execucao em .estado/).
  • api.github.com no aceite. O produto fixa esse endereco para o analysis_data (nao ha variavel que o troque); o AC-003 o admite na lista de dominios, junto dos reservados. E a API publica do GitHub, nao dado interno.

Achados sobre o produto

  1. Corrida nas metricas do Dependency-Track (grave). O gate le as metricas assim que o servidor responde processing: false, e a avaliacao de politica pode terminar depois. Num servidor novo, a primeira revisao com lodash 4.17.15 leu policy_violations=0 e aprovou o que a politica reprova (2 de 2 vezes); em outra execucao, logo apos trocar a dependencia, leu a violacao antiga e reprovou. O tutorial contorna com um aquecimento e a funcao dt_assenta (linha assentamento: nos out/) e declara que e contorno do script. Causa nao investigada; vale um card (reler ate estabilizar).
  2. --semgrep-bin nao existe: o Semgrep e resolvido pelo PATH (cmd/aurumcode/aur548.go). O caso de falha poe um Semgrep falso a frente no PATH.
  3. O check_id leva o caminho do arquivo de regras (semgrep:regras.demo-sem-eval no repositorio; semgrep:policy.regras.demo-sem-eval sob politica em /policy). rule_packs local e relativo ao repositorio; sob politica precisa ser absoluto.
  4. Com o SAST inconclusivo o parecer ainda diz No issues found.; so as linhas SAST ... inconclusive mostram o estado real.
  5. O endereco da API do GitHub do analysis_data e fixo no binario; so o seam de teste Go o troca. AURUMCODE_GITHUB_API_URL vale so para o cliente de PR.
  6. aurumcode sign valida o arquivo do bundle, nao o exit do Cosign: Cosign que sai 0 sem bundle falha (cosign exited 0 but wrote no signature bundle). Sem quality_gates.supply_chain, sign sai 0 sem assinar. Falha de assinatura usa o exit 1 generico (exitQualityNotReviewed).
  7. xbom --help imprime so a linha de uso (sem lista de flags); a politica central precisa de .aurumcode/config.yml valido mesmo para xbom; um catalogo do repositorio ou da politica substitui o embutido por inteiro.
  8. Resultado inconclusivo de analysis_data ou do Dependency-Track deixa o veredito em Comment, nunca Approve, com warn ou block.
  9. O Trivy lista package-lock.json@None como componente de arquivo sem versao.

Limites (o que NAO foi demonstrado)

  • Pacote do registry do Semgrep com sucesso (p/...): exige rede; o caso prova so a falha sem rede (e nao distingue timeout de recusa de rede).
  • max_critical/max_high: o Trivy roda com --scanners license e o servidor nao tem feeds, entao critical/high ficam 0; so policy_violations e provado. dtrack_unreachable, dtrack_http_error e 403 nao foram executados.
  • Timeout do Dependency-Track: provado contra um servidor falso (sempre processing: true), nao contra o Dependency-Track real.
  • Assinatura keyless, upload do artefato e verify-blob keyless: so conferencia estatica (exigem o OIDC do GitHub Actions). Assinatura de imagem real (exige registry).
  • xBOM: envio ao Dependency-Track, modelo real, prompt sobrescrito pela politica.
  • analysis_data: GitHub real, release imutavel, repositorio privado com token, analysis_data_invalid, download da copia OSV. O workflow agendado so e conferido estaticamente. Nao ha runner real do GitHub em nenhum tutorial.

Imagens (por digest, de demo/gate-corporativo/images.lock)

dtrack_apiserver=dependencytrack/apiserver@sha256:764dee822521e43d50ad7d0ca5bc35f48968b6b098ef97945e2ecac8c55d52e5
postgres=library/postgres@sha256:b0f9560a2de083e2cc7382e75f808c7381a32852a7ec49117deedb300e552b24
trivy=aquasec/trivy@sha256:7cced7cae583819fc7806d4cbc0dbbc7cad18b99f7d3e235192e6da8c091045c
semgrep=semgrep/semgrep@sha256:65dcd4408adda7c183a6b4550cb1e9b19f7f627a6fbb7e0559bd466bedc44d7b
cosign=sigstore/cosign/cosign@sha256:9e5c2f2edc34351160407ca3416c61855bdf9403c3c5936e0f0be7fc261611b8

Baixadas so para a demonstracao e removidas ao final: dtrack_apiserver, postgres (pelo down) e cosign. O trivy e o semgrep ja estavam no host por outros usos do repositorio e nao foram removidos.

Execucao real

Execucao real, em container, com a imagem aurum-tutoriais:local construida do Dockerfile do worktree, provedor fixture e a rede descrita acima: bash demo/tutoriais/<t>/run.sh all (os cinco terminaram com exit 0) e run.sh --check. A saida completa de cada caso e demo/tutoriais/<t>/out/<caso>.log (1235 linhas no total). No fim do sbom-dependency-track, o caso down mediu 0 containers, redes e volumes restantes.

sast

  • sast/regra-local: exit_code(s) 3; a regra local achou eval() e o gate de SAST reprovou, sem rede
  • sast/registry-sem-rede: exit_code(s) 1; sem rede, o pacote p/security-audit nao baixa: inconclusivo, gate.inconclusive block reprova
  • sast/nosemgrep-e-semgrepignore: exit_code(s) 0,3; sem politica, o nosemgrep e o .semgrepignore silenciam os dois eval() | sob politica, os dois eval() aparecem apesar de nosemgrep e .semgrepignore
  • sast/origem-sast: exit_code(s) 3,0; a politica conta o achado de origem sast | com gate.sources sem sast, o achado do Semgrep e publicado mas nao reprova o gate
  • sast/semgrep-falha: exit_code(s) 1,0; semgrep falhou: inconclusivo e, com block, o gate reprova | semgrep falhou: com warn o alerta e publicado e o comando sai 0, sem aprovar
  • sast/govet-achado: exit_code(s) 3; go vet achou o printf errado na linha adicionada; o achado antigo de legado.go nao entra (caso acrescentado pelo AUR-492)
  • sast/govet-sem-go: exit_code(s) 1; sem go no PATH: inconclusivo (lint_unavailable) e o gate reprova; nada e instalado (caso acrescentado pelo AUR-492)
caso regra-local: ok
caso registry-sem-rede: ok
caso nosemgrep-e-semgrepignore: ok
caso origem-sast: ok
caso semgrep-falha: ok
CHECK OK

sbom-dependency-track

  • sbom-dependency-track/up: exit_code(s) n/a; servidor, time, chave, quatro projetos e uma politica de violacao prontos
  • sbom-dependency-track/sbom-versao-minima: exit_code(s) 0,1,2,2; SBOM CycloneDX 1.7 aceito contra o minimo 1.6 (mesma major) | SBOM 1.7 recusado contra minimo 2.0 (major diferente) | nenhum SBOM foi escrito | "1.6.0" falha na carga da configuracao, antes do Trivy | format: spdx falha na carga da configuracao, antes do Trivy
  • sbom-dependency-track/upload-e-metricas: exit_code(s) 0,0; o gate enviou o SBOM, esperou o processamento e aprovou
  • sbom-dependency-track/limiares: exit_code(s) 0,3,0; uma violacao de politica acima do limite 0 reprova o gate | com limite 1, a mesma violacao esta dentro do limiar e o gate aprova
  • sbom-dependency-track/violacao-de-politica: exit_code(s) 0,3,0,0; a politica do servidor reprova o componente | sem o componente proibido, o gate aprova
  • sbom-dependency-track/secret-ausente: exit_code(s) 1,0; secret ausente com block: o gate reprova (inconclusivo, nunca aprovado) | com warn, o alerta inconclusivo e publicado e o comando sai 0
  • sbom-dependency-track/timeout: exit_code(s) 0,1; timeout_seconds: 2 vencido com block: inconclusivo e reprovado
  • sbom-dependency-track/projeto-por-microservico: exit_code(s) 0,0,0,0,0,0; servico-a enviado | servico-b enviado ao mesmo projeto | o segundo upload substituiu o primeiro: ms@2.1.3 (servico-a) sumiu do projeto compartilhado (conclusao do script: ms ausente e semver presente) | servico-a no projeto servico-a | servico-b no projeto servico-b | com um projeto por servico, os dois inventarios coexistem (conclusao do script: ms no projeto servico-a, semver no projeto servico-b)
  • sbom-dependency-track/down: exit_code(s) n/a; nenhum container, rede ou volume do tutorial ficou vivo
caso up: ok
caso sbom-versao-minima: ok
caso upload-e-metricas: ok
caso limiares: ok
caso violacao-de-politica: ok
caso secret-ausente: ok
caso timeout: ok
caso projeto-por-microservico: ok
caso down: ok
CHECK OK

assinatura

  • assinatura/chave-efemera: exit_code(s) 0; sign terminou com exit 0 e relatou o bundle | o bundle sbom_app_cyclonedx.json.sigstore.json existe e nao esta vazio (conferido pelo script)
  • assinatura/verificacao-por-terceiro: exit_code(s) 0,0,1; sbom assinado | o terceiro verificou a assinatura com a chave publica | o SBOM adulterado foi rejeitado pelo Cosign (invalid signature)
  • assinatura/keyless-actions: exit_code(s) n/a; conferencia estatica do workflow e das flags; a assinatura keyless em si nao foi demonstrada
  • assinatura/bundle-artefato: exit_code(s) 0; sbom assinado | o bundle que aurumcode sign escreve casa com o glob do upload-artifact (conferido pelo script; o upload em si so ocorre no Actions)
  • assinatura/falha-cosign: exit_code(s) 1; sign falhou (exit 1) e nomeou o SBOM sem assinatura | nenhum bundle foi deixado no repositorio
  • assinatura/falha-sem-bundle: exit_code(s) 1; cosign saiu 0 sem bundle e mesmo assim sign falhou (exit 1)
  • assinatura/falha-imagem-sem-digest: exit_code(s) 1,1; tag sem digest recusada (exit 1) | o Cosign nao foi chamado (cosign-chamado.txt nao existe) | com digest de 64 hex a referencia passou da validacao e o Cosign (falso) foi chamado (cosign-chamado.txt existe) | o Cosign falso saiu 0 sem bundle, e sign falhou: a recusa anterior foi a da validacao, nao a do Cosign
caso chave-efemera: ok
caso verificacao-por-terceiro: ok
caso keyless-actions: ok
caso bundle-artefato: ok
caso falha-cosign: ok
caso falha-sem-bundle: ok
caso falha-imagem-sem-digest: ok
CHECK OK

xbom

  • xbom/build-bom: exit_code(s) 0; Build BOM gerado e validado (CycloneDX 1.6) sem provedor de modelo
  • xbom/cbom: exit_code(s) 0; CBOM gerado e validado
  • xbom/evidencia: exit_code(s) 0,0; CBOM gerado | toda ocorrencia do CBOM cita uma linha que contem o token (conferencia do script)
  • xbom/catalogo: exit_code(s) 0,0; catalogo do repositorio usado | catalogo da politica usado, o do repositorio ignorado
  • xbom/enriquecimento: exit_code(s) 0; BOM enriquecido pelo modelo (fixture) e verificado
  • xbom/tipos-documentados: exit_code(s) 2,2,2,64; tipo aibom e apenas documentado: exit 2 com a ancora da documentacao | tipo saasbom e apenas documentado: exit 2 com a ancora da documentacao | tipo netbom e apenas documentado: exit 2 com a ancora da documentacao | tipo desconhecido: exit 64
  • xbom/falha-catalogo-invalido: exit_code(s) 2; catalogo invalido do repositorio: exit 2, sem voltar ao catalogo embutido | nenhum arquivo foi escrito (conferido pelo script)
caso build-bom: ok
caso cbom: ok
caso evidencia: ok
caso catalogo: ok
caso enriquecimento: ok
caso tipos-documentados: ok
caso falha-catalogo-invalido: ok
CHECK OK

dados-de-analise

  • dados-de-analise/declarado-ou-nao: exit_code(s) 0,0; sem analysis_data declarado o review nao fez nenhuma requisicao e nao imprimiu linha analysis_data | artefato valido: o review aprovou e registrou digest e data na auditoria
  • dados-de-analise/vencido: exit_code(s) 1,0; artefato vencido com block: o review falha (analysis_data_stale) | artefato vencido com warn: exit 0, mas a linha inconclusiva continua no parecer
  • dados-de-analise/cache: exit_code(s) 0,0,1; primeira execucao: artefato remoto verificado e guardado no cache | listagem fora do ar com copia valida em cache: usa o cache e o declara | sem copia em cache e sem listagem: analysis_data_unavailable
  • dados-de-analise/workflow-agendado: exit_code(s) n/a; o workflow tem o agendamento, o teste antes de publicar e a publicacao em duas etapas que o texto descreve (conferencia estatica; a imutabilidade do release depende de 'Immutable releases' no repositorio e NAO foi demonstrada)
  • dados-de-analise/adulterado: exit_code(s) 1,1; arquivo adulterado: analysis_data_digest_mismatch reprova | manifesto adulterado: analysis_data_digest_mismatch reprova
  • dados-de-analise/indisponivel: exit_code(s) 1,1,0; listagem 503 sem cache: analysis_data_unavailable reprova | sem rede e sem cache: analysis_data_unavailable reprova | sem rede com warn: exit 0, mas nunca aprovado silenciosamente
caso declarado-ou-nao: ok
caso vencido: ok
caso cache: ok
caso workflow-agendado: ok
caso adulterado: ok
caso indisponivel: ok
CHECK OK

Aceite

bash tests/acceptance/AUR-563.sh all (offline; o AC-003 usa AURUMCODE_BIN, .bin/aurumcode ou go build no go-shared). Selecionadores: AC-001..AC-004, AC-002-MUT-001. Selecionador desconhecido sai 64. Selado: ./.board/bin/oci-run --profile go-unit-offline-v1 --card AUR-563.