fix(secret-scanner): wire the estate gitleaks baseline and make findings visible - #584
Conversation
|
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. Code Review ✅ ApprovedWires the estate gitleaks baseline configuration and enables verbose redacted logging to resolve false positives and surface actionable scan findings. No issues found.
OptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Important Your trial ends in 4 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more. Was this helpful? React with 👍 / 👎 | Gitar |
The gitleaks gate ran with no `--config`, so gitleaks fell back to looking for `.gitleaks.toml` in the CALLER's tree. Measured 2026-08-06: none of the eleven repositories then failing this gate had one, so all eleven ran on bare default rules with no allowlist. Result: 154 findings across 11 repos, blocking 21 pull requests. Every one was triaged and every one is a false positive — ML training corpora, vendored Yarn bundles, published conformance vectors, `.example` configs, a Zotero bibliographic key, a public `did:key:` identifier, and fixtures belonging to the estate's own secret DETECTORS (cipherbot's analyzer tests, hypatia's scanner-suppression tests, a Scheme contract listing the patterns to detect). `.gitleaks.toml` already predicted this exact outcome in its own header — "turn the gate on with no allowlist, get a wall of red that is entirely noise, someone reverts, and the estate is back to a scanner that cannot fail." The file was written and then never connected to the scan. Four changes: 1. Stage the estate baseline into the workspace root and pass `--config`. It goes at the workspace root rather than $RUNNER_TEMP because gitleaks resolves `[extend] path` against the process CWD — verified, and the opposite of the intuitive "relative to the config file". This lets a repo-local `.gitleaks.toml` declare `[extend] path = ".gitleaks-estate.toml"` and inherit the whole baseline while adding only its own exemptions, so a repo-specific blind spot stays local instead of widening the allowlist for all 400+ repositories. 2. Add `--verbose`. Without it gitleaks prints only "leaks found: N" — no rule, no file, no line — and the run uploads no artifact, so the findings exist solely inside a discarded container. That is a gate that blocks a merge while telling the author nothing actionable, and it is why 154 false positives sat untriaged. `--redact` is already set, so the log gains the rule, path and line but never the value. 3. Document a silent limit of the allowlist `regexes` section. gitleaks 8.18.4 matches those regexes against the finding's MATCH — the whole matched span including surrounding context — not against the extracted secret, and `regexTarget` does not change this (measured with "secret", "match" and unset). So an anchored `^value$` entry works for `aws-access-token`, whose match IS the secret, and is silently INERT for `generic-api-key`, whose match looks like `api_key: "<value>"`. That is the rule responsible for 62 of the 140 remaining findings, so the section was inert exactly where it was most wanted. The comment now says so and directs false positives to a PATH entry in the owning repository instead. 4. Two new allowlist entries, plus the baseline's own path so it does not detonate on itself when staged (its example regexes are credential-shaped by construction — the same failure class as the self-detonating template block). Verified before commit, per the file's own DESIGN RULE: a planted AWS canary is still detected under every configuration above, the gate still exits 1 on a real finding and 0 on a clean tree, and the `[extend]` chain fails loudly (FTL, non-zero) rather than silently going blind if the baseline is missing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
57c8e78 to
ac80224
Compare
This file's own header says: "Do not add literal example tokens to this file, even inside comments." The comment I added to document the regexTarget limit broke that rule — it contained an illustrative key/value assignment, and Hypatia's security_errors/secret_detected rule matches inside COMMENTS, so it fired for real. The PR's own Hypatia gate reported it against .gitleaks.toml. That is the same self-referential class this repository has hit before: a file that describes secret patterns becomes a secret finding. Fixed by describing the shape in prose rather than showing it, which is how the surrounding comments in this file already handle the masked-token case. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
9bc53b6 to
6f89db8
Compare
standards' own `Validate Hypatia Baseline` gate was failing on three
banned-language files, which blocked this pull request. Estate language policy
bans Python with no exceptions, so all three are PORTED, not acknowledged.
An earlier revision of this commit recorded two of them in
.hypatia-baseline.json as "pre-existing debt". That was wrong and is reverted:
a baseline entry is for a finding that is not a violation, or one whose cure
needs its own review. Neither applies to a 58-line text-processing script in a
repository whose whole purpose is to define and enforce estate policy. Writing
the exemption would have made this repository the one place the policy did not
hold.
scripts/check-workflow-duplicate-keys.py -> .sh
Added on 2026-08-06 by me — a check written to protect workflows that
was itself blocking them.
scripts/relock-sha-keys.py -> .sh
⚠ Replacement is LITERAL, via index() splicing, not awk's gsub. Lockfile
keys contain `.` and `/` (actions/checkout@v7.0.1) and gsub treats its
pattern as a REGEX, so `@v7.0.1` would also match `@v7x0y1` in a
neighbouring entry.
a2ml/actions/validate/validate-manifest-dialect.py -> .sh
The dialect's exclusions (anchors, aliases, explicit tags, flow mappings,
single-quoted scalars) are the SPEC, not convenience — each one exists so
a manifest stays unambiguous to a non-YAML reader.
SHELL, NOT BUN. The estate's JS runtime moved from Deno to Bun, and the
duplicate-key check had already been through one language change in two days.
A script depending on no runtime cannot be invalidated by the next migration,
and 29 of the scripts here already work this way.
EVERY PORT VERIFIED BY DIFFERENTIAL TEST AGAINST ITS ORIGINAL, not by reading:
duplicate-key check 400 estate workflow files — 400 agree, 0 disagree;
both reject a synthetic duplicate with exit 1.
relock-sha-keys byte-identical lockfile output, and the entry with no
matching inline pin is left tag-keyed by both — the
safety property that stops it claiming a pin the estate
does not control.
manifest validator 894 real .a2ml files agree; and one planted violation of
each excluded class (anchor, alias, tag, flow map,
single quote, odd indent, tab indent, unparsed line)
plus a clean file with a block scalar containing
`free: text here` — all nine agree.
`git ls-files '*.py'` now returns nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
6f89db8 to
23eb35a
Compare
The workflow-lint job sparse-checks-out standards at `ref: main` to fetch the
duplicate-key checker. That means the RENAME OF THAT SCRIPT fails the linter on
the one pull request that cannot possibly be at fault: the new name does not
exist on main until the renaming pull request merges, so the fetch finds
nothing and the step dies on
cp: cannot stat '.standards-dupkey/scripts/check-workflow-duplicate-keys.sh'
A reusable that pins its own tooling to main cannot test a change to that
tooling. Any future rename hits this identically.
Two changes:
* the checkout is `continue-on-error` — its absence during a rename is
expected, not a failure;
* the step resolves the script, preferring the fetched copy so every other
caller stays on the canonical version, and falling back to the CALLER's own
tree. When the caller is standards itself, that local copy is the correct
one during a rename.
⚠ The `continue-on-error` is on the CHECKOUT, never on the check. If neither
copy is found the step still exits 1 with an explicit message. This estate has
enough gates that cannot fail; this is not becoming another one — the failure
is only moved to where it can say what went wrong instead of surfacing as a
bare `cp: cannot stat`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
Twelve of the fifty error-level Hypatia alerts blocking this repository are the
same templated line, copied into twelve .envrc files:
# export API_KEY="..."
A commented-out example, with an ellipsis for the value. Hypatia's
security_errors/secret_detected rule matches inside COMMENTS, and a quoted
ellipsis is shaped exactly like a value, so each copy reports as a found secret.
⚠ FIXED AT SOURCE RATHER THAN DISMISSED. Twelve dismissals would clear the
board and leave the next minted repository to reproduce all twelve — these are
template files. Changing the placeholder to an angle-bracket form conveys the
identical instruction to a human and cannot match a secret rule:
# export API_KEY=<your-value-here>
⚠ WHY THIS MATTERS BEYOND THE COUNT. standards' branch ruleset carries a
`code_scanning` rule requiring Hypatia at alerts_threshold `errors`, so ANY
error-level alert blocks EVERY merge in this repository — and standards gates
the whole estate. That block is invisible in the checks list: both required
status checks pass and the pull request still reports BLOCKED, with nothing on
the page saying why.
This clears 12 of 50. The remainder are genuine and separate: 11
unwrap_without_check (mixed — `Regex::new(<literal>).unwrap()` is
conventionally safe, `caps.get(1).unwrap()` is a real panic path), 7 secret
actions without a presence gate, 6 shell_download_then_run, and a tail of
FFI-boundary casts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
…nary
The four genuine shell_download_then_run findings, and a worse bug found while
fixing them.
⚠ THE BOOTSTRAP SCRIPTS WERE INSTALLING A 9-BYTE FILE CONTAINING "Not Found".
curl -L "https://github.com/hyperpolymath/must-spec/releases/latest/download/must" \
-o "$BIN_DIR/must"
...
chmod +x "$BIN_DIR/$tool"
No `-f`, so curl writes the HTTP error body to the output file as if it were
the program, and the next line makes it executable. Measured 2026-08-07: BOTH
URLs 404. `hyperpolymath/must-spec` does not exist at all, and
`nickel-augmented` is misnamed — the repository is `nickel-augmentation`, and
it has zero releases. So every bootstrap since has produced an environment
whose tools are error pages, and exited 0.
There is no artefact to pin, so this does not invent one: the tool install now
reports precisely why it cannot proceed and returns non-zero. Installing
something unusable and claiming success is worse than not running.
`just` is now fetched as a PINNED release binary, checksum-verified before use,
with the platform RESOLVED from uname rather than assumed — these scripts
support macOS and Windows package managers, so a hardcoded x86-64 Linux target
would land the wrong binary on Apple Silicon and every ARM machine. An
unrecognised platform returns failure and the caller falls back to the package
manager. Digests were computed from the artifacts on 2026-08-07; casey/just
publishes none, so this is trust-on-first-use — it does not prove they were
authentic then, but any later substitution fails loudly.
Also in rsr-deployer's bootstrap: the same comment
# WARNING: Pipe-to-shell is unsafe — download and verify first
had been inserted FOUR TIMES by an earlier sweep. A warning repeated four times
and acted on zero times is not a mitigation; it is now acted on and the
duplicates are gone.
And setup.sh's own usage instruction told readers to install it by
`curl … | sh`. A script that pins and checksum-verifies every tool it installs
should not ask to be installed by piping an unverified download into a shell.
It now says download, read, then run.
Files: setup.sh, neurosym-a2ml/scripts/bootstrap.sh,
agentic-a2ml/scripts/bootstrap.sh,
rhodium-standard-repositories/satellites/rsr-deployer/scripts/bootstrap.sh.
Verified: all four parse, shellcheck-clean at error level, and no live
pipe-to-shell remains in any of them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
An LSP that panics does not fail one request — it takes the editor's language
features down for the rest of the session. These 24 `.unwrap()` calls sat in
hover, completion and diagnostic handlers, which run on every keystroke.
Two distinct shapes, two distinct fixes.
LITERAL REGEXES (17) were `Regex::new(<literal>).unwrap()` declared inside the
handler functions, so every request RECOMPILED the pattern — on every
keystroke, for completions and diagnostics. Hoisted to `LazyLock` statics,
compiled once, with `expect` stating the invariant: the pattern is a
compile-time constant, so a failure is a programming error rather than a
runtime condition. Several functions shared the same literal and now share one
static.
CAPTURE-GROUP ACCESS (7) was `caps.get(N).unwrap()` after a successful match.
That holds while the group is non-optional, which makes it a latent trap: the
call site is correct today and becomes a panic the moment someone makes a
group optional. Each now handles the `None`, and the choice of handling is the
point:
* in a loop body -> `continue`. A panic aborts diagnostics for the WHOLE
document, so one odd line would blank the editor's problem list rather than
produce one fewer entry.
* in an iterator chain -> `filter_map` instead of `map`.
* in a function returning Option -> `?`.
Verified: `cargo check` clean, `cargo clippy` reports zero warnings, and all 12
existing tests pass. `grep '\.unwrap()' src/` now matches only the explanatory
comments describing what was removed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
Same treatment as a2ml-lsp, plus one failure mode that crate did not have. LITERAL REGEXES (5) recompiled on every request — every keystroke — inside the handler functions. Hoisted to `LazyLock` statics with `expect` stating the invariant. Named for WHAT THEY MATCH (TRUST_LEVEL_RE, VARIANT_RE) rather than for the local they replaced: a mechanical rename produced `RE_RE` and `RE_RE2`, which is a worse name than the original code had. CAPTURE ACCESS (9) was three separate `caps.get(N).unwrap()` calls per site — one each for `.as_str()`, `.start()` and `.end()`. Now bound once and matched, with `continue` on absence: a panic aborts diagnostics for the WHOLE document, so one malformed line would blank the editor's problem list rather than cost one entry. ⚠ FIVE `self.documents.lock().unwrap()` CALLS WERE THE WORST OF THEM. `Mutex::lock` fails only when the mutex is POISONED — some other handler panicked while holding it. Unwrapping there turns one panicked request into a PERMANENTLY DEAD language server: every subsequent request panics on the same poisoned lock, and the editor loses completions, hover and diagnostics for the rest of the session. Now `unwrap_or_else(|e| e.into_inner())`. Recovering is right for THIS data specifically, and the reasoning is recorded at the field: it is a cache of document text keyed by URI, so the worst a panic mid-update can leave is one stale entry, which the next didChange overwrites wholesale. There is no cross-entry invariant to violate. Recovery is not automatically correct for other poisoned locks and should not be applied by pattern. Also took clippy's `map_or` -> `is_some_and` suggestion. That warning was PRE-EXISTING — verified by running clippy against the unmodified file — but the crate is now warning-free rather than one-warning-and-stable. Verified: `cargo check` clean, `cargo clippy` zero warnings, 16/16 tests pass, and `grep '\.unwrap()' src/` matches only the comment describing the change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
…ot by pattern
Ten `RwLock` unwraps on the session store — five in src/session_manager.rs and
five in the copy inside tests-offline. Applying the poison-recovery pattern used
for k9-lsp's document cache would have introduced a SECURITY bug here, so this
does not do that.
`RwLock::read`/`write` fail only when another thread panicked while holding the
lock, and the correct response depends on what the function MEANS:
is_acknowledged -> FAIL CLOSED. It reports whether a session cleared the
manifest gate. Recovering a poisoned lock could read a half-updated map
and answer `true` for a session that had not acknowledged — failing OPEN
in a gatekeeper. It now returns false on doubt, which denies.
acknowledge -> PROPAGATE. It already returns Result, so the caller decides.
Recovering here could report an acknowledgement that was never stored.
get_or_create_session, cleanup_expired, active_count -> RECOVER. Creating a
session, counting sessions and expiring them grant no access; the worst a
mid-update panic leaves is one stale entry.
The reasoning is recorded at the field, because the next person to see five
identical `.unwrap()`s will be tempted to replace them with five identical
recoveries.
⚠ VERIFICATION IS INDIRECT, AND WORTH STATING. The main crate DOES NOT BUILD:
fuse3 v0.7.3 fails to compile on Rust >= 1.80, which is why tests-offline
exists as a separate crate at all. So src/session_manager.rs could not be
compiled directly. tests-offline carries a byte-identical copy of this logic —
verified: 3 write().unwrap() and 2 read().unwrap() in each before the change —
and the same edit applied there compiles and passes all 29 tests.
That the production crate cannot be built at all is a larger problem than these
unwraps, and is not addressed here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
CODE FIXES, each compiled and tested:
enterprise-service/src/handlers.rs — four RwLock unwraps in HTTP handlers.
Three return Result<_, AppError> and now surface AppError::Internal on a
poisoned lock: serving from a half-written map returns data the service
cannot vouch for, and 500 is the honest answer. ⚠ `list_users` returns
`Json<Vec<User>>` with NO error channel, so it cannot report a 500 without an
API change — it recovers and logs at warn instead, and the comment says so
rather than leaving the asymmetry unexplained. 6/6 tests pass.
k9-svc/bindings/rust/src/parser.rs — `starts_with("component:")` followed by
`strip_prefix("component:").unwrap()`. Folded into one `if let Some(rest) =
strip_prefix(...)`: one prefix scan instead of two, and the guard can no
longer drift away from the extraction it protects. 9+33 tests pass.
a2ml/bindings/rust/src/parser.rs — `chars().next().unwrap()` guarded by
`len() < 3` three lines above. Infallible today, but guard and unwrap are
separate statements with nothing keeping them in step. Now let-else.
11+36 tests pass.
RECORDED, WITH THE REASON, because they are not defects to fix:
Zig FFI casts (**/ffi/zig/**, **/zig-gateway/**) — a shim crossing into a
foreign runtime must reinterpret opaque pointers. Architectural: it does not
shrink over time.
information_theory.agda postulates — the file already states the reasoning:
known theorems of information theory that cannot be proven over Agda's
IEEE-754 Float without a real-analysis formalisation. Recorded in the file's
own words: justified postulates, not proof debt.
Tea.res.js — GENERATED ReScript output. Editing it is overwritten on the next
build; a fix belongs in the .res source, which is itself slated for removal
under the ReScript ban.
check-ts-allowlist.ts — the TS source of the TS→AffineScript migration
(standards#239/#241). ⚠ Its compiled target is a .deno.js and the estate has
moved to Bun, so that retirement now has a second reason.
⚠ ONE ENTRY IS DELIBERATELY LEFT AS WORK TO DO. The wildcard CORS header in
consent-aware-http's reference implementation is recorded rather than
suppressed: a reference implementation is precisely the thing people copy, so
`Access-Control-Allow-Origin: *` there propagates into real services. It is
noted as a finding to fix, not as an exemption.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
The comments I added explaining the unwrap removal QUOTED the construct they removed, and would therefore have been reported as findings themselves. Hypatia strips `///` and `//!` doc comments for Rust — the regex is `^[ \t]*//[/!][^\n]*$` — but NOT plain `//` comments. So four files that now contain zero live unwraps still matched `unwrap_without_check`, purely on the explanatory text. I would have removed 38 findings and introduced 4. This is the same self-referential trap `standards/.gitleaks.toml` already warns about for secrets: "Deliberately described rather than shown: writing the masked token out literally here makes THIS file trip the estate's Hypatia secret detector." The rule applies to any detector, not just secrets — a file that documents a pattern will be matched by the rule that looks for it. Reworded to describe the construct in prose. `grep '\.unwrap()'` across all four files now matches nothing at all, and both crates still pass their tests. Extending the strip to plain `//` comments would also have worked and is arguably right for code_safety — a commented-out `.unwrap()` cannot panic — but it is a wider change to the scanner than this cleanup warrants, and a `//` comment can legitimately hold commented-out code that a reader should still notice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
|
…ing them This is the upstream cause of a required gate failing in hyperpolymath/standards#584, traced from the merge block down. `expect_in_hot_path` is meant not to fire inside a `LazyLock` body, because that body runs ONCE — the rule carries `context: :runtime_path` and `strip_lazy_initialisers` is supposed to elide those bodies first. The intent, in the existing comment, was "brace-counting from the initialiser opener". The implementation was a regex with two hard-coded levels of nesting. ⚠ REGEXES CANNOT COUNT, and the nesting here is unbounded because the elided body contains a REGEX LITERAL whose own groups nest arbitrarily: LazyLock::new(|| Regex::new(r"\[\|\s*((?:'[A-Za-z]+\s*,?\s*)*)\|]").expect(..)) That pattern is one level deeper than the approximation allowed, so the initialiser was not elided and its `.expect(` was reported as a hot-path finding — on a body that by definition runs once. Measured in k9-svc/lsp: FOUR of five statics elided and the fifth did not, differing only in having one more capture group. A rule that fires or not depending on how many groups an unrelated pattern contains is not measuring anything. Replaced with an actual paren counter. ⚠ RUST STRING LITERALS ARE HONOURED, INCLUDING RAW STRINGS. `r#"..."#` exists precisely so a literal may contain `"`, and regex patterns use it for exactly that — `r#"(install|deploy)\s*=\s*"([^"]*)""#`. Treating those embedded quotes as delimiters desynchronises the count. That was not hypothetical: after the plain-string case was handled, this exact pattern still survived elision. ⚠ THE DANGEROUS FAILURE MODE IS SILENT. A desynchronised counter does not error — it swallows the remainder of the file, blinding every code_safety rule after that point while still reporting success. There is a test for it. Four regression tests: nested capture groups elide; hash raw strings elide; a genuine per-call `.expect(` two lines later is STILL reported; and an unbalanced paren inside a string does not swallow the file. 41 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
All of this repository's gitleaks findings were triaged on 2026-08-06 by reading each matched line with the value redacted. **Every one is a false positive — no live credential was found.** This adds locally justified path exemptions. Each names *what the value actually is* rather than saying a file is noisy. **Why local and not in the estate baseline:** every entry is a blind spot. Held here it blinds this repository only, and the justification sits beside the code it describes. Promoted to the baseline it would blind all 400+ repositories. **Depends on hyperpolymath/standards#584**, which wires the estate baseline into the scan and stages it at the workspace root so this file's `[extend] path` resolves. **Verified before commit:** with this config in place, a planted AWS canary outside the exempted paths is still DETECTED and the gate still exits non-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
All of this repository's gitleaks findings were triaged on 2026-08-06 by reading each matched line with the value redacted. **Every one is a false positive — no live credential was found.** This adds locally justified path exemptions. Each names *what the value actually is* rather than saying a file is noisy. **Why local and not in the estate baseline:** every entry is a blind spot. Held here it blinds this repository only, and the justification sits beside the code it describes. Promoted to the baseline it would blind all 400+ repositories. **Depends on hyperpolymath/standards#584**, which wires the estate baseline into the scan and stages it at the workspace root so this file's `[extend] path` resolves. **Verified before commit:** with this config in place, a planted AWS canary outside the exempted paths is still DETECTED and the gate still exits non-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
All of this repository's gitleaks findings were triaged on 2026-08-06 by reading each matched line with the value redacted. **Every one is a false positive — no live credential was found.** This adds locally justified path exemptions. Each names *what the value actually is* rather than saying a file is noisy. **Why local and not in the estate baseline:** every entry is a blind spot. Held here it blinds this repository only, and the justification sits beside the code it describes. Promoted to the baseline it would blind all 400+ repositories. **Depends on hyperpolymath/standards#584**, which wires the estate baseline into the scan and stages it at the workspace root so this file's `[extend] path` resolves. **Verified before commit:** with this config in place, a planted AWS canary outside the exempted paths is still DETECTED and the gate still exits non-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
All of this repository's gitleaks findings were triaged on 2026-08-06 by reading each matched line with the value redacted. **Every one is a false positive — no live credential was found.** This adds locally justified path exemptions. Each names *what the value actually is* rather than saying a file is noisy. **Why local and not in the estate baseline:** every entry is a blind spot. Held here it blinds this repository only, and the justification sits beside the code it describes. Promoted to the baseline it would blind all 400+ repositories. **Depends on hyperpolymath/standards#584**, which wires the estate baseline into the scan and stages it at the workspace root so this file's `[extend] path` resolves. **Verified before commit:** with this config in place, a planted AWS canary outside the exempted paths is still DETECTED and the gate still exits non-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
All of this repository's gitleaks findings were triaged on 2026-08-06 by reading each matched line with the value redacted. **Every one is a false positive — no live credential was found.** This adds locally justified path exemptions. Each names *what the value actually is* rather than saying a file is noisy. **Why local and not in the estate baseline:** every entry is a blind spot. Held here it blinds this repository only, and the justification sits beside the code it describes. Promoted to the baseline it would blind all 400+ repositories. **Depends on hyperpolymath/standards#584**, which wires the estate baseline into the scan and stages it at the workspace root so this file's `[extend] path` resolves. **Verified before commit:** with this config in place, a planted AWS canary outside the exempted paths is still DETECTED and the gate still exits non-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
All of this repository's gitleaks findings were triaged on 2026-08-06 by reading each matched line with the value redacted. **Every one is a false positive — no live credential was found.** This adds locally justified path exemptions. Each names *what the value actually is* rather than saying a file is noisy. **Why local and not in the estate baseline:** every entry is a blind spot. Held here it blinds this repository only, and the justification sits beside the code it describes. Promoted to the baseline it would blind all 400+ repositories. **Depends on hyperpolymath/standards#584**, which wires the estate baseline into the scan and stages it at the workspace root so this file's `[extend] path` resolves. **Verified before commit:** with this config in place, a planted AWS canary outside the exempted paths is still DETECTED and the gate still exits non-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
All of this repository's gitleaks findings were triaged on 2026-08-06 by reading each matched line with the value redacted. **Every one is a false positive — no live credential was found.** This adds locally justified path exemptions. Each names *what the value actually is* rather than saying a file is noisy. **Why local and not in the estate baseline:** every entry is a blind spot. Held here it blinds this repository only, and the justification sits beside the code it describes. Promoted to the baseline it would blind all 400+ repositories. **Depends on hyperpolymath/standards#584**, which wires the estate baseline into the scan and stages it at the workspace root so this file's `[extend] path` resolves. **Verified before commit:** with this config in place, a planted AWS canary outside the exempted paths is still DETECTED and the gate still exits non-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
All of this repository's gitleaks findings were triaged on 2026-08-06 by reading each matched line with the value redacted. **Every one is a false positive — no live credential was found.** This adds locally justified path exemptions. Each names *what the value actually is* rather than saying a file is noisy. **Why local and not in the estate baseline:** every entry is a blind spot. Held here it blinds this repository only, and the justification sits beside the code it describes. Promoted to the baseline it would blind all 400+ repositories. **Depends on hyperpolymath/standards#584**, which wires the estate baseline into the scan and stages it at the workspace root so this file's `[extend] path` resolves. **Verified before commit:** with this config in place, a planted AWS canary outside the exempted paths is still DETECTED and the gate still exits non-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
All of this repository's gitleaks findings were triaged on 2026-08-06 by reading each matched line with the value redacted. **Every one is a false positive — no live credential was found.** This adds locally justified path exemptions. Each names *what the value actually is* rather than saying a file is noisy. **Why local and not in the estate baseline:** every entry is a blind spot. Held here it blinds this repository only, and the justification sits beside the code it describes. Promoted to the baseline it would blind all 400+ repositories. **Depends on hyperpolymath/standards#584**, which wires the estate baseline into the scan and stages it at the workspace root so this file's `[extend] path` resolves. **Verified before commit:** with this config in place, a planted AWS canary outside the exempted paths is still DETECTED and the gate still exits non-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
All of this repository's gitleaks findings were triaged on 2026-08-06 by reading each matched line with the value redacted. **Every one is a false positive — no live credential was found.** This adds locally justified path exemptions. Each names *what the value actually is* rather than saying a file is noisy. **Why local and not in the estate baseline:** every entry is a blind spot. Held here it blinds this repository only, and the justification sits beside the code it describes. Promoted to the baseline it would blind all 400+ repositories. **Depends on hyperpolymath/standards#584**, which wires the estate baseline into the scan and stages it at the workspace root so this file's `[extend] path` resolves. **Verified before commit:** with this config in place, a planted AWS canary outside the exempted paths is still DETECTED and the gate still exits non-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>



The gitleaks gate ran with no
--config, so gitleaks fell back to lookingfor
.gitleaks.tomlin the CALLER's tree. Measured 2026-08-06: none of theeleven repositories then failing this gate had one, so all eleven ran on bare
default rules with no allowlist.
Result: 154 findings across 11 repos, blocking 21 pull requests. Every one
was triaged and every one is a false positive — ML training corpora, vendored
Yarn bundles, published conformance vectors,
.exampleconfigs, a Zoterobibliographic key, a public
did:key:identifier, and fixtures belonging tothe estate's own secret DETECTORS (cipherbot's analyzer tests, hypatia's
scanner-suppression tests, a Scheme contract listing the patterns to detect).
.gitleaks.tomlalready predicted this exact outcome in its own header —"turn the gate on with no allowlist, get a wall of red that is entirely
noise, someone reverts, and the estate is back to a scanner that cannot
fail." The file was written and then never connected to the scan.
Four changes:
Stage the estate baseline into the workspace root and pass
--config.It goes at the workspace root rather than $RUNNER_TEMP because gitleaks
resolves
[extend] pathagainst the process CWD — verified, and theopposite of the intuitive "relative to the config file". This lets a
repo-local
.gitleaks.tomldeclare[extend] path = ".gitleaks-estate.toml"and inherit the whole baseline while adding only its own exemptions, so a
repo-specific blind spot stays local instead of widening the allowlist for
all 400+ repositories.
Add
--verbose. Without it gitleaks prints only "leaks found: N" — norule, no file, no line — and the run uploads no artifact, so the findings
exist solely inside a discarded container. That is a gate that blocks a
merge while telling the author nothing actionable, and it is why 154 false
positives sat untriaged.
--redactis already set, so the log gains therule, path and line but never the value.
Set
regexTarget = "secret"on the allowlist. Without an explicit target,gitleaks 8.18.4 does not apply the allowlist regexes to
generic-api-keyfindings at all — measured: an EXACT-value entry fails to suppress a
generic-api-keyfinding while the same entry does suppress anaws-access-tokenone. Every anchored regex in the file was silently inertfor the rule that needed them most.
Two new allowlist entries, plus the baseline's own path so it does not
detonate on itself when staged (its example regexes are credential-shaped
by construction — the same failure class as the self-detonating template
block).
Verified before commit, per the file's own DESIGN RULE: a planted AWS canary
is still detected under every configuration above, the gate still exits 1 on
a real finding and 0 on a clean tree, and the
[extend]chain fails loudly(FTL, non-zero) rather than silently going blind if the baseline is missing.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
🤖 Generated with Claude Code