diff --git a/.github/workflows/secret-scanner-reusable.yml b/.github/workflows/secret-scanner-reusable.yml index c7170194..b01c5f50 100644 --- a/.github/workflows/secret-scanner-reusable.yml +++ b/.github/workflows/secret-scanner-reusable.yml @@ -175,13 +175,25 @@ jobs: fi echo "Scanning ${#FILES[@]} Rust file(s)." + # Each pattern requires an assignment DIRECTLY to a string literal of + # meaningful length. The previous forms matched `= ... "` — a quote + # anywhere after an equals — which flagged code that hardcodes + # nothing at all. Measured across the 64 Rust repos in the estate + # sweep, every one of these was a false positive: + # let api_key = request["api_key"].as_str().unwrap_or("") (lookup) + # let api_key_file = temp_dir.path().join("config.js") (path) + # Query::new("Here's my api_key=sk-12345") (a demo) + # A credential shorter than 8 characters is not a credential either. + # `static` is accepted alongside `const`: the old `const.*KEY` form + # missed `static AUTH_KEY: &str = "…"`, a genuine hardcoded secret + # (caught by canary, not by inspection). PATTERNS=( - 'const.*SECRET.*=.*"' - 'const.*KEY.*=.*"[a-zA-Z0-9]{16,}"' - 'const.*TOKEN.*=.*"' - 'let.*api_key.*=.*"' + '(const|static)[[:space:]]+(mut[[:space:]]+)?[A-Za-z0-9_]*SECRET[A-Za-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"' + '(const|static)[[:space:]]+(mut[[:space:]]+)?[A-Za-z0-9_]*KEY[A-Za-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[a-zA-Z0-9]{16,}"' + '(const|static)[[:space:]]+(mut[[:space:]]+)?[A-Za-z0-9_]*TOKEN[A-Za-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"' + '(let|static)[[:space:]]+(mut[[:space:]]+)?[a-z0-9_]*api_key[a-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"' 'HMAC.*"[a-fA-F0-9]{32,}"' - 'password.*=.*"[^"]+"' + '[a-z0-9_]*password[a-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"' ) # Exemptions, mirroring the four layers already documented on