Pular para conteúdo

AUR-531: review explica se o código usa a parte vulnerável da dependência

Medido antes (leitura, base 67977bea, com origin/stream/A mesclado)

  • O AUR-495 (stream A) entrega internal/dependencies (não internal/analysis, como o card supunha): Report.Findings com Change (manifesto, ecossistema, pacote, versões) e Vulnerability (id, aliases, resumo, severidade, link), status introduced|preexisting|fixed; runDependencyCheck roda em joinEvidence dos dois caminhos e o gate lê s.depReport. A Vulnerability não traz os símbolos afetados do OSV; o modelo lê o resumo do advisory.
  • As ferramentas de leitura do AUR-526 (read_file, search_text, find_symbol) e tools.Revision existem neste stream.
  • Não há engine de alcance mantida por ecossistema registrada (nenhum govulncheck no registro de scanners nem no Dockerfile).

Decisão

  • internal/review/reach: Explainer.Explain roda uma deliberação limitada (limites de deliberation) com as ferramentas do repositório sobre a revisão revisada, com o prompt em prompt.md (dado). A resposta é lida só como {uses, locations, explanation}; qualquer outro campo (severity, verdict) nunca é lido. Cada local citado precisa existir na revisão (Revision.Read + linha no intervalo); local inventado vai para Discarded; yes sem local aterrado vira unknown. Falha ou formato errado é Reason, nunca "sem uso".
  • cmd/aurumcode/dependency_reach.go: com deliberation.enabled e deliberation.dependency_reachability: true, uma explicação por advisory introduzido ou pré-existente (até 5), como linha do parecer (Limitations) e no stderr, sempre com "o achado, a severidade e o veredito não mudam". s.depReport nunca é tocado: o gate julga o mesmo relatório com ou sem explicação. Sem a chave, nada muda.
  • A chave fica em deliberation (internal/config/deliberation.go, fora dos paths do card) para não editar internal/config/dependencies.go do stream A.

Fora do escopo desta entrega (registrado)

  • Elevar a severidade quando o uso é exposto a entrada externa: o Outcome permite, mas exigiria mexer na política de dependências do gate (stream A); hoje a explicação só informa.
  • govulncheck como evidência: exige registrar a engine e o binário na imagem; fica para um card próprio de engine.

Como cada AC/MUT é provado (tests/acceptance/AUR-531.sh)

  • AC-001: TestAUR531UseIsCitedWithFileAndLine (fixture Python que chama yaml.load; a busca chega ao modelo e a linha cita app/config.py:4).
  • AC-002: TestAUR531NoUseSaysSoAndFindingStands (sem uso: "o modelo não achou uso"; local inventado descartado) e TestAUR531ExplanationNeverChangesTheReport (relatório idêntico byte a byte).
  • AC-003: TestAUR531DowngradeAttemptIsIgnored (severity: low, verdict: approve não chegam à explicação; resposta malformada não vira "sem uso") e o teste de sessão acima.
  • MUT-001: inserir if x.Uses == reach.UsesNo { s.depReport.Findings = nil } antes da linha do parecer; TestAUR531ExplanationNeverChangesTheReport fica vermelho.

Documentação stale corrigida

  • docs/configuration.md: Deliberação ganha dependency_reachability; "Dependências do PR" aponta para ela (antes não havia explicação de alcance).

Correção da revisão estática

  • As explicações saíam em Limitations, que filterLimitationsAgainstDiff pode descartar no --pr. Agora ficam em reviewState.reachLines e são uma seção própria do parecer (appendReachSection, nos dois caminhos), fora das limitações (TestAUR531ReachHasItsOwnSection, TestAUR531ExplanationNeverChangesTheReport).
  • Os textos ("Alcance de...", motivos) vêm do catálogo internal/i18n (pt-BR com acentos e en) e seguem o idioma da revisão (TestAUR531LineFollowsTheReviewLanguage).