Skip to content

fix(redact): mask secrets nested in added, removed or retyped values - #6

Open
vishalhabib99 wants to merge 1 commit into
esperanza-volkov:mainfrom
vishalhabib99:fix/redact-nested-values
Open

vishalhabib99 wants to merge 1 commit into
esperanza-volkov:mainfrom
vishalhabib99:fix/redact-nested-values

Conversation

@vishalhabib99

Copy link
Copy Markdown

What this changes

redact (CLI --redact, the Action's redact: true, MCP redact: true) prints secrets in plain text when they sit inside an object or array that was added, removed or changed type. Only a secret whose own key is the changed path was masked.

Repro on main (6920fcc):

$ echo '{"app":1}' > a.json
$ echo '{"app":1,"db":{"password":"hunter2","user":"x"}}' > b.json
$ confdiff --redact a.json b.json
+ db  = {"password":"hunter2","user":"x"}

--redact --json gives "newValue": {"password": "hunter2", ...} with no "redacted": true, and MCP diff_configs returns the same in its text and structuredContent. The same happens for a removed subtree (- db = {"token":"abc"}), a container type change (~ db (type) "x" => {"password":...}), and new array elements (indexed, --array-set, --array-key, and {name: DB_PASSWORD, value: ...} entries without --array-key name).

Cause

makeRedactMatcher (src/redact.ts:151-163) looks only at the last segment of the change's path (db, env[1]), and looksHighEntropy only accepts strings. When a whole subtree changes, diff.ts emits one change at the parent path (e.g. :275,277, :304-305, :320,322, :416,418, :439,442), and render.ts (show at :33-34, renderJson at :103-105) then prints the full value unmasked.

Fix

  • src/redact.ts: new redactNested(value, path, redact) walks arrays and plain objects, calls the same matcher on each nested path (so built-in key names, --redact-key globs and --redact-entropy all apply at any depth), applies the name/value-pair rule to object elements, and returns a masked copy. Dates and other non-plain objects are left alone.
  • src/render.ts: renderText and renderJson use it when the change is not already masked as a whole. renderJson sets "redacted": true when anything inside was masked.
  • CLI, directory mode, MCP and Action all render through these two functions, so they're all covered. action/confdiff.cjs and docs/playground.js are rebuilt with npm run build:action / npm run build:web (both rebuild byte-identical on main before this change, so their diff is only this fix). I did not rebuild packages/confdiff-mcp/bin/confdiff-mcp.cjs or bump versions; I left that for your release.
  • CHANGELOG entry under Unreleased.

Tests

  • test/render.test.ts: added object (text + JSON), then removed / type change / indexed / set / keyed (nested two levels) / name-value element, a no-over-redaction case, and --redact-key + --redact-entropy inside an added object.
  • test/mcp.test.ts: diff_configs with redact: true on an added db object, checking text and structuredContent.
  • Before the fix, 4 of the 5 new tests fail (the no-over-redaction test passes both ways). After it, npm test passes 128/128. npm run build is clean.
  • Checked by hand: dist/cli.js --redact, --redact --json and action/confdiff.cjs --redact on the repro now print + db = {"password":"«redacted:28c19f»","user":"x"}.

This branch has not been deployed

No deployments
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.

1 participant