From 431dd181695d51ece016fce519a9370bfc4909ea Mon Sep 17 00:00:00 2001 From: safishamsi Date: Fri, 17 Jul 2026 11:28:52 +0100 Subject: [PATCH] fix(detect): keep .tfvars out of the graph under the sensitive-dir carve-out (follow-up to #1955) The #1943 carve-out rescues genuine source under secrets/ / credentials/, but .tfvars sits in CODE_EXTENSIONS while being Terraform's canonical values store (routinely real secrets), so it would now be indexed. Add .tfvars to _SECRET_PRONE_DATA_EXTS so the shared graphable-source predicate drops it in both Stage 1 and Stage 3; .tf/.hcl stay graphable as genuine infra source. Co-Authored-By: Claude Opus 4.8 (1M context) --- graphify/detect.py | 4 ++++ tests/test_detect.py | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/graphify/detect.py b/graphify/detect.py index 3a49e93f2..5a686d7e1 100644 --- a/graphify/detect.py +++ b/graphify/detect.py @@ -144,6 +144,10 @@ _GENERIC_KEYWORD_PATTERNS = [ _SECRET_PRONE_DATA_EXTS = frozenset({ ".json", ".yaml", ".yml", ".toml", ".ini", ".cfg", ".conf", ".config", ".xml", ".properties", ".env", ".txt", + # .tfvars is Terraform's canonical VALUES store (routinely holds real + # secrets), not source — keep it out of the graph even though it sits in + # CODE_EXTENSIONS. .tf/.hcl are genuine infra source and stay graphable. + ".tfvars", }) # Word separators for the load-bearing check (underscore intentionally included; diff --git a/tests/test_detect.py b/tests/test_detect.py index 640d921ac..142b7c298 100644 --- a/tests/test_detect.py +++ b/tests/test_detect.py @@ -1108,6 +1108,16 @@ def test_sensitive_dir_carveout_does_not_bypass_name_screens(): assert _is_sensitive(Path("credentials/id_rsa")) # extensionless key +def test_sensitive_dir_carveout_still_drops_tfvars_values_store(): + # #1943 follow-up: genuine source under secrets/ is rescued, but .tfvars is + # Terraform's canonical values store (real secrets), not source — it stays + # dropped, while the real code file beside it is kept. + assert _is_sensitive(Path("secrets/prod.tfvars")) + assert not _is_sensitive(Path("secrets/loader.py")) + # .tf / .hcl are genuine infra source and remain graphable under secrets/. + assert not _is_sensitive(Path("secrets/main.tf")) + + # ── Generic keywords must be load-bearing: topic slugs are not secret stores ── # A keyword buried mid-phrase in a >=3-word descriptive name is a note ABOUT # the topic, not a credential file. It must not be silently dropped.