Repository navigation
security: full-audit the 1,355 legacy .secrets.baseline entries left unreasoned by #16299's guard #17034
Description
Activity
Chunking triage — a proposal, not an assignment
- Proposed priority:
priority: low— not applied — and the priority is moot if the recommended move happens first. - triage(v0.9.0): release criticality of the 123 open issues — 26 blocking, 36 small, 18 umbrellas, 41 misfiled, 2 undetermined #17639 criterion met: none of the five. Placed as misfiled: not blocking and not "landing now". triage(v0.9.0): release criticality of the 123 open issues — 26 blocking, 36 small, 18 umbrellas, 41 misfiled, 2 undetermined #17639 recommends moving it out of v0.9.0.
- triage(v0.9.0): release criticality of the 123 open issues — 26 blocking, 36 small, 18 umbrellas, 41 misfiled, 2 undetermined #17639 bucket: 4 — misfiled (not blocking and not "landing now")
- Scope:
security (secondary secrets) - Primary files named by the issue:
repo_tests/secrets_baseline_reasons.py - Umbrella / container: no.
- Pre-filter: clean — no merged commit on
origin/mainsince 2026-08-14 references this issue. - Basis: triage(v0.9.0): release criticality of the 123 open issues — 26 blocking, 36 small, 18 umbrellas, 41 misfiled, 2 undetermined #17639's per-issue row, reused rather than re-derived — "Full audit of the 1,355 legacy secrets-baseline entries. Audit/hygiene data work, not a shipped defect, no open PR. Target backlog or v0.10.0"
Nothing was relabelled, moved or closed by this pass.
- Proposed priority:
Which question #16299's guard answers — and why this issue's remaining AC should not be phrased as "shrink the file"
Read at
origin/mainab05ba3aef; nothing run. Posted because the guard turns out to answer a third question, not either of the two I expected.The guard: "does every entry carry a tracked reason — specific or frozen-legacy?"
repo_tests/secrets_baseline_reasons_guard_test.py::58-63 _offenders(...) -> reasoned = set(SPECIFIC_REASONS) | legacy_keys :65 test_every_baseline_entry_has_a_tracked_reason :77 test_specific_reasons_are_real_not_the_generic_legacy_label :96 test_legacy_keys_match_the_frozen_snapshot_exactly :114 test_negative_control_a_new_unreasoned_entry_is_caughtSo the property enforced is tracked, not specific: an entry passes on a real
SPECIFIC_REASONSreason or on membership in the frozen legacy snapshot. A second test stops a specific reason from degrading into the generic label, and a negative control proves the sweep can fail.It is not the audited question. That belongs to
repo_tests/no_tracked_key_material_test.py("must carry an audited verdict",:18) and it is closed: all 1,400 findings in.secrets.baselinehave a non-nullis_secret, across 301 files.The 1,355 in this issue's title is an exact file
repo_tests/secrets_baseline_legacy_keys.json -> a JSON list of exactly 1355 entriesfrozen by SHA-256 in
test_legacy_keys_match_the_frozen_snapshot_exactly, whose reasoning is worth quoting because it rules out the obvious approach:"A count ceiling alone would let someone swap a legitimate legacy entry for a fabricated one while keeping the total unchanged … Pinning the exact content catches an add, a remove, OR a swap."
So the entries are not "unreasoned". They carry a disclosed generic reason and the guard enforces that they do. The gap this issue closes is generic → specific, which is a different and smaller claim than the title's "left unreasoned".
The correction that matters for the AC
The same file says two things that point opposite ways:
:16 "… and #17034 for the follow-up that will shrink the legacy set" :100-103 "#17034 never needs to touch this file at all … so this hash should never need updating again"The snapshot is immutable by design, and
_offendersunionsSPECIFIC_REASONSwith it — so giving a legacy key a real reason is additive and the snapshot never changes. The progress metric is therefore derived, something like keys whose only reason is the legacy label =legacy_keys − set(SPECIFIC_REASONS), currently 1,355 − 70 overlapping at most, and it falls asSPECIFIC_REASONSgrows.So the remaining AC should be stated against that derived count, never against the file. Phrased as "shrink
secrets_baseline_legacy_keys.json" it invites exactly the edit the hash test exists to reject, and whoever tries it will read:16as permission. Worth reconciling the two sentences in the guard at the same time.Verdict
Not started, premise intact once restated: 1,400 findings, all audited, 70 with a specific reason, 1,355 in the frozen legacy bucket. The work is upgrading reasons, the metric is derived, and the file is not a thing to edit.
Problem
#16299 adds a guard requiring every
.secrets.baselineentry to carry atracked reason (that issue's AC5). Given the baseline's actual scale (1,360
entries at the time, 91% "Secret Keyword" hits — sampled and found to be
overwhelmingly test fixtures, CI-only credentials, and demo/placeholder
values already marked inline, not real guessable production defaults), the
owner ruled AC5's guarded boundary is declared rather than comprehensive:
(
.env.docker/docker/.env.docker'sautobotliteral, the ansiblebackend role's
change-me-in-production/JWT placeholder, and themonitoring role's
adminGrafana password) get real, specific,individually-reviewed reasons.
recorded with one explicit, disclosed reason: legacy, unreviewed, pending
this follow-up. This is a stated boundary (
docs/developer/RATCHET_BASELINES.mdrule 1), not a silent gap — the guard fails if a genuinely NEW,
post-introduction entry tries to reuse that same legacy label.
Scope
representative, exhaustively-categorized sample if truly identical in
shape — e.g. the same
# noqa/# nosec-marked demo literal repeatedacross near-identical test files) and replace the generic legacy
reason with either:
- a specific reason confirming it is a genuine false positive / test
fixture / already-marked demo value, or
- a specific reason confirming it is a real guessable default,
triaged the same way this issue's named 5 were (generate-on-first-run,
or whatever the applicable fix pattern is)
repo_tests/secrets_baseline_reasons.py'sLEGACY_KEYS/reasonsdata to shrink as entries get individually reasoned; the guard from
security: guessable default credentials ship in templates, ansible defaults and the compose file #16299 should be extended (or kept as-is if its shape already supports
this) to fail if
LEGACY_KEYSgrows past its introduction sizeturned out to be a real default needing a fix
Filed per the owner's ruling on #16299, milestone v0.9.0.