#!/usr/bin/env bats # Tests for the secret-scan block shared by the elisp, bash, and go pre-commit # hooks. The block greps added lines in the staged diff for credential # patterns; a hit blocks the commit (exit 1), a clean scan falls through to the # variant's language check (exit 0). # # Every case stages a .txt file, so the language checks that follow the scan # (check-parens, shellcheck, gofmt) all skip and the scan is what's under test. # # The two boundary cases exist because of a live false-positive in a downstream # project: an embedded PNG sprite data URI blocked a real commit and forced # --no-verify. Root cause was `grep -iE` applying case-insensitivity to the # fixed-case AWS token AKIA[0-9A-Z]{16}, so any mixed-case 20-char run inside a # random base64 blob matched. Measured at ~6% of 100KB blobs; case-sensitive # matching drops it to 0 across ~10MB. VARIANTS="elisp bash go" setup() { REPO="$(mktemp -d)" cd "$REPO" || return 1 git init -q . git config user.email t@example.com git config user.name Test } teardown() { cd /tmp || true [ -n "${REPO:-}" ] && rm -rf "$REPO" } # Stage $2 as the content of file $1 (default staged.txt). stage() { local file="${2:-staged.txt}" printf '%s\n' "$1" > "$file" git add "$file" } # Run a variant's hook in the temp repo. $1 = variant name. run_hook() { bash "${BATS_TEST_DIRNAME}/../../languages/$1/githooks/pre-commit" } # ---- Normal: real secrets still block, clean content still passes ---- @test "secret-scan: clean content passes in every variant" { stage 'const greeting = "hello world";' for v in $VARIANTS; do run run_hook "$v" [ "$status" -eq 0 ] || { echo "$v blocked clean content: $output"; return 1; } done } @test "secret-scan: a real uppercase AWS access key blocks in every variant" { stage 'aws_key = "AKIAIOSFODNN7EXAMPLE"' for v in $VARIANTS; do run run_hook "$v" [ "$status" -eq 1 ] || { echo "$v missed an AWS key"; return 1; } [[ "$output" == *"potential secret"* ]] done } @test "secret-scan: a keyword=value credential blocks in every variant" { stage 'api_key: "sk_live_9f3b2a7c1e4d8f0a6b5"' for v in $VARIANTS; do run run_hook "$v" [ "$status" -eq 1 ] || { echo "$v missed an api_key assignment"; return 1; } done } @test "secret-scan: a PEM private-key header blocks in every variant" { stage '-----BEGIN RSA PRIVATE KEY-----' for v in $VARIANTS; do run run_hook "$v" [ "$status" -eq 1 ] || { echo "$v missed a PEM header"; return 1; } done } # ---- Boundary: the case-sensitivity fix ---- @test "secret-scan: a lowercase akia-like run does not block (AWS keys are uppercase)" { # Under `grep -iE` this matched the AKIA token and blocked a legitimate commit. stage 'const blob = "akiaiosfodnn7examplexyz";' for v in $VARIANTS; do run run_hook "$v" [ "$status" -eq 0 ] || { echo "$v false-positived on a lowercase run: $output"; return 1; } done } @test "secret-scan: an embedded base64 data URI carrying a mixed-case akia run does not block" { # The live failure: a sprite blob whose random base64 contained a mixed-case # 20-char run. Case-sensitive matching is what clears it. stage 'const SPRITE = "data:image/png;base64,iVBORw0KGgoAkIaIOSFODNN7ExAMPLEqQmCC";' for v in $VARIANTS; do run run_hook "$v" [ "$status" -eq 0 ] || { echo "$v false-positived on a sprite data URI: $output"; return 1; } done } # ---- Boundary: the scan must not go blind on data-URI lines ---- @test "secret-scan: a real credential sharing a line with a base64 data URI still blocks" { # Minified bundles put a whole file on one line, so a data URI and a real key # can share it. Skipping any line containing ';base64,' would hide the key. stage 'const S="data:image/png;base64,iVBORw0KGgoAAAANS";const c={api_key:"sk_live_9f3b2a7c1e4d8f0a6b5"};' for v in $VARIANTS; do run run_hook "$v" [ "$status" -eq 1 ] || { echo "$v went blind on a data-URI line and missed the key"; return 1; } done } @test "secret-scan: a line matching both passes is reported once, not twice" { # The scan runs a case-sensitive and a case-insensitive pass. A line carrying # both an AWS key and a keyword=value credential hits both; reporting it twice # reads as two separate leaks. stage 'api_key = "AKIAIOSFODNN7EXAMPLE_padding"' for v in $VARIANTS; do run run_hook "$v" [ "$status" -eq 1 ] hits="$(printf '%s\n' "$output" | grep -c 'AKIAIOSFODNN7EXAMPLE_padding')" [ "$hits" -eq 1 ] || { echo "$v reported the line $hits times, want 1"; return 1; } done } # ---- Error / edge ---- @test "secret-scan: an empty staged diff passes" { for v in $VARIANTS; do run run_hook "$v" [ "$status" -eq 0 ] || { echo "$v failed on an empty diff: $output"; return 1; } done } @test "secret-scan: a secret only on a removed line does not block" { # The scan reads added lines. Deleting a key should never block the deletion. stage 'aws_key = "AKIAIOSFODNN7EXAMPLE"' git commit -qm "seed" --no-verify printf 'clean\n' > staged.txt git add staged.txt for v in $VARIANTS; do run run_hook "$v" [ "$status" -eq 0 ] || { echo "$v blocked a removal: $output"; return 1; } done }