Pular para conteúdo

AUR-623 — Plugin agendado em repositório privado sem Code Security: achados viram issues

Problema

Decisão do dono (2026-10-14): em repositório privado sem GitHub Code Security não há aba Security para alertas de código; os achados do plugin agendado viram issues do próprio repositório, visíveis só a colaboradores. Em repositório público, nunca: só a aba Security. Até aqui (AUR-622) o job decidia o destino e falhava antes de rodar o plugin quando ele seria issues.

Desenho

arquivo responsabilidade
internal/plugin/issues_findings.go Lê o SARIF do ingest. Ausente, malformado, execução sem sucesso ou categoria de outro plugin: inconclusivo. Redige de novo cada texto e deduplica por fingerprint.
internal/plugin/issues_body.go Rótulo aurumcode-plugin:<nome>, marcador <!-- aurumcode-plugin:<nome>:<fingerprint> --> (fingerprint fora de [A-Za-z0-9._-]{1,128} vira sha256), lido só da primeira linha do corpo; título só com campos estruturados; corpo pt-BR com a descrição redigida num bloco de código (crase vira ˋ). Título acima de 256 caracteres encurta o caminho pela esquerda; corpo acima de 65536 corta a descrição com aviso, sempre do mesmo jeito: limite externo nunca derruba a sincronização.
internal/plugin/issues_github.go Cliente HTTP mínimo (GITHUB_TOKEN, AURUMCODE_GITHUB_API_URL validado por config.GitHubAPIURL): visibilidade, rótulo, listagem paginada até página vazia (sem teto), criar, atualizar, fechar, comentar. Erro só com o código HTTP.
internal/plugin/issues_ratelimit.go 429 ou 403 do limitador (Retry-After, X-RateLimit-Remaining: 0): espera o pedido e reenvia (a escrita recusada não duplica), como o cliente de PR.
internal/plugin/issues_sync.go Plano puro (abrir, atualizar, reabrir, fechar) e aplicação; issue criada sem o rótulo reprova (seria duplicada a cada varredura). Fechar deixa um comentário com <!-- aurumcode-plugin:<nome>:fechado -->.
internal/plugin/issues_history.go Quem fechou: o ator do último evento closed (eventos e comentários paginados, sem teto). É o plugin se for o autor da issue ou o autor de um comentário-marcador posterior à última reabertura; outro ator = dispensada por pessoa (fica fechada, sem escrita). Eventos ilegíveis ou sem closed: reabre (falha fechada: achado presente nunca some sem decisão humana). Marcador forjado só pode levar a reabrir, nunca a esconder.
internal/plugin/issues_run.go Ordem: SARIF local (inconclusivo: nenhuma chamada) → visibilidade (private/internal e private: true, senão recusa antes de escrever) → rótulo → listagem → plano. Saída só com contagens.
cmd/aurumcode/cmd_plugin.go Verbo issues (só flags).
.github/workflows/review.yml "Choose destination" grava destino; upload-sarif e a contagem só em security; "Sync issues" só em issues após ingest conclusivo; issues: write documentado para o chamador.
demo/tutoriais/plugin-agendado/ Casos issues (três varreduras contra github-falso-issues.py) e issues-publico (recusa e inconclusivo sem chamada).

Aceite

tests/acceptance/AUR-623.sh: AC-001..AC-005; MUT-001 (a checagem de visibilidade aceitar qualquer repositório derruba AC-003) e MUT-002 (o SARIF inconclusivo virar zero conclusivo, fechando issues, derruba AC-003).

TestAUR622WorkflowPluginsJob passou a exigir o if: do upload com o destino security (antes, exatamente success()).

Pendências declaradas

  • Sem execução contra o GitHub real neste card: o comportamento da API (rótulo criado antes da issue, state=all com rótulo) segue a documentação pública e foi provado contra o GitHub falso.
  • Se a identidade do plugin mudar (outro token) e a nova fechar issues abertas pela antiga, o comentário-marcador da nova identidade, escrito logo antes do fechamento, a reconhece; uma pessoa que forja o marcador e fecha ela mesma faz a issue ser reaberta (ruído, nunca achado escondido).
  • Repositório com Issues desativadas: a sincronização falha (código HTTP) a cada execução e nada é publicado em outro canal.
  • Uma falha da API no meio da sincronização para na primeira escrita que falhou; a varredura seguinte converge do estado em que o repositório ficou.