Skip to content

ci: allowlist the synthetic fixture token by content, not commit SHA - #68

Merged
sumitake merged 1 commit into
mainfrom
dev/claude/gitleaks-stale-fingerprints
Jul 28, 2026
Merged

ci: allowlist the synthetic fixture token by content, not commit SHA#68
sumitake merged 1 commit into
mainfrom
dev/claude/gitleaks-stale-fingerprints

Conversation

@sumitake

@sumitake sumitake commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

The weekly full-history Secret scan has been failing on main since the 4.2.0 clean-slate history rewrite. .gitleaksignore fingerprints are bound to a commit SHA (<commit>:<file>:<rule>:<line>); the rewrite re-parented every tracked file into a single squash commit, so all three entries still named the pre-rewrite SHA eec4c7a7 — a commit that no longer exists here. The exemption was dead and gitleaks reported 3 leaks.

The breakage was invisible on push and pull_request because gitleaks-action scans only the commits in the event range there. It surfaced only on the weekly schedule, which scans full history and re-reads the squash commit.

This replaces the SHA-bound fingerprints with a .gitleaks.toml allowlist scoped by line content, so the exemption survives any future rebase, squash, or history rewrite.

Evidence

  • Failing scheduled run 30251896215: gitleaks 8.24.3, gitleaks detect with no --log-opts, leaks found: 3, all generic-api-key on tests/fixtures/provider_dispatcher_protocol_v1.json lines 9/23/36 at commit b9c5a4e4.
  • git cat-file -t eec4c7a7d9940b9122fa255694ec8cb6a754388b → fails; the SHA is absent from this repository.
  • Fixed run 30335290546 on this branch: same full-history command, 37 commits scanned, no leaks found, both jobs green.

The flagged value is not a credential. "lane_token": "3b73a0ffbe3426ef5761f5c09b756ef6" is deterministically derived from fixed all-a/all-b digests by runtime_client._dispatcher_lane_token, and pinned byte-for-byte by test_dispatcher_protocol_matches_the_cross_repository_fixture, which holds the wire protocol in parity with the workspace-side counterpart. Changing the literal would break that parity contract, which is why the fix is an allowlist rather than a fixture edit.

Why the exemption stays narrow. Top-level paths and regexes are OR'd (there is no condition at top level), so adding a paths entry would exempt the whole fixture file. Instead regexTarget = "line" is matched against a regex pinning both the key and the literal value: any other secret added to that same fixture is still reported.

One non-obvious trap, recorded in the file's comments. The first attempt used top-level [[allowlists]] with condition = "AND" and silently did nothing (run 30335168339, still 3 leaks). In gitleaks 8.24 config/config.go, the plural Allowlists field with condition is parsed only inside [[rules]]; the top level takes singular Allowlist. An unsupported top-level table is dropped without warning — a quiet way to disable your own exemption.

Boundary declaration

  • No provider executor source, raw provider command, credential, private absolute path, retired package tree, downloader, or post-install hook is included.
  • Native-runtime changes, if any, contain only a final signed artifact and reviewed public verification metadata; implementation and credentials remain private. (No runtime change.)
  • The change does not create a host-specific preset or provider-specific plugin.

Generated and release surfaces

  • Skill specs and generated SKILL.md files are in parity.
  • Claude and Codex marketplaces/manifests are in parity.
  • No changelog.d/ fragment: CI-tooling fix with no user-visible behavior change (changelog.d/README.md § "When NOT to add a fragment"). CHANGELOG.md untouched.
  • No version bump: no behavior or distributed content changed.

Verification

  • python3 scripts/build_skills.py --check — PASS
  • python3 scripts/build_marketplace.py --check — PASS
  • python3 scripts/build-changelog.py --check — PASS
  • python3 -m unittest discover -s tests -t . — PASS (Ran 579 tests, OK, exit 0)
  • python3 -m unittest discover -s scripts -p 'test_*.py' — PASS (Ran 254 tests, OK, exit 0)
  • python3 scripts/check_release_consistency.py — PASS
  • python3 scripts/secret_scan.py — PASS (321 files, clean)
  • python3 scripts/check-public-export-safety.py --active-tree — SAFE
  • git diff --check — clean
  • End-to-end: workflow_dispatch of Secret scan on this branch, exercising the exact failing full-history path — green.

check-public-export-safety.py --history reports three raw_provider_recipe hits locally. They are unreachable dangling blobs left in the local clone by the same 4.2.0 rewrite (git rev-list --objects origin/main matches none of them; plugins/antigravity-collab/ is not tracked on main). Pre-existing, local-only, unrelated to this diff; a fresh CI checkout does not carry those objects.

Review and post-condition

Tier 3 (docs/public-governance.md) — declared conservatively: this changes the coverage of a credential-scanning gate on a public repository. Not an operator-reserved path (no CODEOWNERS entry).

Independent cross-family review — Grok (xAI), distinct from the Anthropic-family author:

VERDICT: APPROVE / CONFIDENCE: H / CONCERNS: none

Root-cause diagnosis "correct… complete and well supported". Deleting .gitleaksignore "safe" — it held only the three dead fingerprints. Allowlist scope: "claim holds… A different secret (other key, other value, same file) does not match and remains reportable." Public-repo posture: "no block… restores schedule without opening a meaningful bypass." Alternatives (refresh SHAs / path allowlist / change fixture literal / rule-level allowlist / stopwords) all assessed and rejected in favor of this approach as "the right durable fix".

Post-condition: after merge, confirm the next scheduled Secret scan on main is green, or dispatch it manually on main to confirm immediately.

Compliance trace

author: claude
standing_directives: public boundary declaration; changelog-fragment convention; independent cross-family review; full verification-gate run before merge
tier: 3
cross_check: PROCEED — Grok (xAI) governance review, APPROVE, confidence H, zero concerns; distinct family from the Anthropic-family author
post_condition: next scheduled (or manually dispatched) Secret scan on main is green
mcp_coverage_gap: NONE
contributor_rights: OWNER-AUTHORED
operator_reserved: no

The weekly full-history secret scan has been failing since the 4.2.0
clean-slate history rewrite. `.gitleaksignore` fingerprints are bound to a
commit SHA (`<commit>:<file>:<rule>:<line>`), and the rewrite re-parented
every tracked file into a single squash commit, so all three entries still
named the pre-rewrite SHA `eec4c7a7` -- a commit that no longer exists in
this repository. The exemption was dead and gitleaks reported 3 leaks.

The failure was invisible on push and pull_request because gitleaks-action
scans only the commits in the event range there; it surfaced only on the
weekly schedule, which scans full history and re-reads the squash commit.

Replace the SHA-bound fingerprints with a `.gitleaks.toml` allowlist scoped
by path AND line content, so the exemption survives any future rebase,
squash, or history rewrite. Scoping with condition = "AND" keeps coverage:
only this one literal synthetic value in this one fixture is exempt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sumitake
sumitake merged commit a740698 into main Jul 28, 2026
18 checks passed
@sumitake
sumitake deleted the dev/claude/gitleaks-stale-fingerprints branch July 28, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant