Skip to content

chore: P0/P3 credibility and robustness cleanup (6 issues) - #60

Merged
fahadsiddiqui merged 7 commits into
mainfrom
chore/lowest-hanging-cleanup
Jul 23, 2026
Merged

chore: P0/P3 credibility and robustness cleanup (6 issues)#60
fahadsiddiqui merged 7 commits into
mainfrom
chore/lowest-hanging-cleanup

Conversation

@fahadsiddiqui

Copy link
Copy Markdown
Member

Summary

Six small, independent fixes from the product audit's "lowest hanging fruit" bucket - each closes one open issue. Every commit is self-contained and can be reviewed/reverted individually.

Test plan

  • npm run build - clean
  • npm test - 377/377 passing (2 new test files: config unknown-key warnings, disabled-notice behavior)
  • npm run lint - clean
  • Manual smoke tests: normal block/pass-through, unknown-key warning, disabled-notice session dedup (notice → silent on same session → notice again on new session)
  • CI green on all 5 matrix jobs (ubuntu x3, windows, macos)

src/redactor/masker.ts was never imported anywhere in src/ or scripts/
(verified via grep). Redaction is actually handled by
PrivacyScanner.scan()/buildHookResponse() in engine.ts and response.ts.
Dead code in a security-audited repo invites doubt about what's
load-bearing.

Closes #49
.claude-plugin/marketplace.json was stuck at 0.1.2 while
package.json/plugin.json were at 0.2.8 - eight releases of drift,
because scripts/release.sh only ever bumped plugin.json. Also gave
the marketplace listing's description a trailing period to match
normal sentence punctuation.

- Bump marketplace.json to the current version (0.2.8)
- Have release.sh bump marketplace.json's plugin version alongside
  package.json/plugin.json so this can't drift again

Closes #47
… run

Three entries in data/regex_list_1.json survive the coding-only
keyword filter but were rejected by safe-regex2 on every single hook
invocation, printing a warning and wasting load work while
contributing zero detections:

- "Password etc shadow": the /etc/shadow hash branch nested an
  optional group around unbounded .* repetitions (star height 2).
  Rewrote it as a non-optional, delimiter-bounded [^$:]* match - same
  intent (locked-account markers or a $id$salt$hash), no nesting.
- "heroku_key": (?:-\w{4}){3} nested a bounded repetition around
  another repetition. Unrolled it to -\w{4}-\w{4}-\w{4} - identical
  match, no nesting.
- "slack_api_token": (?:-[a-zA-Z0-9]+){4,} nests two unbounded
  repetitions, a genuine catastrophic-backtracking shape. Removed
  outright rather than reworked - it's a strict subset of the
  existing built-in 'slack-token' detector, which already covers
  xoxb/xoxp/xoxa/xoxr/xapp with better false-positive guards.

Closes #48
ConfigLoader only ever validated the "mode" field. Any other typo'd
key (e.g. "alowedValues" instead of "allowedValues") was silently
merged over the defaults and just as silently ignored - for a
security tool, a config typo that silently weakens protection with no
feedback is a real footgun.

ConfigLoader now checks every top-level key against the known
PrivacyGuardConfig fields and prints a console.warn naming the
offending key. Unknown keys are still merged through unchanged (not
stripped), preserving the config-UI's "unknown keys survive a save"
behavior.

Closes #50
Setting "enabled": false in .privacy-guard.json silently let every
prompt through unscanned with no in-session signal - a stale config
line left over from debugging meant a user could be completely
unprotected without any indication.

The hook now emits a systemMessage the first time it sees a given
session_id with the guard disabled, then stays quiet for the rest of
that session (tracked via a small marker file in the existing cache
dir, keyed on session_id) so it isn't repeated on every prompt.
Falls back to notifying every time only when no session_id is
available (e.g. the script invoked manually without the JSON
envelope), since there's nothing to dedupe against.

Closes #51
Windows support is hand-coded (path handling, %LOCALAPPDATA% config
resolution, no bash wrapper by design) and macOS is the primary dev
platform for Claude Code users, but CI only ever ran ubuntu-latest.
Untested platform claims rot silently.

- Keep the full Node 18/20/22 matrix on ubuntu-latest, add one
  windows-latest and one macos-latest job on Node 20 via `include`
  (fail-fast: false so one platform's failure doesn't hide another's)
- Force LF line endings repo-wide via .gitattributes (`* text=auto
  eol=lf`) - without this, Windows checkouts convert committed LF to
  CRLF via core.autocrlf, which would make the "dist/ matches src/"
  verification step fail spuriously on windows-latest even when
  nothing actually changed

Closes #52
@fahadsiddiqui fahadsiddiqui self-assigned this Jul 23, 2026
Two bugs surfaced by the new windows-latest job (#52):

1. The "Verify committed dist/ matches src/" step uses bash `if !
   cmd; then` syntax, but Windows runners default `run:` steps to
   PowerShell - which fails to parse it outright
   (ParserError: Missing '(' after 'if' in if statement), unrelated
   to whether dist/ actually matched. Set `defaults.run.shell: bash`
   on the job so every step runs under bash on all three platforms.

2. Once that parses, the check would still have failed spuriously on
   Windows: tsc's `newLine` option defaults to the platform's native
   line ending, so a Windows build emits CRLF while the committed
   dist/ (LF) would not match even with nothing actually changed. Set
   `"newLine": "lf"` in tsconfig.json so tsc always emits LF
   regardless of OS, independent of the .gitattributes normalization
   added in the prior commit.
@fahadsiddiqui
fahadsiddiqui merged commit e03bbbb into main Jul 23, 2026
5 checks passed
@fahadsiddiqui
fahadsiddiqui deleted the chore/lowest-hanging-cleanup branch July 23, 2026 09:37
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