AUR-442 — aurumcode review --seguranca: the passage finds what the catalog promises
Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.
Command
aurumcode review --base <ref> [--fail-on <level>] [--modelo <nome>] [--seguranca]
Same command AUR-435 published. This card does not add a flag or change
the output shape; it repairs what --seguranca's deterministic pass
actually matches, so the pass stops claiming coverage it never delivered.
The measured defect (2026-08-13 dogfooding)
Running the real binary against real repositories: --seguranca matched
only 2 of the 8 catalog rules (security/sql-injection,
security/command-injection), both requiring the narrow "..." + var
string-concatenation shape. The other six
(xss, path-traversal, hardcoded-secret, weak-crypto,
insecure-random, missing-auth) were metadata with no pattern, so they
never matched anything. The observable consequence: the project's own demo
fixture, tests/fixtures/repos/git-demo — whose sole purpose is to plant
a plaintext secret — reported No security findings. on every run.
The decision: option (a), scoped to one rule
The card offered two legitimate fixes: give the missing rules a pattern
with a fixture proving each one (a), or declare the covered subset honestly
and stop promising the rest (b). This card takes (a), scoped to exactly
one rule — security/hardcoded-secret, the card's named priority and the
rule git-demo's fixture depends on — rather than (a) for several rules
under the same review pass. The other five stay declared-only: each now
carries an explicit code comment in internal/review/rules/security.yml
recording that decision (not silence), and this file is the honest,
spec-level declaration the card's option (b) requires for them. Two
reasons narrowed scope to one rule instead of the card's own
hardcoded-secret-plus-weak-crypto example:
- Precision cost. A matcher shipped without a validated, tested
false-positive boundary is exactly the failure mode this card exists to
close (a rule that fires on the wrong things is not meaningfully better
than a rule that never fires).
hardcoded-secretalone required two regex branches, an explicit "letter mixed with a digit or hyphen" requirement to reject plain function calls (token := getToken()) and plain numeric constants (TOKEN_MAX_AGE_SECONDS = 31536000), and a dedicated benign-line test suite (seeinternal/review/rules/security.yml's rule comment andtests/unit/AUR-442.go'sScanRejectsBenignAssignments). A second matcher (weak-crypto, or any other) needs the same rigor, which this card's scope did not budget for without rushing it. xss,path-traversal, andmissing-authare not line-shape questions at all — they turn on data flow (does untrusted input reach an unescaped sink / an unvalidated path / a handler that should require auth and does not), which a single added line cannot answer regardless of how carefully the regex is written.
Every undelivered rule remains citable by a model finding (AUR-434's
rule-citation gate resolves any catalog id, pattern or not) — only the
deterministic --seguranca pass is scoped. Nothing in --help, this
document, or the command's printed output claims coverage beyond what is
proven below.
What security/hardcoded-secret now matches
Two shapes, both requiring a credential-named identifier (api key,
secret, password, passwd, token, credential, access key,
case-insensitive) assigned a value that mixes a letter with a digit or a
hyphen:
<keyword> (:=|:|=) "<value>"— a quoted assignment, the shape common in application source (api_key := "AURUM-FAKE-KEY-9000-2222").UPPER_SNAKE_KEYWORD = <value>unquoted — the env/config-file shapetests/fixtures/repos/git-demo/content/03/config/demo-tokens.txtuses (DEMO_API_TOKEN=AURUM-FAKE-TOKEN-0000-0001). The keyword may be the whole identifier with no prefix (TOKEN=...,SECRET=...,API_KEY=...,PASSWORD=...) or prefixed (DEMO_API_TOKEN=...); a review fix (2026-08-13) closed a gap where a mandatory leading uppercase letter silently consumed the keyword's own first character whenever the identifier had no prefix, so the four bare forms never matched despite this shape being documented without that exclusion (tests/unit/AUR-442.go'sScanFindsTheBareUnquotedEnvShape).
The letter-plus-(digit-or-hyphen) requirement is deliberate: it is what
lets the matcher find password = "hunter2xyz123" and
SERVICE_ACCESS_KEY=AURUM-FAKE-ACCESS-9000-3333 while passing over
token := getAuthToken(), API_TOKEN = get_token_from_vault(), and
TOKEN_MAX_AGE_SECONDS = 31536000 — a bare function call or a bare numeric
constant, neither a hardcoded secret. Findings cite the rule and, new
under this card, the project security standard SCR-003 (Cryptographic
Failures / hardcoded credential, standards/security-review/rules.md).
Known limitation, same category as the SQL-injection pattern's own
documented breadth (docs/specs/AUR-435.md, noted by the AUR-435
reviewer): a line-level regexp cannot see intent. A variable named
secretary assigned an unrelated 16+ character token, or a comment line
that happens to read secret: <8+ char word>, can still match. This is an
accepted, bounded trade-off — the alternative (no matcher at all) is the
defect this card fixes — not a promise of perfect precision.
Output shape
Unchanged from AUR-435:
<notices and quality findings, exactly as without the flag>
Security findings (standards/security-review):
config/demo-tokens.txt:4: [error] Hardcoded credentials or API keys detected [standards/security-review SCR-003] (rule security/hardcoded-secret: Hardcoded Secrets)
config/demo-tokens.txt:5: [error] Hardcoded credentials or API keys detected [standards/security-review SCR-003] (rule security/hardcoded-secret: Hardcoded Secrets)
config/demo-tokens.txt:6: [error] Hardcoded credentials or API keys detected [standards/security-review SCR-003] (rule security/hardcoded-secret: Hardcoded Secrets)
The message is trusted catalog text (rule.Description), never the
matched diff content: the secret VALUE never reaches this line, only the
file, the line number, and the rule/standard citation. This is structural
(internal/review/securitypass.go builds every message from the catalog,
not from the matched body), proven in tests/unit/AUR-442.go's
ScanNeverEchoesTheMatchedValue and exercised end to end in
tests/integration/AUR-442.go and tests/e2e/AUR-442.sh.
Exit codes
Unchanged from AUR-435 (docs/specs/AUR-435.md):
| Code | Meaning |
|---|---|
0 |
Review ran; gate (if any) open. |
1 |
The review itself failed (no provider, unreadable repo, broken rules catalog). |
2 |
Usage error (missing --base, unknown flag or level). |
3 |
--fail-on gate closed. A matched hardcoded-secret finding is severity error and closes --fail-on high on its own. |
Offline, secret-free examples
The card's central proof: git-demo
tests/fixtures/repos/git-demo plants three synthetic secrets
specifically so a security pass has something to find. Before this card,
--seguranca reported No security findings. here; it now reports all
three:
cd tests/fixtures/repos/git-demo/repo.git
AURUMCODE_LLM_FIXTURE=../../../review/known-problem-response.json \
aurumcode review --base HEAD~1 --seguranca
A dedicated fixture proving both matched shapes
tests/fixtures/review/vuln/hardcoded-secret (new under this card,
rebuildable deterministically with
tests/fixtures/repos/git-demo/build-fixture.sh; sibling to and never
touching AUR-435's own tests/fixtures/review/vuln/repo.git, whose
HEAD~1..HEAD diff AUR-435's frozen tests pin byte for byte) plants one
secret of each shape beside one deliberately benign line each:
cd tests/fixtures/review/vuln/hardcoded-secret/repo.git
AURUMCODE_LLM_FIXTURE=../../../known-problem-response.json \
aurumcode review --base HEAD~1 --seguranca
prints, after the unchanged quality block:
Security findings (standards/security-review):
config/secrets.env:4: [error] Hardcoded credentials or API keys detected [standards/security-review SCR-003] (rule security/hardcoded-secret: Hardcoded Secrets)
src/config.py:4: [error] Hardcoded credentials or API keys detected [standards/security-review SCR-003] (rule security/hardcoded-secret: Hardcoded Secrets)
— and not the benign SERVICE_NAME=aurum-fixture or timeout_seconds = 30
lines beside them.
Failure diagnosis
flag provided but not defined: -seguranca— the binary predates AUR-435; rebuild from source.aurumcode review: review rules unavailable: ...— the embedded rules catalog is broken; fixinternal/review/rules/and rebuild.- The section says
No security findings.but you expected ahardcoded-secretmatch — check the letter-plus-(digit-or-hyphen) requirement above; a bare function call or a bare numeric constant next to a credential-named identifier is correctly out of scope. - The section is silent about XSS, path traversal, weak crypto, insecure
randomness, or missing auth — those five rules are declared metadata
only (see "The decision" above); they are never out of scope by
accident, and a model finding (without
--seguranca, or alongside it) may still cite them.
Security
- Structural: the finding message is trusted catalog text, never the matched diff body (see "Output shape" above); the secret value cannot reach stdout through this path.
- The
AURUM_SECRET_CANARYvalue never reaches stdout, stderr, prompt, cache, or evidence;tests/acceptance/AUR-442.shasserts this on every run.
Compatibility
review --basewithout--segurancais byte-identical to the published AUR-430 contract;--fail-on,--modelo,--limite,--pr,--check, anddocsare unaffected (tests/acceptance/AUR-433.sh,tests/acceptance/AUR-441.shpass unchanged against this card's tree).security/sql-injectionandsecurity/command-injection(AUR-435) keep matching exactly what they matched before (tests/unit/AUR-442.go'sOtherSecurityRulesUnaffected).tests/acceptance/AUR-435.shandtests/integration/AUR-435.goare updated by this card, not left as follow-up debt. Both originally hardcoded thatgit-demo's--segurancarun printsNo security findings.— true only because no rule had a matcher for the plaintext secret that fixture exists to plant. AUR-442's write-set was extended (.board/cards/ready/AUR-442.md'spaths, same precedent as AUR-424 in this reconstruction: the card that changes behavior updates the tests that pinned the old behavior) to include both files.nominal_case(AUR-435.sh) andIntegrationAUR435(AUR-435.go) now assert the correct behavior instead — thesecurity/hardcoded-secretrule citation, theSCR-003standard citation, and each of the three planted lines (config/demo-tokens.txt:4-6) by name — and explicitly fail ifNo security findings.reappears, so the rebase cannot regress to a weaker check. AUR-435's ownMUT-001(mutation_case, which runs against the unrelatedtests/fixtures/review/vuln/repo.git, notgit-demo) is untouched and still rejects its mutant.
Validation
tests/acceptance/AUR-442.sh AC-001 (sealed:
./.board/bin/oci-run --profile bootstrap-readonly-v1 --card AUR-442),
with selectors TestAUR442 (tests/unit/AUR-442.go), IntegrationAUR442
(tests/integration/AUR-442.go), E2EAUR442 (tests/e2e/AUR-442.sh) and
AC-001-MUT-001 (deleting security/hardcoded-secret's pattern line,
which must make the expected git-demo finding vanish).
Selector naming note (same technique tests/unit/AUR-445.go and
tests/integration/AUR-445.go document): the card text's TDD proof
section names TestAUR435 / IntegrationAUR435, copy-paste artifacts
from the AUR-435 card this one was drafted against. Both symbols already
exist in their packages (tests/unit/AUR-435.go,
tests/integration/AUR-435.go) and would collide, so this card's proofs
are TestAUR442 / IntegrationAUR442 instead.