Skip to content

security: full-audit the 1,355 legacy .secrets.baseline entries left unreasoned by #16299's guard #17034

Description

@mrveiss

Problem

#16299 adds a guard requiring every .secrets.baseline entry to carry a
tracked 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:

  • The 5 entries matching this issue's own named guessable defaults
    (.env.docker/docker/.env.docker's autobot literal, the ansible
    backend role's change-me-in-production/JWT placeholder, and the
    monitoring role's admin Grafana password) get real, specific,
    individually-reviewed reasons.
  • Every other entry present in the baseline at guard-introduction time is
    recorded with one explicit, disclosed reason: legacy, unreviewed, pending
    this follow-up. This is a stated boundary (docs/developer/RATCHET_BASELINES.md
    rule 1), not a silent gap — the guard fails if a genuinely NEW,
    post-introduction entry tries to reuse that same legacy label.

Scope

  • Read each of the ~1,355 legacy-labelled baseline entries (or a
    representative, exhaustively-categorized sample if truly identical in
    shape — e.g. the same # noqa/# nosec-marked demo literal repeated
    across 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)
  • Update repo_tests/secrets_baseline_reasons.py's LEGACY_KEYS/reasons
    data 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_KEYS grows past its introduction size
  • Report a final count: entries confirmed false-positive vs. entries that
    turned out to be a real default needing a fix

Filed per the owner's ruling on #16299, milestone v0.9.0.

Activity

  1. added this to the v0.9.0 milestone on Sep 18, 2026
  2. mrveiss commented on Sep 28, 2026

    @mrveiss
    OwnerAuthor

    Chunking triage — a proposal, not an assignment

    Nothing was relabelled, moved or closed by this pass.

  3. mrveiss commented on Sep 28, 2026

    @mrveiss
    OwnerAuthor

    Which question #16299's guard answers — and why this issue's remaining AC should not be phrased as "shrink the file"

    Read at origin/main ab05ba3aef; 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_caught
    

    So the property enforced is tracked, not specific: an entry passes on a real SPECIFIC_REASONS reason 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.baseline have a non-null is_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 entries
    

    frozen 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 _offenders unions SPECIFIC_REASONS with 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 as SPECIFIC_REASONS grows.

    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 :16 as 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions