Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions internal/redaction/betterleaks.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ targetRules = ["generic-api-key"]
regexTarget = "match"
regexes = ['''(?i)\bsha(?:1|224|256|384|512):[0-9a-f]{40,128}\b''']

[[allowlists]]
description = "SSH public key fingerprints, such as the output of git log --show-signature"
targetRules = ["generic-api-key"]
regexTarget = "match"
# OpenSSH prints a fingerprint as SHA256: and the unpadded base64 of the hash,
# which is always 43 characters. The fingerprint must end the match, so a
# longer value after SHA256:, also one that goes on after a - . or _, is still
# redacted. Only the terminator the rule itself adds to its match can follow:
# a quote, a backtick, whitespace, a semicolon, or an escaped line break.
regexes = ['''\bSHA256:[A-Za-z0-9+/]{43}(?:[\x60'"\s;]|\\[nr])?$''']

[[allowlists]]
description = "Code expressions, test durations and the bare key word, which are not password values"
targetRules = ["generic-password"]
Expand Down
39 changes: 39 additions & 0 deletions internal/redaction/precision_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const (
// sampleAPIKey is a random-looking key the generic-api-key rule matches.
sampleAPIKey = "q8Zr2LmX7v" + "Pk4TnW9sYb"
sampleEmail = "sarah@chainloop.local"
// sampleSSHFingerprint is the unpadded base64 of a SHA-256 hash, as
// OpenSSH prints the fingerprint of a public key after SHA256:
sampleSSHFingerprint = "q3Rk8vLm2+Zx7Pw4" + "Tn9sYbHc1/Fd6Gj0" + "Ue5Ai8Ko2Ws"

ruleGenericAPIKey = "generic-api-key"
ruleGitHubPAT = "github-pat"
Expand Down Expand Up @@ -148,6 +151,17 @@ func TestRulesConfigKeepsNonSecrets(t *testing.T) {
text: "API_URL=http://localhost:48002\nCAS_ENDPOINT=localhost:49001\nTEST_EMAIL=" + sampleEmail + "\n",
wantDefaultRule: ruleCredentialURI,
},
{
// git log --show-signature on a commit signed with an SSH key
name: "ssh key fingerprint of a commit signature",
text: "Good \"git\" signature for " + sampleEmail + " with ED25519 key SHA256:" + sampleSSHFingerprint + "\n",
wantDefaultRule: ruleGenericAPIKey,
},
{
name: "rsa key fingerprint of a commit signature",
text: "Good \"git\" signature for " + sampleEmail + " with RSA key SHA256:" + sampleSSHFingerprint + "\n",
wantDefaultRule: ruleGenericAPIKey,
},
}

for _, tc := range testCases {
Expand Down Expand Up @@ -191,6 +205,31 @@ func TestRulesConfigStillRedactsSecrets(t *testing.T) {
secret: sampleDigest,
wantRule: ruleGenericAPIKey,
},
{
name: "base64 key without a fingerprint prefix",
text: "api_key: " + sampleSSHFingerprint + "\n",
secret: sampleSSHFingerprint,
wantRule: ruleGenericAPIKey,
},
{
name: "key longer than a fingerprint after a SHA256 prefix",
text: "signing key SHA256:" + strings.Repeat(sampleAPIKey, 3) + "\n",
secret: strings.Repeat(sampleAPIKey, 3),
wantRule: ruleGenericAPIKey,
},
{
name: "key that continues a fingerprint with a separator",
text: "signing key SHA256:" + strings.Repeat(sampleAPIKey, 3)[:43] + "-" + sampleAPIKey + "\n",
secret: sampleAPIKey,
wantRule: ruleGenericAPIKey,
},
{
name: "api key on the line after an ssh key fingerprint",
text: "Good \"git\" signature with ED25519 key SHA256:" + sampleSSHFingerprint + "\napi_key: " + sampleAPIKey + "\n",
secret: sampleAPIKey,
wantRule: ruleGenericAPIKey,
keep: "SHA256:" + sampleSSHFingerprint,
},
{
name: "password next to an email username",
text: "host: db.internal\nuser: " + sampleEmail + "\npassword: " + samplePassword + "\n",
Expand Down
Loading