Skip to content

chore(hooks): sync .claude/hooks fleet — mts conversion + new guards#1300

Merged
John-David Dalton (jdalton) merged 2 commits intomainfrom
chore/split-hooks-config
May 5, 2026
Merged

chore(hooks): sync .claude/hooks fleet — mts conversion + new guards#1300
John-David Dalton (jdalton) merged 2 commits intomainfrom
chore/split-hooks-config

Conversation

@jdalton
Copy link
Copy Markdown
Collaborator

@jdalton John-David Dalton (jdalton) commented May 5, 2026

Summary

  • Replaces .sh husky / git-hooks scaffolding with TypeScript .mts
    implementations (single-language toolchain).
  • Adds the new fleet-canonical guard hooks: auth-rotation-reminder,
    logger-guard, path-guard, private-name-guard, release-workflow-guard,
    setup-security-tools, stale-process-sweeper, token-guard.
  • Updates existing hooks: check-new-deps, public-surface-reminder.
  • Re-registers hooks under PreToolUse / Stop in .claude/settings.json.
  • Enables oxfmt JSDoc formatting in .oxfmtrc.json.

Scope

This is the hooks + harness-config slice split out of #1286. Companion
splits in flight:

  • (this PR) hooks + harness-config.claude/hooks/, .git-hooks/,
    .husky/, .claude/settings.json, .oxfmtrc.json
  • skills + CLAUDE.md (separate PR, TBD) — CLAUDE.md, docs/references/,
    .claude/skills/*, .socket-repo-template.json,
    scripts/socket-repo-template-*
  • deps + drift (folds into chore(ci): cascade socket-registry pin to 85a2fc0d #1285 SHA cascade per scope direction) —
    package.json, pnpm-lock.yaml, pnpm-workspace.yaml, packages/* drift,
    scripts/check.mts, scripts/power-state.mts

After all three splits land, #1286 closes.

Test plan

  • Pre-commit hook: token-guard blocks raw secrets in commit messages
  • PreToolUse: release-workflow-guard blocks gh workflow run (post-fix)
  • Stop hook: stale-process-sweeper reaps orphaned vitest workers
  • CI: hook subdirectories (tsconfig.json per hook) typecheck cleanly

Note

High Risk
High risk because it introduces multiple blocking PreToolUse/git hook enforcement paths (including token/path/workflow dispatch guards) and adds an automated Stop hook that logs users out of CLIs, which can disrupt developer workflows if misconfigured or overly broad.

Overview
Adds new Claude Code hooks that block or warn on risky actions: token-guard (replacing token-hygiene) to prevent secret-leaking Bash shapes, path-guard to prevent inline multi-stage build-path construction, logger-guard to block direct console.*/stream writes in source, release-workflow-guard to block GitHub Actions workflow dispatch commands, and private-name-guard to remind on public-surface commands.

Introduces new Stop hooks: auth-rotation-reminder to periodically revoke CLI logins with snooze/skip-list/throttling, and stale-process-sweeper to kill orphaned test/build worker processes. Registers these under PreToolUse/Stop in .claude/settings.json and updates check-new-deps (improved Cargo.toml extraction and safer module entrypoint ordering).

Migrates Husky/git hooks from shell to .mts (commit-msg, pre-commit, pre-push) with a shared _helpers.mts, expanding scanners (AI attribution stripping, secret/personal-path detection, npx/dlx and logger-leak checks, submodule pristine check) and updates setup-security-tools to install AgentShield via the dlx cache with a schema switch to TypeBox. Also enables JSDoc formatting options in .oxfmtrc.json.

Reviewed by Cursor Bugbot for commit f5e6d06. Configure here.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Commit-msg hook drops Linear issue reference blocking
    • Added scanLinearReferences() to _helpers.mts with the same team-key regex and linear.app URL detection from the old bash script, and invoked it from commit-msg.mts to block commits containing Linear issue references.

Create PR

Or push these changes by commenting:

@cursor push 73335fc0fb
Preview (73335fc0fb)
diff --git a/.git-hooks/_helpers.mts b/.git-hooks/_helpers.mts
--- a/.git-hooks/_helpers.mts
+++ b/.git-hooks/_helpers.mts
@@ -382,6 +382,41 @@
   return hits
 }
 
+// ── Linear issue reference scanner ──────────────────────────────────
+//
+// Linear tracking lives in Linear; keep commit history tool-agnostic.
+// Team keys enumerated from the Socket workspace. PATCH listed before
+// PAT so the engine matches the longer prefix first.
+
+const LINEAR_TEAM_KEYS =
+  'ASK|AUTO|BOT|CE|CORE|DAT|DES|DEV|ENG|INFRA|LAB|MAR|MET|OPS|PAR|PATCH|PAT|PLAT|REA|SALES|SBOM|SEC|SMO|SUP|TES|TI|WEB'
+
+const LINEAR_ISSUE_RE = new RegExp(
+  `(?:^|[^A-Za-z0-9_])((?:${LINEAR_TEAM_KEYS})-[0-9]+)(?:$|[^A-Za-z0-9_])`,
+)
+const LINEAR_URL_RE = /linear\.app\/[A-Za-z0-9/_-]+/
+
+// Scans commit-message text for Linear issue references (team-key
+// patterns like SMO-590 and linear.app URLs). Ignores git comment
+// lines (lines starting with `#`).
+export const scanLinearReferences = (text: string): string[] => {
+  const hits: string[] = []
+  for (const line of text.split('\n')) {
+    if (line.startsWith('#')) {
+      continue
+    }
+    const issueMatch = line.match(LINEAR_ISSUE_RE)
+    if (issueMatch) {
+      hits.push(issueMatch[1]!)
+    }
+    const urlMatch = line.match(LINEAR_URL_RE)
+    if (urlMatch) {
+      hits.push(urlMatch[0])
+    }
+  }
+  return hits.slice(0, 5)
+}
+
 // ── AI attribution scanner ─────────────────────────────────────────
 
 const AI_ATTRIBUTION_RE =

diff --git a/.git-hooks/commit-msg.mts b/.git-hooks/commit-msg.mts
--- a/.git-hooks/commit-msg.mts
+++ b/.git-hooks/commit-msg.mts
@@ -1,11 +1,13 @@
 #!/usr/bin/env node
 // Socket Security Commit-msg Hook
 //
-// Two responsibilities:
+// Three responsibilities:
 //   1. Block commits that introduce API keys / .env files (security
 //      layer that runs even when pre-commit is bypassed via
 //      `--no-verify`).
-//   2. Auto-strip AI attribution lines from the commit message before
+//   2. Block commits whose message references Linear issues (keep
+//      commit history tool-agnostic).
+//   3. Auto-strip AI attribution lines from the commit message before
 //      git records the commit.
 //
 // Wired via .husky/commit-msg, which invokes this with the path to the
@@ -23,6 +25,7 @@
   out,
   red,
   readFileForScan,
+  scanLinearReferences,
   scanSocketApiKeys,
   shouldSkipFile,
   stripAiAttribution,
@@ -67,9 +70,27 @@
     }
   }
 
-  // Auto-strip AI attribution lines from the commit message.
+  // Block Linear issue references in the commit message.
   const commitMsgFile = process.argv[2]
   if (commitMsgFile && existsSync(commitMsgFile)) {
+    const msgText = readFileSync(commitMsgFile, 'utf8')
+    const linearHits = scanLinearReferences(msgText)
+    if (linearHits.length > 0) {
+      out(red('✗ Commit message references Linear issue(s):'))
+      for (const hit of linearHits) {
+        out(`  ${hit}`)
+      }
+      out(
+        red(
+          'Linear tracking lives in Linear. Remove the reference from the commit message.',
+        ),
+      )
+      errors++
+    }
+  }
+
+  // Auto-strip AI attribution lines from the commit message.
+  if (commitMsgFile && existsSync(commitMsgFile)) {
     const original = readFileSync(commitMsgFile, 'utf8')
     const { cleaned, removed } = stripAiAttribution(original)
     if (removed > 0) {

You can send follow-ups to the cloud agent here.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit f5e6d06. Configure here.

Comment thread .git-hooks/commit-msg.mts
Comment thread .claude/hooks/auth-rotation-reminder/index.mts Outdated
Comment thread .git-hooks/_helpers.mts Outdated
Comment thread .claude/hooks/auth-rotation-reminder/test/auth-rotation-reminder.test.mts Outdated
John-David Dalton (jdalton) added a commit that referenced this pull request May 5, 2026
Four findings, all from socket-repo-template canonical (synced):

1. commit-msg lost Linear-ref blocking in the .sh→.mts conversion.
   The old shell hook scanned for team-key+digits patterns + linear.app
   URLs and refused commits. Restored as scanLinearRefs() in
   _helpers.mts, called from commit-msg.mts. Comment lines starting
   with `#` are skipped (git hint text + diff snippets).

2. auth-rotation-reminder/index.mts used (e as Error).message in three
   catch blocks. Switched to errorMessage(e) from
   @socketsecurity/lib/errors per repo convention.

3. _helpers.mts scanSocketApiKeys mapped filtered lines back to LineHit
   via .find() on h.line === line, which returns the wrong lineNumber
   when two hits have identical content. Filter LineHit[] directly via
   the new isAllowedApiKey() helper instead.

4. auth-rotation-reminder/test used rmSync from node:fs for cleanup.
   Switched to safeDelete from @socketsecurity/lib/fs (async, since
   tests are already async). Added a CLAUDE.md rule documenting the
   async-over-sync preference for safeDelete.
John-David Dalton (jdalton) added a commit that referenced this pull request May 5, 2026
Four findings, all from socket-repo-template canonical (synced):

1. commit-msg lost Linear-ref blocking in the .sh→.mts conversion.
   The old shell hook scanned for team-key+digits patterns + linear.app
   URLs and refused commits. Restored as scanLinearRefs() in
   _helpers.mts, called from commit-msg.mts. Comment lines starting
   with `#` are skipped (git hint text + diff snippets).

2. auth-rotation-reminder/index.mts used (e as Error).message in three
   catch blocks. Switched to errorMessage(e) from
   @socketsecurity/lib/errors per repo convention.

3. _helpers.mts scanSocketApiKeys mapped filtered lines back to LineHit
   via .find() on h.line === line, which returns the wrong lineNumber
   when two hits have identical content. Filter LineHit[] directly via
   the new isAllowedApiKey() helper instead.

4. auth-rotation-reminder/test used rmSync from node:fs for cleanup.
   Switched to safeDelete from @socketsecurity/lib/fs (async, since
   tests are already async). Added a CLAUDE.md rule documenting the
   async-over-sync preference for safeDelete.
John-David Dalton (jdalton) added a commit that referenced this pull request May 5, 2026
Synced from socket-repo-template canonical. The fleet CLAUDE.md
moved to a fleet-canonical / project-specific layout — public-surface
hygiene rules, parallel-session safeguards, code style, and tooling
go in CLAUDE.md; project-specific extensions (build commands, test
targets, repo-particular conventions) go below.

Skills added:
- path-guard — audit and fix path duplication ("1 path, 1 reference")
- programmatic-claude-lockdown — reference for locking down headless
  Claude invocations (claude CLI in workflows, agent-sdk query() in
  code) per the four-flag lockdown pattern
- promise-race-pitfall — reference for the Promise.race
  cross-iteration handler-leak bug

Skills updated:
- security-scan — wires AgentShield + zizmor + Socket CLI dependency
  scanning, A-F graded report

Path-guard infra:
- scripts/check-paths.mts — repo-level path-duplication scanner
- .github/paths-allowlist.yml — known-acceptable duplicates
- .claude/skills/path-guard/reference/* — templates for new repos

Doctrine references:
- docs/references/inclusive-language.md — substitution table
- docs/references/sorting.md — alphanumeric sort rules

Repo-template integration:
- .socket-repo-template.json — repo-particular kind config
- scripts/socket-repo-template-{schema,emit-schema}.mts — schema tooling
- socket-repo-template-schema.json — emitted JSON schema

Splits content out of #1286. Companion split PR #1300 covers hooks +
harness config; deps_misc bucket folds into #1285 SHA cascade per
project direction.
Synced from socket-repo-template canonical hooks fleet. Replaces
socket-cli's .sh husky/git-hooks scaffolding with TypeScript .mts
implementations (single-language toolchain, easier to test and
maintain), and adds the new fleet-canonical guard hooks.

Hooks added:
- auth-rotation-reminder — prompts on token rotation events
- logger-guard — blocks console.log/error in production code
- path-guard — enforces "1 path, 1 reference" in edits
- private-name-guard — blocks public-facing internal-only names
- release-workflow-guard — blocks dispatching publish/release flows
- setup-security-tools — bootstraps sfw + zizmor + AgentShield pins
- stale-process-sweeper — Stop hook reaping orphaned vitest workers
- token-guard — blocks raw secret exposure in tool output

Hooks updated:
- check-new-deps — soak-window wording + .mjs→.mts script refs
- public-surface-reminder — package.json sync

Conversion:
- .git-hooks/{commit-msg,pre-push,_helpers}.sh → .mts (3 deletions)
- .husky/{commit-msg,pre-commit,pre-push} — call .mts entries
- .oxfmtrc.json — enable JSDoc formatting (oxfmt 0.x feature)
- .claude/settings.json — register new hooks under PreToolUse/Stop

Splits content out of #1286. Identical file content; this PR is the
hooks/config slice with no skill or CLAUDE.md changes.
Four findings, all from socket-repo-template canonical (synced):

1. commit-msg lost Linear-ref blocking in the .sh→.mts conversion.
   The old shell hook scanned for team-key+digits patterns + linear.app
   URLs and refused commits. Restored as scanLinearRefs() in
   _helpers.mts, called from commit-msg.mts. Comment lines starting
   with `#` are skipped (git hint text + diff snippets).

2. auth-rotation-reminder/index.mts used (e as Error).message in three
   catch blocks. Switched to errorMessage(e) from
   @socketsecurity/lib/errors per repo convention.

3. _helpers.mts scanSocketApiKeys mapped filtered lines back to LineHit
   via .find() on h.line === line, which returns the wrong lineNumber
   when two hits have identical content. Filter LineHit[] directly via
   the new isAllowedApiKey() helper instead.

4. auth-rotation-reminder/test used rmSync from node:fs for cleanup.
   Switched to safeDelete from @socketsecurity/lib/fs (async, since
   tests are already async). Added a CLAUDE.md rule documenting the
   async-over-sync preference for safeDelete.
John-David Dalton (jdalton) added a commit that referenced this pull request May 5, 2026
…1301)

* docs(claude+skills): CLAUDE.md restructure + path-guard + new skills

Synced from socket-repo-template canonical. The fleet CLAUDE.md
moved to a fleet-canonical / project-specific layout — public-surface
hygiene rules, parallel-session safeguards, code style, and tooling
go in CLAUDE.md; project-specific extensions (build commands, test
targets, repo-particular conventions) go below.

Skills added:
- path-guard — audit and fix path duplication ("1 path, 1 reference")
- programmatic-claude-lockdown — reference for locking down headless
  Claude invocations (claude CLI in workflows, agent-sdk query() in
  code) per the four-flag lockdown pattern
- promise-race-pitfall — reference for the Promise.race
  cross-iteration handler-leak bug

Skills updated:
- security-scan — wires AgentShield + zizmor + Socket CLI dependency
  scanning, A-F graded report

Path-guard infra:
- scripts/check-paths.mts — repo-level path-duplication scanner
- .github/paths-allowlist.yml — known-acceptable duplicates
- .claude/skills/path-guard/reference/* — templates for new repos

Doctrine references:
- docs/references/inclusive-language.md — substitution table
- docs/references/sorting.md — alphanumeric sort rules

Repo-template integration:
- .socket-repo-template.json — repo-particular kind config
- scripts/socket-repo-template-{schema,emit-schema}.mts — schema tooling
- socket-repo-template-schema.json — emitted JSON schema

Splits content out of #1286. Companion split PR #1300 covers hooks +
harness config; deps_misc bucket folds into #1285 SHA cascade per
project direction.

* fix(check-paths): Rule F requires >=2 distinct files, not just >=2 hits

Cursor Bugbot caught: `checkRuleF` grouped Rule-A findings purely by
string-literal shape and promoted to Rule F whenever count >= 2,
without checking distinct files. Two hand-builds of the same path
shape in the SAME file would be incorrectly flagged as 'cross-file
repetition' — but Rule F's whole point is cross-file duplication.

Fix: build a Set of distinct file paths and gate the promotion on
size >= 2. Also include the file count in the message
(`in N files (M places)`) so the reviewer knows both numbers.
Synced to socket-repo-template canonical.
@jdalton John-David Dalton (jdalton) merged commit d5a6f46 into main May 5, 2026
4 checks passed
@jdalton John-David Dalton (jdalton) deleted the chore/split-hooks-config branch May 5, 2026 23:16
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