Pular para conteúdo

AUR-595: a autorrevisão conclui em PR real

Medido antes (base 7b9cb359, PR #89)

A autorrevisão da PR #89 (configuração do próprio repositório, AUR-591) terminou inconclusiva por três motivos. Auditoria do job (aurumcode-audit-89): deliberation.rounds=1, tokens_in=65918, tokens_out=91, desfecho deliberation_limit:max_cost_tokens; gate fail com SECRETS (gitleaks, ...) inconclusivo (secrets_execution_error) e dois security/command-injection em demo/tutoriais/sast/out/nosemgrep-e-semgrepignore.log:36 e demo/tutoriais/sast/out/regra-local.log:22.

  1. Teto de deliberação contava o prompt base. Session.Run (internal/deliberation/session.go) somava TokensIn + TokensOut de todas as rodadas e comparava com max_cost_tokens (60000). A primeira rodada já carrega o prompt base inteiro (65918 tokens numa PR média): o teto estourava antes de o modelo pedir qualquer ferramenta.
  2. Gitleaks no merge commit. Diagnóstico reproduzindo o job: clone com o mesmo fetch do actions/checkout (fetch-depth: 0: +refs/heads/*:refs/remotes/origin/* e tags), checkout destacado da cabeça da PR, montado só leitura num container root com safe.directory via GIT_CONFIG_*, e os mesmos comandos de verifyRange/scanRange:
== GITHUB_SHA=a1ee8f28... (refs/pull/89/merge)
cat-file 098f7342... rc=0
fatal: Not a valid object name a1ee8f28...^{commit}
cat-file a1ee8f28... rc=128          -> ErrBadRange -> secrets_execution_error
== GITHUB_SHA=110ffb72... (cabeça da PR)
cat-file 110ffb72... rc=0
gitleaks rc=0  INF 12 commits scanned.  WRN leaks found: 2

O env: do passo define GITHUB_SHA com a cabeça, mas num evento pull_request o GitHub reserva a variável ao merge commit sintético (o mesmo fato de AUR-504; o workflow_sha da auditoria é o merge a1ee8f28). O checkout da cabeça não traz refs/pull/N/merge, então a ponta do intervalo não existia no clone. O motivo publicado era só o token, sem dizer qual ponta faltava. 3. Logs gravados de tutorial na revisão. demo/tutoriais/*/out/*.log repetem de propósito exemplos com eval(); o passe de segurança os acusou como código adicionado.

O que mudou

  • internal/deliberation/transcript.go, session.go: o transcript registra base_tokens (entrada da primeira rodada, o prompt base como o provedor o mede) e cost_tokens (saída de cada rodada + o que a entrada de cada rodada seguinte traz além do prompt base). max_cost_tokens limita cost_tokens; o prompt base segue sob o orçamento do prompt. O detalhe do limite diz os dois números.
  • cmd/aurumcode/pr_scan_range.go, review_pr_analysis.go: no --pr o intervalo dos scanners é AURUMCODE_BASE_SHA..HEAD do checkout verificado (o HEAD que resolveCheckout já provou igual à cabeça da API); nunca GITHUB_SHA. Sem checkout verificado a cabeça fica vazia e os scanners continuam bloqueados (*_unverified_checkout).
  • internal/scanner/detail.go, executor.go: Outcome.Err é o erro cru da engine, nunca publicado como está; Summarize(err, redact) redige o texto cru inteiro (com as quebras de linha) e só depois colapsa espaços e corta em 240 bytes na fronteira de rune. Sem redator, não há detalhe. Ordem medida pela revisão: resumir antes de redigir vazava o prefixo de um ghp_ cortado no limite e um Authorization: Bearer em linha própria (o padrão é ancorado no começo da linha); o gitleaks também não corta mais a linha citada de stderr e a põe em linha própria. internal/gate/scanner.go: Scan.Detail; a linha do gate fica inconclusivo (<token>) [detalhe: ...] (o token continua inteiro entre parênteses). cmd/aurumcode/scanner_pass.go: o detalhe passa pelo filtro de redação da revisão antes de qualquer saída e entra na limitação publicada (notice.scanner_detail, internal/i18n/catalog.yml).
  • internal/scanner/gitleaks/invocation.go: os erros dizem qual ponta (base commit <id> not found in the checkout), clone raso, e a última linha de stderr do git/gitleaks que falhou (ou a primeira linha ERR/FTL de um log com erro e exit 0).
  • .aurumcode/config.yml: ignore ganha demo/tutoriais/*/out/** e demo/tutoriais/*/expected/**. docs/configuration.md: teto relativo, intervalo do --pr, detalhe do motivo, recomendação para artefatos gerados. docs/getting-started.md: as três notas.

Provas

bash tests/acceptance/AUR-595.sh all (go-shared, GOCACHE do chamador; o mesmo no selado oci-run --profile go-unit-offline-v1 --card AUR-595):

AUR-595/AC-001/pass
AUR-595/AC-002/pass
AUR-595/AC-003/pass
AUR-595/AC-004/pass
    cost_test.go:18: a base prompt above the ceiling stopped a deliberation that asked for nothing: deliberation_limit: max_cost_tokens (66009 tokens de deliberacao alem do prompt base de 65918, teto 60000)
--- FAIL: TestAUR595LargeBasePromptWithoutToolsIsNotALimit (0.00s)
    aur595_test.go:252: exit=1 deliberation=&{Outcome:deliberation_limit:max_cost_tokens BaseTokens:4347 CostTokens:4396}, want an answered deliberation; ...
--- FAIL: TestAUR595BasePromptAboveTheCeilingConcludes (0.09s)
AUR-595/MUT-001/rejected
    aur595_test.go:185: gitleaks never scanned (exit=1)
--- FAIL: TestAUR595GitleaksScansThePullRequestHeadNotTheMergeCommit (0.06s)
AUR-595/MUT-002/rejected
AUR-595/all/pass
  • AC-001: TestAUR595LargeBasePromptWithoutToolsIsNotALimit (base 65918, teto 60000, sem ferramenta: responde, cost_tokens=91), TestAUR595ToolRoundsBeyondTheBaseStillExceedTheCeiling (rodadas de ferramenta somam 13314 além da base, teto 8000: max_cost_tokens na rodada 3), TestAUR580MaxCostTokensIsALimitError (reescrito para estourar por rodada de ferramenta), TestAUR595BasePromptAboveTheCeilingConcludes (ponta a ponta: base 4347 > teto 300, conclui, auditoria com base_tokens/cost_tokens) e TestAUR580CostExceededIsInconclusive.
  • AC-002: TestAUR595GitleaksScansThePullRequestHeadNotTheMergeCommit (checkout com objetos git soltos, sem binário git, que o perfil selado não tem; o executor de teste responde cat-file/rev-parse pelo object store do próprio checkout, então verifyRange decide sobre o repositório real; GITHUB_SHA = merge ausente: o gitleaks recebe base..head e o gate conclui; o mesmo caminho com o git e o gitleaks de verdade está na reprodução da PR #89 abaixo); TestAUR595AbsentBaseIsInconclusiveWithItsDetail (base ausente segue secrets_execution_error).
  • AC-003: TestAUR595AbsentBaseIsInconclusiveWithItsDetail (o detalhe base commit <id> not found in the checkout na linha do gate, no gate.reason da auditoria e no parecer publicado) e TestAUR595EngineFailureDetailIsRedacted (uma credencial impressa pela engine sai [REDACTED] no stderr, na auditoria e no parecer).
  • MUT-003: juntar e cortar antes de redigir -> AC-003 vermelho (TestAUR595SummaryRedactsATokenAtTheCut mostra ghp_Q7w..., TestAUR595SummaryRedactsAHeaderOnItsOwnLine e TestAUR595EngineHeaderLineIsRedacted mostram o valor do header).
  • MUT-001: somar a entrada da primeira rodada em CostTokens -> AC-001 vermelho (unitário e ponta a ponta). MUT-002: r.Head = p.env().githubSHA -> AC-002 vermelho (o gitleaks nunca roda; o intervalo aponta para o merge ausente).

Reprodução real com a PR #89 (cabeça d25edc75, merge 4f14aec1 ausente do clone, base 098f7342), aurumcode review --pr 89 --publicar --check contra um proxy local só leitura da API (escritas descartadas localmente):

imagem de main (7b9cb359):  SECRETS (gitleaks, origem gitleaks, secao repo) inconclusivo (secrets_execution_error)
imagem desta branch:        gitleaks:generic-api-key ... in commit 3b77f2c4792c (gitleaks v8.30.1) (severidade error, ...)
                            gitleaks:aws-access-token ... in commit 2dd5caf978f4 (gitleaks v8.30.1) (severidade error, ...)

A varredura conclui; os dois achados são canários de teste da própria PR #89 (cmd/aurumcode/mcp_server_test.go:18, internal/mcpserver/server_test.go:197), que passam a contar no gate dela.

AC-004: como verificar na PR deste card

O --pr lê do branch base as configurações que afetam o gate (regras, ignore): a PR não enfraquece a própria revisão. Logo o ignore novo de .aurumcode/config.yml só vale para as PRs abertas depois de este card estar no main; o código (teto relativo, intervalo, detalhe) vale já, porque o workflow roda a ferramenta do merge da PR (job.workflow_sha).

  1. Abrir a PR de card/AUR-595 para main.
  2. O check review / Review pull request precisa terminar verde, com o aurumcode/policy-gate em success. Na auditoria (aurumcode-audit-<N>): deliberation.outcome diferente de deliberation_limit:*, deliberation.base_tokens e cost_tokens presentes, nenhum secrets_execution_error em gate.reason.
  3. Se o passe de segurança acusar demo/tutoriais/*/out/*.log ou expected/*.txt regravados por este card (o ignore ainda é o do main), não é regra a desligar: o hunk de .aurumcode/config.yml entra no main primeiro e a PR é reavaliada por um novo evento (git merge main + push), que relê a configuração da nova base.

Fora do escopo

Desligar regra, aumentar tetos, tratar falha de scanner como sucesso. Os achados do gitleaks na PR #89 são dela.