# claude-nomad: allowlist for tool-output noise that is structurally
# distinguishable from real secrets. Real high-entropy credentials
# (ghp_*, sk_live_*, xoxb-*, AKIA*) still fire because they do not match
# any allowlist regex.

[extend]
useDefault = true

# Path-scoped: this tool-output noise (gitleaks fingerprints, coverage
# line-keys, npm audit JSON id hashes, Sonar issue keys) accumulates in Claude
# Code session transcripts when a conversation runs those tools. Two of these
# regexes are structurally generic enough that, left global, they could suppress
# a real credential that happened to sit in a `path:word:digit` or hex-`id`
# context anywhere in the repo. Scoping to `shared/projects/<logical>/.../*.jsonl`
# with `condition = "AND"` (matching every other block below) confines the
# suppression to synced transcripts: a real secret in a source file still fires.
# The Sonar-issue-key regex is length-bounded to the real key shape (`AY` + 17-22
# base64url chars = 19-24 total, matching the sibling `key:`/`rule:` block) and
# token-anchored with `\b` on both ends, so it cannot suppress a longer or
# embedded `AY`-prefixed credential as a substring (an unbounded `{20,}` could).
[[allowlists]]
description = "claude-nomad: structurally-distinguishable tool-output noise in synced session transcripts"
regexes = [
    '''\bAY[A-Za-z0-9_-]{17,22}\b''',
    '''[\w./-]+\.[A-Za-z0-9]+:[\w-]+:\d+''',
    '''"id"\s*:\s*"[a-f0-9]{40,64}"''',
    '''key=[a-f0-9]{8,} [\w./-]+\.\w+:\d+''',
]
paths = [
    '''^shared/projects/[^/]+/.*\.jsonl$''',
]
condition = "AND"

# Path-scoped: the documented test-fixture github-pat literal AND the three
# entropy-variant placeholders (zero-suffix, alphabet, repeat-A) accumulate
# in Claude Code session transcripts whenever a conversation touches the
# Pitfall 4 docs, this allowlist itself, or a session-scrub discussion that
# names one of the variants. Live sessions cannot be safely sed-scrubbed
# (sed -i renames out from under the running CLI's open file descriptor
# and silently drops post-rename writes), so the only sustainable
# false-positive handler is a narrow allowlist scoped to synced session
# paths. `condition = "AND"` requires BOTH a known literal AND a
# `shared/projects/<logical>/.../*.jsonl` path; a real PAT in the same
# file (different 36-char body) still fires.
[[allowlists]]
description = "claude-nomad: documented test-fixture github-pat literals + scrub placeholders in synced session transcripts"
regexes = [
    '''ghp_xJZbT3qfV2nLpKR8mYwH4dGtCsW9aE1uF6oA''',
    '''ghp_xJZbT3qfV2nLpKR8mYwH4dGtCs0000000000''',
    '''ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789''',
    '''ghp_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA''',
]
paths = [
    '''^shared/projects/[^/]+/.*\.jsonl$''',
]
condition = "AND"

# Path-scoped: SSH public-key fingerprints in git signature-verification
# output (`git log --show-signature`, `git verify-commit`) land in session
# transcripts as `Good "git" signature for <signer> with ED25519 key
# SHA256:<43-char base64>`. The fingerprint is a hash of a PUBLIC key, not a
# credential, but its 43-char base64 body trips generic-api-key. Anchoring on
# the surrounding `with <keytype> key SHA256:` structure (via
# regexTarget = "line") keeps this from whitelisting a bare token: a real
# secret is never preceded by an SSH key-type label and the SHA256: scheme
# prefix. `condition = "AND"` plus the session-jsonl path scope double-locks
# it to synced transcripts.
[[allowlists]]
description = "claude-nomad: SSH public-key fingerprints (with <keytype> key SHA256:<b64>) in git signature output in synced session transcripts"
regexTarget = "line"
regexes = [
    '''with (?:ED25519|ED25519-SK|ECDSA|ECDSA-SK|RSA|DSA) key SHA256:[A-Za-z0-9+/]{43}''',
]
paths = [
    '''^shared/projects/[^/]+/.*\.jsonl$''',
]
condition = "AND"

# Path-scoped: SonarCloud issue-listing tool output (`gh`/sonar API dumps of
# the form `key: <20-char id>` immediately followed by `rule: <lang>:S<n>`)
# lands in session transcripts during PR reviews. The issue key is an opaque
# 20-char base64url identifier, not a credential, but it is shaped like a
# generic API key and does not carry the `AY` prefix the noise allowlist
# above keys on. Anchoring on the surrounding `key:`/`rule:` structure (via
# regexTarget = "line") keeps this from whitelisting a bare token: a real API
# key is never followed by `\n  rule: <lang>:S####`. `condition = "AND"` plus
# the session-jsonl path scope double-locks it to synced transcripts.
[[allowlists]]
description = "claude-nomad: SonarCloud issue-listing output (key: <id> / rule: <lang>:S<n>) in synced session transcripts"
regexTarget = "line"
regexes = [
    '''key:\s*[A-Za-z0-9_-]{19,24}\\n\s*rule:\s*\w+:S\d+''',
]
paths = [
    '''^shared/projects/[^/]+/.*\.jsonl$''',
]
condition = "AND"
