diff --git a/docs/architecture/scripts/secrets.sh b/docs/architecture/scripts/secrets.sh index b3bd38c..ae9d9ed 100755 --- a/docs/architecture/scripts/secrets.sh +++ b/docs/architecture/scripts/secrets.sh @@ -68,6 +68,11 @@ cd "$(git rev-parse --show-toplevel 2>/dev/null)" || { say() { printf 'secrets: %s\n' "$*" >&2; } +# The delimiter for the masking substitution below. A real control byte, because +# these patterns contain both `/` and `|` and either would end the expression +# early. It cannot occur in a pattern and it cannot occur in source text. +MASK_D=$'\001' + MODE="staged" BUILT_DIR="" ALLOW=() @@ -92,7 +97,10 @@ done # and it is far too eager to run against source, where it matches ordinary # base64. In a bundle it is worth the noise. BUILT_PATTERNS=( - 'eyJ[A-Za-z0-9_-]{10,}' + # All three segments, not just the header. Masking removes exactly what the + # pattern matched, so a pattern that stops at the first dot redacts `eyJ...` + # and prints the payload and signature beside it -- which is the token. + 'eyJ[A-Za-z0-9_-]{10,}(\.[A-Za-z0-9_-]+){0,2}' '\bservice_role\b' '\bapikey["'"'"'[:space:]]*[:=]' ) @@ -225,13 +233,18 @@ for pattern in "${PATTERNS[@]}"; do done [ -n "$skip" ] && continue - # The line is truncated to 120 characters, which bounds how much of a long - # value reaches the terminal. It does NOT redact the match: a credential - # shorter than the budget is printed whole, and a scanner that prints the - # secret it found has published it to the scrollback, the CI log, and - # wherever that log is shipped. Masking the matched span is the real fix and - # is tracked separately -- until then, treat this output as sensitive. - printf ' %.120s…\n' "$hit" + # The match is masked, then the line is truncated. Truncation alone was not + # enough and used to be all there was: it bounds how much of a LONG value + # reaches the terminal and prints a short one whole, so the scanner + # published the very thing it was built to find — to the scrollback, the CI + # log, and wherever that log is shipped. + # + # \001 as the delimiter, because these patterns contain both `/` and `|` + # and either would end the expression early. It cannot occur in a pattern + # and it cannot occur in the text of a source file. + masked="$(printf '%s' "$hit" | sed -E "s${MASK_D}${pattern}${MASK_D}[redacted]${MASK_D}g" 2>/dev/null)" + [ -n "$masked" ] || masked="[a line matching a credential pattern, unprintable]" + printf ' %.120s…\n' "$masked" found=$((found + 1)) done < <(printf '%s\n' "$CONTENT" | grep -nEI "$pattern" 2>/dev/null | head -20) done