From d193df0403b5ee9e06bbfac334aa97a2881a275b Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Fri, 21 Aug 2026 19:20:31 +0100 Subject: [PATCH] fix(hooks): exported vars judged only by inherited value Raw assignment can hide a short resolved secret or read as a reference when the exported value is the real literal. Co-Authored-By: Claude Fable 5 --- hooks/secret-guard.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/hooks/secret-guard.py b/hooks/secret-guard.py index 8404ff4..9936d0a 100755 --- a/hooks/secret-guard.py +++ b/hooks/secret-guard.py @@ -70,23 +70,22 @@ def env_secrets(): val = val[1:-1] if name in ALLOW_NAMES: continue - # The inherited environment resolves $-expansions; the raw literal - # is the fallback for values the shell never exported. A literal - # that is nothing but a $-reference matches the referencing style - # itself, so it is never a candidate. - resolved = os.environ.get(name) or val - candidates = {os.environ.get(name, ""), val} - { - v for v in (val,) - if re.fullmatch(r"\$\{?[A-Za-z_][A-Za-z0-9_]*\}?", v) - } - guarded = False - for v in candidates: - if (len(v) < MIN_LEN or v in ALLOWLIST or plain_url(v) - or v.startswith(("/", "~"))): - continue - out.setdefault(name, []).append(v) - guarded = True - if not guarded and 0 < len(resolved) < MIN_LEN: + # An exported variable is judged only by its inherited value — the + # raw assignment may expand to something else entirely. The raw + # literal counts only for never-exported lines, and one that is + # nothing but a $-reference matches the referencing style itself, + # so it is skipped. + if name in os.environ: + resolved = os.environ[name] + elif re.fullmatch(r"\$\{?[A-Za-z_][A-Za-z0-9_]*\}?", val): + continue + else: + resolved = val + if (len(resolved) >= MIN_LEN and resolved not in ALLOWLIST + and not plain_url(resolved) + and not resolved.startswith(("/", "~"))): + out.setdefault(name, []).append(resolved) + elif 0 < len(resolved) < MIN_LEN: unguardable.append(name) return out, unguardable