Skip to content

feat(gitleaks): make the estate baseline shareable instead of copy-only - #596

Merged
hyperpolymath merged 5 commits into
mainfrom
feat/gitleaks-estate-baseline-sharing
Aug 7, 2026
Merged

feat(gitleaks): make the estate baseline shareable instead of copy-only#596
hyperpolymath merged 5 commits into
mainfrom
feat/gitleaks-estate-baseline-sharing

Conversation

@hyperpolymath

@hyperpolymath hyperpolymath commented Aug 7, 2026

Copy link
Copy Markdown
Owner

The estate gitleaks baseline could not be inherited, only duplicated. This adds the sharing mechanism that several repos already assume exists.

The problem

A consumer repo wanting the shared allowlist had two options, both bad:

  • Copy it — copies drift; a fix to one is a fix to none of the others.
  • Push its repo-specific entries into the shared file — which blinds all 400+ repositories.

There was no third option, because the mechanism did not exist.

metadatastician/stapeln#21 is what surfaced it. It ships a well-reasoned config doing [extend] path = ".gitleaks-estate.toml", on the stated premise that this workflow stages that file. It does not, and never did:

FTL failed to load extended config, err: open .gitleaks-estate.toml: no such file or directory

That is worse than a missing feature. The config loads nothing, the scan runs over no files at all, and the failure presents as a findings failure — a scanner that appears to be working and is scanning nothing.

What this adds

config/gitleaks/estate-baseline.toml The shared baseline, git mvd out of this repo's root config so history is preserved. Only universally-true entries belong here.
.gitleaks.toml (this repo) Now a four-line consumer of it. Deliberate dogfooding — the mechanism is exercised by standards' own scan, so a change that breaks consumers breaks us first.
secret-scanner-reusable.yml Stages the baseline as .gitleaks-estate.toml, only when the repo's config actually references it.
docs/GITLEAKS-ESTATE-BASELINE.adoc How to opt in, and the two traps below.

This is a no-op for every existing caller. A repo that does not reference the baseline gains nothing in its scanned tree.

Two things verified rather than assumed

1. [extend] path resolves against the process working directory — not the config file's directory. Tested directly: the same relative path resolves from the repo root and fails from a subdirectory. That is why the baseline is staged at the workspace root, and it confirms the premise #21 was written against was correct.

2. Moving the baseline made it scannable. As .gitleaks.toml gitleaks excluded it automatically as its own config. At its new path it is an ordinary file, and its documented placeholder shapes immediately tripped generic-api-key — a finding caused purely by renaming the file.

Caught by scanning before and after:

before the move:                 9 findings
after the move:                 10 findings   <- the baseline flagging itself
after allowlisting both paths:   9 findings   <- zero regressions

Both the canonical path and the staged .gitleaks-estate.toml are now in the baseline's own paths. If it moves again, those entries move with it.

Design notes

Pinned by construction. The baseline is fetched at ${{ github.job_workflow_sha }} — the commit of this reusable workflow — so a caller pinned to an old SHA gets that SHA's baseline. The workflow and the baseline it stages can never disagree, and there is no moving @main fetch.

The checkout is removed before scanning. Otherwise standards' own tree is scanned as if it were the caller's, which is how a shared config turns into a wall of someone else's findings.

Failure is loud. If the baseline is referenced but cannot be fetched, the job errors rather than scanning with a silently reduced config. A scan that quietly loses its allowlist produces a wall of false positives, and the usual response to that is to switch the gate off — which is exactly the history this file already records from before #500.

Verification

gitleaks detect --source . --no-git   # 9 before, 9 after — no regression
python3 -c "import yaml; yaml.safe_load(open(...))"   # workflow parses

Unrelated pre-existing local edits in this checkout were deliberately left unstaged; this PR touches four files.

Follow-up

Once this lands, stapeln#21 becomes viable as written — its estate-extension approach and its documentation discipline ("each entry names what the value is"; plant a canary and confirm it is still detected) are better than the useDefault-plus-local-paths approach currently proposed in stapeln#20.

🤖 Generated with Claude Code


Summary by Gitar

  • Documentation & Standards:
    • Added ZIGZAG-TESTING.md and ZIGZAG-TESTING.adoc defining aspect-oriented testing methodology
    • Updated TEST-NEEDS.md to require Zigzag Testing for CRG Grade B/A

This will update automatically on new commits.

hyperpolymath and others added 4 commits July 31, 2026 09:23
The estate baseline could not be inherited, only duplicated. A consumer
repo wanting the shared allowlist had to copy it (copies drift), or push
its own repo-specific entries into the shared file (which blinds all 400+
repositories). There was no third option, because the sharing mechanism
did not exist.

stapeln #21 is what surfaced this. It ships a well-reasoned config that
does `[extend] path = ".gitleaks-estate.toml"` on the stated premise that
this workflow stages that file. It does not, and never did, so gitleaks
aborts before scanning anything:

    FTL failed to load extended config, err: open .gitleaks-estate.toml:
    no such file or directory

That is worse than a missing feature: the config loads nothing, the scan
runs on no files, and the failure looks like a findings failure.

WHAT THIS ADDS

- config/gitleaks/estate-baseline.toml — the shared baseline, moved out of
  this repo's root .gitleaks.toml (git mv, history preserved). Only
  universally-true entries belong here.
- .gitleaks.toml here is now a four-line consumer of it. Deliberate
  dogfooding: the mechanism is exercised by standards' own scan, so a
  change that breaks consumers breaks us first.
- secret-scanner-reusable.yml stages the baseline as .gitleaks-estate.toml
  in the consumer workspace, but ONLY when the repo's config actually
  references it. A repo that does not extend it gains nothing in its
  scanned tree, so this is a no-op for every existing caller.
- docs/GITLEAKS-ESTATE-BASELINE.adoc.

TWO THINGS VERIFIED RATHER THAN ASSUMED

`[extend] path` resolves against the process working directory, not the
config file's directory. Tested directly: the same relative path resolves
from the repo root and fails from a subdirectory. That is why the baseline
is staged at the workspace root, and it confirms the premise #21 was
written against.

Moving the baseline out of the root made it scannable. As `.gitleaks.toml`
gitleaks excluded it automatically as its own config; at its new path it is
an ordinary file, and its documented placeholder shapes immediately tripped
generic-api-key. Caught by scanning before and after the move: 9 findings
before, 10 after, 9 again once both the canonical path and the staged name
were allowlisted. Zero regressions.

Pinned by construction: the baseline is fetched at
github.job_workflow_sha, the commit of this workflow, so a caller pinned to
an old SHA gets that SHA's baseline. The workflow and its baseline cannot
disagree.

Fails loudly: if the baseline is referenced but cannot be fetched, the job
errors rather than scanning with a silently reduced config. A scan that
quietly loses its allowlist produces a wall of false positives, and the
usual response to that is to switch the gate off -- which is the history
this file already records.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gitar-bot

gitar-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

Note

Automatic reviews are paused because your trial's included automatic processing has been used for this period. Upgrade now, or comment "Gitar review" to run a review anytime.
Learn more

Code Review ✅ Approved

Makes the Gitleaks estate baseline shareable via [extend] path and workflow staging, alongside the new Zigzag Testing documentation standards. No issues found.

Auto-approved and auto-merge armed: No blocking issues found.
Please see Auto-approve Docs for details on setting custom approval criteria. — merges when pipeline and required approvals pass.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Important

Your trial ends in 3 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.

Was this helpful? React with 👍 / 👎 | Gitar

@gitar-bot
gitar-bot Bot enabled auto-merge (squash) August 7, 2026 13:26
@gitar-bot gitar-bot Bot added the gitar-approved Added by Gitar label Aug 7, 2026
gitar-bot[bot]
gitar-bot Bot previously approved these changes Aug 7, 2026

@gitar-bot gitar-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gitar has auto-approved this PR and enabled auto-merge (configure)

main moved under this branch. #597 ("close the baseline/alert split and
stop the SPDX check fighting the lockfile") rewrote both files this branch
touches, so the conflict is real rather than textual.

Both conflicts were additive and both sides are kept:

.gitleaks.toml -- #597 added a substantial measured finding to the
baseline: gitleaks 8.18.4 matches allowlist `regexes` against the whole
MATCH, not the extracted secret, and `regexTarget` does not change it, so
an anchored `^value$` entry is silently INERT for generic-api-key (the
estate's largest false-positive source). That documentation is preserved
verbatim -- it now lives in config/gitleaks/estate-baseline.toml, where it
reaches every repo that extends the baseline instead of only this one.
The root .gitleaks.toml remains the thin consumer.

secret-scanner-reusable.yml -- #597 added a comment explaining why
--verbose is required (without it the gate blocks a merge while telling
the author nothing, which is how 154 false positives sat untriaged across
eleven repositories). Kept, alongside the estate-baseline staging steps.

Verified in a clean worktree, same tree, both configs:

    main's config: 4 findings
    this branch:   3 findings
    regressions:   NONE
    difference:    the baseline file no longer flags itself

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Aug 7, 2026

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath disabled auto-merge August 7, 2026 13:45
@hyperpolymath
hyperpolymath merged commit 86bad54 into main Aug 7, 2026
36 of 37 checks passed
@hyperpolymath
hyperpolymath deleted the feat/gitleaks-estate-baseline-sharing branch August 7, 2026 13:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gitar-approved Added by Gitar

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant