AUR-582 — regra embutida de segredo lê a base pública do gitleaks como dado pinado
Medido antes
internal/analysis/analysis.gofixava em Go, porregexp.MustCompile, uma única regex de palavra-chave paraanalysis/hardcoded-secret(password|token|secret... = "<8+ chars>"): sem formatos de fornecedor, sem entropia, sem allowlist. Uma chave AWS ou um token GitHub atribuídos a um identificador neutro (awsID := "AKIA...") não produziam achado.- O lock
.board/bootstrap/locks/scanners.ymljá pina a base:secrets_rulebase_id: gitleaks-default-config-v8.30.1esecrets_rulebase_sha256: sha256:e163e53b…caf(97731 bytes,https://raw.githubusercontent.com/gitleaks/gitleaks/v8.30.1/config/gitleaks.toml). O download conferiu exatamente esse digest.
O que mudou (v2)
internal/analysis/rules/secrets.json: derivação JSON da configuração padrão do gitleaks v8.30.1 (id, descrição, regex, path, secretGroup, entropy, keywords, allowlists por regra e allowlist global), comsource.sha256=secrets_rulebase_sha256do lock. O TOML de origem NÃO é commitado: o repositório é público e as allowlists da base trazem chaves de exemplo com forma de credencial.- Literais de allowlist com forma de credencial — sem metacaractere de regex
e casados pela regex da própria regra (hoje: os 16 exemplos
AIza…degcp-api-key) — vão para o JSON só como sha256 (literal_sha256). Os demais regexes de allowlist e as stopwords ficam em claro. Diferença de semântica registrada: na fonte, o regex de allowlist casava qualquer alvo que CONTIVESSE o literal (substring); aqui o alvo (regexTarget, por padrão o segredo capturado) é suprimido só por IGUALDADE exata de hash. internal/analysis/rules/secrets.json.sha256: digest dos bytes do JSON, checado pelo loader (pânico no init se divergir).scripts/analysis/update-secret-rules.sh(host com rede): lê versão e digest do lock, baixa o TOML na tag, recusa digest divergente, deriva o JSON compython3/tomllib(stdlib — nenhum parser TOML nogo.mod), converte os literais com forma de credencial em hash (só se a regex da regra os casa), confere que cada regra derivada mantém id e regex da fonte, grava JSON e sidecar.AURUMCODE_GITLEAKS_TOML_OUT=<arquivo>guarda uma cópia do TOML verificado fora do repositório. Reexecutar o script deixainternal/analysis/rules/sem diff.internal/analysis/rules/secrets-local.json: a regra de palavra-chave anterior, agora como dado (aurumcode-keyword-assignment, contextocode-outside-string-literals). Justificativa: a base pública não cobre os casos existentespassword = "xxxxxxxx",token = "zzzzzzzz"etc. — o valor bate na allowlist global (^(?i:a+|…|x+|…|z+)$) e na entropia mínima. Manter a regra local preserva o comportamento publicado (mensagem fixaHardcoded secret or credential assigned inline, usada por testes decmd/,tests/unit/AUR-505.go, o tutorialgatee docs), e a supressão de exemplos dentro de string literal continua só nela.internal/analysis/secretcatalog.go:go:embeddo JSON, do sidecar e da regra local; loader recusa schema desconhecido, digest de artefato divergente esource.sha256malformado. Regras sem regex (sópath) e regex que o RE2 recuse viramskipped, nunca somem.internal/analysis/secretscan.go: semântica do gitleaks — pré-filtro por keywords, regex, segredo =secretGroupou primeiro grupo não vazio ou o match, entropia de Shannon > mínimo, allowlists por regra e global (regexes e hashes comregexTargetsecret/match/line, paths, stopwords, condição OR/AND). Regras locais primeiro, depois a base; no máximo um achadoanalysis/hardcoded-secretpor linha; só linhas adicionadas, após remover comentários.- Mensagem: regra local mantém a mensagem fixa; regra da base usa
Hardcoded secret matched rule <id> (<descrição>); o valor capturado nunca entra na mensagem. O idanalysis/hardcoded-secrete as demais regras (injeção de comando/SQL, permissões) não mudam.
Cadeia de digests (sem campo novo no lock)
lock (secrets_rulebase_sha256) → TOML (o script recusa outro digest) →
JSON (source.sha256, comparado ao lock pelo teste com
AURUMCODE_SCANNERS_LOCK) → bytes do JSON (secrets.json.sha256, checado no
loader). Um campo secrets_rulebase_artifact_sha256 mudaria a identidade em
locks.yml, o bloco citado em docs/tutorials/operacao.md e entradas de
tutoriais e testes fora dos paths, sem ganho de prova: o sidecar já amarra
cada byte do artefato.
Fidelidade à fonte (teste condicionado)
Como o TOML não está no repositório, TestDerivedSecretCatalogFaithfulToSource
só roda com AURUMCODE_GITLEAKS_TOML=<cópia verificada>; sem ela, pula com o
motivo explícito. Com ela, confere sha256 da fonte, número e ordem das
regras, id, regex e entropia, e que cada literal_sha256 é o hash de um
literal da allowlist da regra de origem que a regex da própria regra casa.
O script faz a mesma conferência de id/regex em cada atualização. Rodado
localmente com a cópia baixada: --- PASS: TestDerivedSecretCatalogFaithfulToSource.
Cobertura da base
222 regras; 221 compilam no regexp do Go. A única pulada é pkcs12-file
(regra só de path), fixada em TestSkippedSecretRulesAreDeclared. A
heurística do gitleaks de exigir dígito em segredos de regras generic* não
faz parte da configuração e não foi reproduzida.
Prova
bash tests/acceptance/AUR-582.sh all (container go-shared), últimas linhas:
secretcatalog_test.go:120: lock sha256:f163e5…, catalog records sha256:e163e5…
panic: secret catalog: artifact digest sha256:2f8f84… does not match the recorded sha256:3ed493…
ok github.com/Mpaape/AurumCode/internal/analysis 0.018s
secretcatalog_test.go:279: planted.go:5:42: secret-shaped regex compiled in Go
AC-005: no credential-shaped literal
--- FAIL: TestSecretAllowlistAndEntropy/low-entropy_aws-shaped_key_is_below_the_minimum (0.00s)
secretcatalog_test.go:98: a derived catalog one byte off its recorded digest was accepted
AUR-582/all/pass
- AC-001 —
TestSecretVendorFormatsReportRuleIDWithoutValue:awsID := "AKIA…"egh := "ghp_…"(vetores por concatenação) produzem dois achadosanalysis/hardcoded-secretcomaws-access-tokenegithub-patna mensagem e sem o valor. - AC-002 —
TestSecretAllowlistAndEntropy:password: <alta entropia>emconfig.ymlé achado da base (generic-api-key); o mesmo valor com sufixo-example(stopword) não; chave AWS terminada emEXAMPLE(allowlist regex) não; baixa entropia não;go.sum(allowlist global de path) não.TestHashedAllowlistSuppressesExampleKey: a chave de exemplo GCP allowlistada só por hash não gera achado, outra chave do mesmo formato gera, e a mesma regra sem allowlists flagra o exemplo (o hash é a causa). Os casos antigos (TestAnalyzeTable,TestAUR4*,TestNewRunnerZeroConfig) seguem verdes sem edição. - AC-003 —
source.sha256do artefato =secrets_rulebase_sha256do lock (teste executado, não pulado); um lock com outro digest reprova (catalog records); um byte trocado no JSON derruba o init (artifact digest … does not match). - AC-004 — grep sem
regexp.(Must)Compilede padrão de segredo em Go de produção eTestNoSecretRegexCompiledInGo(go/ast) verde; plantar umregexp.MustCompiledepassworddeixa o teste vermelho. - AC-005 —
git ls-files -z | xargs -0 grep -lE '<AIza|ghp_|xox|AKIA|sk_live_|glpat-|PEM>'vazio (sem git, no selado, o mesmo grep sobre a árvore materializada). - MUT-001 — entropia ignorada reprova AC-002.
- MUT-002 — loader que aceita digest divergente reprova AC-003
(
was accepted).
Regressão (container go-shared):
go vet ./... && go test -p 1 ./...: todos os pacotesok.tests/acceptance/AUR-574.sh all→AUR-574/all/pass.- Tutorial
gate(únicoexpected/que cita o achado), com imagem do worktree:run.sh alle--check→CHECK OK(medido na v1; a v2 não muda o comportamento sobre esse repositório). tests/acceptance/AUR-435.shnão roda em árvore limpa: a linha 122 copia pacotes enumerados (internal/documentation/extractors,.../incremental) que não são rastreados pelo git — falha de infraestrutura anterior a este card.tests/acceptance/AUR-541.sh all→AUR-541/all/pass, rc 0, 302 s, executando AC-001, AC-002 e AC-001-MUT-001 em sequência (oallfalha no primeiro seletor vermelho); o rastrobash -xcita 52 scripts detests/e2e/(AUR-461 sete vezes, pela mutação). A medida anterior de "~1 min" foi erro de leitura do relógio: a primeira execução também levou cerca de 5 min.