Skip to content

fix(terraform): redact secret-named variable defaults and output values - #3817

Closed
breken-ai wants to merge 1 commit into
Graphify-Labs:v8from
breken-ai:fix/terraform-sensitive-variable-default
Closed

breken-ai wants to merge 1 commit into
Graphify-Labs:v8from
breken-ai:fix/terraform-sensitive-variable-default

Conversation

@breken-ai

Copy link
Copy Markdown
Contributor

What does this PR do?

Terraform secret redaction (#3644, #3762) keys off the attribute name, so it misses a secret named by the block label. variable and output blocks keep the secret's name in their label and the literal under a generic key (default for a variable, value for an output). This input:

variable "db_password" {
  type    = string
  default = "hunter2"
}
output "admin_token" {
  value = "tok-123"
}

wrote "default": "hunter2" and "value": "tok-123" into graph.json, and the MCP query/get_node surface returned them unredacted. A password = ... attribute in the same file was already redacted.

The fix is in graphify/extractors/terraform.py, where attributes are attached to their owner block. For a variable or output block, it redacts default/value in two cases: the block label matches the existing _SENSITIVE_KEY_RE, or the block sets Terraform's own sensitive = true. Ordinary variables and outputs such as variable "region" and output "bucket_name" are unchanged. All other keys on the block, such as type, stay visible.

This PR does not overlap #3787, which covers the { name = "DB_PASSWORD", value = ... } pair idiom. This PR covers the block-label and sensitive = true cases.

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Tests or CI
  • Refactor
  • Security fix

How was this tested?

# New regression: tests/test_terraform.py::test_terraform_secret_named_variable_default_and_output_value_are_redacted
# On v8 @ 4c735618 (before the fix):
uv run --frozen pytest tests/test_terraform.py -q -k variable_default
  AssertionError: assert 'hunter2-default' == '[redacted]'      -> 1 failed
# With the fix:
uv run --frozen pytest tests/test_terraform.py tests/test_terraform_modules.py -q   -> 40 passed

# End to end (AST only), same main.tf as above:
uv run --frozen graphify update <dir> && grep -c hunter2 <dir>/graphify-out/graph.json
  v8:   1 match for hunter2, 1 match for tok-123
  fix:  0 matches for either

uv run --frozen pytest tests/ -q --tb=short      -> 5965 passed, 14 skipped
uv run --frozen ruff check graphify/extractors/terraform.py tests/test_terraform.py -> All checks passed

Tested on macOS with Python 3.12 (uv).

Graphify-specific checklist

  • I added or updated tests for behavior changes.
  • I updated documentation or confirmed that no documentation is needed.
  • I updated generated skill artifacts when changing their source fragments. (No skill fragments changed.)
  • I considered compatibility across supported Python versions. (Plain dict/str operations only.)
  • I confirmed that no API keys, generated graph data, or local-only files are included.

This change was prepared with AI assistance (Claude) and verified with the commands above.

🤖 Generated with Claude Code

A variable or output names its secret in the block label, so the literal
sits under the generic key default/value and the key-name check never
flags it: variable "db_password" { default = "..." } reached graph.json
verbatim. Redact default/value when the label matches the sensitive-key
pattern or the block sets Terraform's own sensitive = true.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

Redacts the default/value literal of variable and output blocks in extract_terraform when the block label matches the sensitive-name pattern or the block sets sensitive = true, closing the gap where key-name matching missed secrets stored under generic keys. Leaves ordinary variables/outputs and non-secret attributes like type untouched.

Worth a look

  • Label-less variable/output blocks now raise IndexError during extraction — graphify/extractors/terraform.py:438 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1448 functions depend on the 52 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract() — 703 callers, 47 callees
  • new: _rebuild_code() — 144 callers, 55 callees
  • new: main() — 98 callers, 3 callees
  • new: dispatch_command() — 2 callers, 125 callees
  • new: extract_terraform() — 22 callers, 8 callees
  • new: run_pipeline() — 8 callers, 13 callees
  • new: watch() — 5 callers, 7 callees
  • new: _build() — 7 callers, 3 callees
  • …and 10 more — each is listed as a finding

Verification — 1448 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 785 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

2 of 300 test file(s) selected (1%) via static blast radius.

  • tests/test_terraform.py — impact, changed-test
  • tests/test_terraform_modules.py — impact

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

· 18 more finding(s) on lines outside this diff (see the check run).

@breken-ai

Copy link
Copy Markdown
Contributor Author

Re the Graphify review finding "Label-less variable/output blocks now raise IndexError during extraction" (graphify/extractors/terraform.py:438): I checked this and it cannot happen.

The redaction runs after the block-type dispatch. variable and output only reach it through elif btype == "variable" and labels: and elif btype == "output" and labels:. A block with no label falls through to the final else: continue, so labels[0] is never read for it.

Repro on 01e4171 with the terraform extra installed: a file with a label-less variable { default = "hunter2" sensitive = true }, a label-less output { value = "x" }, and variable "db_password" { default = "s3cret" }. extract_terraform returns without error, emits no node for the two label-less blocks, and emits var.db_password with {'default': '[redacted]'}. No code change needed.

safishamsi added a commit that referenced this pull request Sep 25, 2026
Windows hash-seed re-exec wait (#3816/#3799), Terraform secret-named
variable-default/output redaction (#3817), COBOL fixed-format
sequence-number detection (#3813) and PERFORM...THRU both-endpoint
linking (#3814), and gate the GRAPH_REPORT undocumented-components
reason on a real semantic layer (#3828/#3801).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@safishamsi

Copy link
Copy Markdown
Collaborator

Shipped in v0.9.68 (now on PyPI) via an authorship-preserving cherry-pick, so your commit keeps contributor-graph credit. Thanks @breken-ai! Terraform secret-named variable-default/output redaction.

Release: https://github.com/Graphify-Labs/graphify/releases/tag/v0.9.68

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants