Browse Source

fix(push-gate): allowlist public Mapbox pk.* tokens, keep sk.* flagged

Mapbox public client tokens (pk.eyJ...) ship in the page source of every
Mapbox GL site and are exposed in-browser by design — they are not
secrets, but gitleaks' default rules flagged them, blocking legitimate
pushes of frontend map code.

scan-secrets.sh now loads references/gitleaks-config.toml via --config
(guarded, so the gate still runs with built-in defaults if absent). The
config extends the full default ruleset (useDefault = true) and carves
out only the public pk.* shape; secret sk.* tokens remain flagged. The
regex-layer fallback gets the same pk.eyJ allowlist entry.

Verified with gitleaks 8.30.1: pk.* allowlisted, sk.* still trips the
gate (exit 1).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0xDarkMatter 2 weeks ago
parent
commit
5e35818d19

+ 14 - 0
skills/push-gate/references/gitleaks-config.toml

@@ -0,0 +1,14 @@
+# push-gate gitleaks config — the full built-in rule set PLUS an allowlist for
+# tokens that are PUBLIC BY DESIGN and therefore not secrets. Loaded via --config
+# from scan-secrets.sh. `useDefault = true` keeps every built-in gitleaks rule
+# active; the allowlist only carves out known-public token shapes.
+[extend]
+useDefault = true
+
+# Mapbox public client tokens (pk.*) are embedded in the page source of every
+# Mapbox GL site and are exposed in-browser by design — they are not secrets.
+# Secret tokens (sk.*) are deliberately NOT allowlisted and remain flagged.
+[[allowlists]]
+description = "Mapbox public pk.* client tokens (public by design; sk.* still flagged)"
+regexTarget = "secret"
+regexes = ['''pk\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}''']

+ 8 - 1
skills/push-gate/scripts/scan-secrets.sh

@@ -66,9 +66,16 @@ echo "push-gate: scanning ${SCAN_LABEL}"
 GITLEAKS_REPORT="$(mktemp -t gitleaks.XXXXXX.json)"
 trap 'rm -f "$GITLEAKS_REPORT" "$DIFF_FILE" 2>/dev/null || true' EXIT
 
+# Config: default rule set + allowlist for public-by-design tokens (e.g. Mapbox pk.*).
+# Guarded so push-gate still runs with the built-in default config if it's absent.
+GL_PUBTOKEN_CFG="$SCRIPT_DIR/../references/gitleaks-config.toml"
+GL_CONFIG_ARG=()
+[ -f "$GL_PUBTOKEN_CFG" ] && GL_CONFIG_ARG=(--config "$GL_PUBTOKEN_CFG")
+
 GITLEAKS_EXIT=0
 gitleaks detect \
   --source . \
+  "${GL_CONFIG_ARG[@]}" \
   --log-opts="$GITLEAKS_LOG_OPTS" \
   --report-format=json \
   --report-path="$GITLEAKS_REPORT" \
@@ -130,7 +137,7 @@ RAW_HITS="$(rg --no-filename --line-number --no-heading "${PATTERN_ARGS[@]}" "$A
 # patterns (placeholder/example/getenv/etc) cover the bulk of false positives.
 FILTERED_HITS="$(
   printf '%s\n' "$RAW_HITS" \
-    | grep -viE '(example|placeholder|\<dummy\>|\<fake\>|\<TODO\>|<unset>|os\.environ|process\.env|getenv|\$\{[A-Z_]+:-|\$\{[A-Z_]+\}|\$\([A-Z_]+\)|\$env:[A-Z_]+|\.\.\.<)' \
+    | grep -viE '(example|placeholder|\<dummy\>|\<fake\>|\<TODO\>|<unset>|os\.environ|process\.env|getenv|\$\{[A-Z_]+:-|\$\{[A-Z_]+\}|\$\([A-Z_]+\)|\$env:[A-Z_]+|\.\.\.<|pk\.eyJ[A-Za-z0-9_-]{6,})' \
     || true
 )"