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).