From 72ed49d9fa15a4e3cc445e3f32f355e8990d41c1 Mon Sep 17 00:00:00 2001 From: "@permadeath.com" Date: Tue, 11 Aug 2026 14:30:42 -0400 Subject: [PATCH] test(container): cover redact() redact() strips credentials out of a URL or an Authorization header before fetch() logs it in a fatal die message - the one thing standing between a malformed presigned camo/manifest URL and a real credential landing in the log. It had zero coverage. Covers every query-parameter spelling it handles (X-Amz-Signature, Signature, sig, token), a case-insensitive variant, more than one credential in the same URL, an Authorization: header, and a URL with no credential at all, which must come through unchanged. --- tests/shell/test-redact.sh | 90 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100755 tests/shell/test-redact.sh diff --git a/tests/shell/test-redact.sh b/tests/shell/test-redact.sh new file mode 100755 index 0000000..f7b4f55 --- /dev/null +++ b/tests/shell/test-redact.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +# redact() in lib/common.sh is the only thing standing between a malformed or +# expired presigned camo/manifest URL and a real credential landing in the +# container's log - fetch() pipes a failed download's URL through it before +# handing the result to `die`. It had no coverage at all until this file. +# +# Each case pipes a fixture line through redact() in a child shell (a clean +# sourcing of common.sh) and checks the credential value is gone while the +# rest of the line survives. +set -uo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" + +fail=0 +check() { # + if "${@:2}"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi +} + +# redact_line -> redact()'s output for that one line +redact_line() { + printf '%s\n' "$1" | \ + bash -c 'set -uo pipefail; . "$1"; redact' _ "$ROOT/container/lib/common.sh" +} + +gone() { bash -c '! grep -qF -- "$2" <<<"$1"' _ "$1" "$2"; } # +present() { bash -c 'grep -qF -- "$2" <<<"$1"' _ "$1" "$2"; } # + +# --- every query-parameter spelling redact() claims to handle --------------- + +url="https://bucket.s3.amazonaws.com/manifest.json?X-Amz-Signature=SECRET-AMZ-SIG" +out="$(redact_line "$url")" +check "X-Amz-Signature's value is gone" gone "$out" "SECRET-AMZ-SIG" +check " the marker and the rest survive" present "$out" "X-Amz-Signature=REDACTED" +check " the host and path survive" present "$out" "bucket.s3.amazonaws.com/manifest.json" + +url="https://cdn.example/camo.png?Signature=SECRET-PLAIN-SIG" +out="$(redact_line "$url")" +check "Signature's value is gone" gone "$out" "SECRET-PLAIN-SIG" +check " the marker survives" present "$out" "Signature=REDACTED" + +url="https://cdn.example/camo.png?sig=SECRET-SIG-SHORT" +out="$(redact_line "$url")" +check "sig's value is gone" gone "$out" "SECRET-SIG-SHORT" +check " the marker survives" present "$out" "sig=REDACTED" + +url="https://cdn.example/camo.png?token=SECRET-BEARER-TOKEN" +out="$(redact_line "$url")" +check "token's value is gone" gone "$out" "SECRET-BEARER-TOKEN" +check " the marker survives" present "$out" "token=REDACTED" + +# --- case-insensitivity ------------------------------------------------------- + +url="https://cdn.example/camo.png?x-amz-signature=SECRET-LOWER-CASE" +out="$(redact_line "$url")" +check "a lowercase spelling is still caught" gone "$out" "SECRET-LOWER-CASE" + +url="https://cdn.example/camo.png?SIG=SECRET-UPPER-CASE" +out="$(redact_line "$url")" +check "an uppercase spelling is still caught" gone "$out" "SECRET-UPPER-CASE" + +# --- more than one credential in the same URL -------------------------------- +# A presigned URL commonly carries several of the spellings above at once. +# redact()'s prefix used to be unbounded and greedy, so a POSIX leftmost- +# longest match spanned every "¶m=value" up to the last recognised one - +# every earlier credential value came through untouched, wrapped inside the +# part of the match that was kept rather than the part that got REDACTED. +url="https://bucket.s3.amazonaws.com/manifest.json?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Signature=SECRET-FIRST&other=value&sig=SECRET-SECOND" +out="$(redact_line "$url")" +check "the first credential in a multi-credential URL is gone" gone "$out" "SECRET-FIRST" +check " and so is the second" gone "$out" "SECRET-SECOND" +check " and a plain, non-credential param survives untouched" present "$out" "other=value" + +# --- the Authorization header ------------------------------------------------- + +out="$(redact_line "Authorization: Bearer SECRET-BEARER-HEADER")" +check "an Authorization header's value is gone" gone "$out" "SECRET-BEARER-HEADER" +check " the field name survives" present "$out" "Authorization: REDACTED" + +out="$(redact_line "authorization: Bearer SECRET-LOWER-HEADER")" +check "a lowercase 'authorization:' is still caught" gone "$out" "SECRET-LOWER-HEADER" + +# --- nothing to redact --------------------------------------------------------- + +url="https://cdn.example/camo.png?faction=TraineeA&slot=A" +out="$(redact_line "$url")" +check "a URL with no credential comes through unchanged" test "$out" = "$url" + +echo +[ "$fail" -eq 0 ] && echo "all redact() cases passed" || echo "some redact() cases FAILED" +exit "$fail" -- 2.51.2