Skip to content

Commit f504816

Browse files
committed
fix(hooks): address Cursor Bugbot feedback on hooks-mts conversion
Bugbot review on commit 1e30641 surfaced 4 regressions from the .sh→.mts conversion. Fixed all four: 1. **Linear issue reference check restored** (high) — the original commit-msg.sh blocked Socket Linear team-key references (ASK-123, ENG-456, linear.app URLs). Re-added scanLinearReferences to _helpers.mts and wired into commit-msg.mts. 2. **scanSocketApiKeys duplicate-line bug** (low) — the post-filter reconstructed LineHits via `hits.find(h => h.line === line)`, which collapses duplicates onto the first match's line number. Replaced with Set-membership filter that preserves all hits. 3. **SOCKET_CLI_NO_API_TOKEN restored in .husky/pre-commit** (medium) — original husky shim ran `SOCKET_CLI_NO_API_TOKEN=1 pnpm test --staged` so contributors without a real API token don't see test failures pre-commit. 4. **.env.precommit allowlist** (low) — pre-commit.mts allowlist only had example/test variants; commit-msg.mts had precommit too. Aligned both to allow .env.{example,test,precommit}. Smoke-tested commit-msg.mts: - "ENG-123 in body" → exit 1 (blocked) ✓ - "fix: legit" → exit 0 (clean) ✓
1 parent 9b86a0f commit f504816

4 files changed

Lines changed: 67 additions & 11 deletions

File tree

.git-hooks/_helpers.mts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,10 @@ export const scanSocketApiKeys = (text: string): LineHit[] => {
140140
hits.push({ lineNumber: i + 1, line })
141141
}
142142
}
143-
return filterAllowedApiKeys(hits.map(h => h.line)).map(line => ({
144-
lineNumber: hits.find(h => h.line === line)!.lineNumber,
145-
line,
146-
}))
143+
// Filter the LineHit objects directly so duplicate-content lines
144+
// at different line numbers keep their correct numbers.
145+
const allowedSet = new Set(filterAllowedApiKeys(hits.map(h => h.line)))
146+
return hits.filter(h => allowedSet.has(h.line))
147147
}
148148

149149
export const scanAwsKeys = (text: string): LineHit[] => {
@@ -198,6 +198,34 @@ export const scanNpxDlx = (text: string): LineHit[] => {
198198
return hits
199199
}
200200

201+
// ── Linear issue reference scanner ─────────────────────────────────
202+
// CLAUDE.md "ABSOLUTE RULES": NEVER reference Linear issues in commits.
203+
// Team keys enumerated from the Socket workspace. PATCH listed before
204+
// PAT so the alternation matches the longer prefix first.
205+
206+
const LINEAR_TEAM_KEYS =
207+
'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'
208+
209+
const LINEAR_ISSUE_RE = new RegExp(
210+
`(?:^|[^A-Za-z0-9_])((?:${LINEAR_TEAM_KEYS})-[0-9]+)(?:$|[^A-Za-z0-9_])`,
211+
'gm',
212+
)
213+
214+
const LINEAR_URL_RE = /linear\.app\/[A-Za-z0-9/_-]+/g
215+
216+
export const scanLinearReferences = (commitMsg: string): string[] => {
217+
const hits: string[] = []
218+
const lines = commitMsg.split('\n').filter(l => !l.startsWith('#'))
219+
const body = lines.join('\n')
220+
for (const m of body.matchAll(LINEAR_ISSUE_RE)) {
221+
hits.push(m[1]!)
222+
}
223+
for (const m of body.matchAll(LINEAR_URL_RE)) {
224+
hits.push(m[0]!)
225+
}
226+
return hits.slice(0, 5)
227+
}
228+
201229
// ── AI attribution scanner ─────────────────────────────────────────
202230

203231
const AI_ATTRIBUTION_RE =

.git-hooks/commit-msg.mts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
#!/usr/bin/env node
22
// Socket Security Commit-msg Hook
33
//
4-
// Two responsibilities:
4+
// Three responsibilities:
55
// 1. Block commits that introduce API keys / .env files (security
66
// layer that runs even when pre-commit is bypassed via
77
// `--no-verify`).
8-
// 2. Auto-strip AI attribution lines from the commit message before
8+
// 2. Block commits whose message references Linear issues — Socket
9+
// keeps Linear tracking out of git history per CLAUDE.md.
10+
// 3. Auto-strip AI attribution lines from the commit message before
911
// git records the commit.
1012
//
1113
// Wired via .husky/commit-msg, which invokes this with the path to the
@@ -23,6 +25,7 @@ import {
2325
out,
2426
red,
2527
readFileForScan,
28+
scanLinearReferences,
2629
scanSocketApiKeys,
2730
shouldSkipFile,
2831
stripAiAttribution,
@@ -67,10 +70,28 @@ const main = (): number => {
6770
}
6871
}
6972

70-
// Auto-strip AI attribution lines from the commit message.
7173
const commitMsgFile = process.argv[2]
7274
if (commitMsgFile && existsSync(commitMsgFile)) {
7375
const original = readFileSync(commitMsgFile, 'utf8')
76+
77+
// Block Linear issue references in the commit message. Socket
78+
// keeps Linear tracking out of git history; commit messages stay
79+
// tool-agnostic.
80+
const linearHits = scanLinearReferences(original)
81+
if (linearHits.length > 0) {
82+
out(red('✗ Commit message references Linear issue(s):'))
83+
for (const hit of linearHits) {
84+
out(` ${hit}`)
85+
}
86+
out(
87+
red(
88+
'Linear tracking lives in Linear. Remove the reference from the commit message.',
89+
),
90+
)
91+
errors++
92+
}
93+
94+
// Auto-strip AI attribution lines from the commit message.
7495
const { cleaned, removed } = stripAiAttribution(original)
7596
if (removed > 0) {
7697
writeFileSync(commitMsgFile, cleaned)

.git-hooks/pre-commit.mts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,14 @@ const main = (): number => {
6262
errors++
6363
}
6464

65-
// .env files (allowlist .env.example / .env.test).
65+
// .env files (allowlist .env.example / .env.test / .env.precommit).
66+
// Match commit-msg.mts allowlist — .env.precommit is a tracked file
67+
// some repos use to disable test API tokens during pre-commit runs.
6668
out('Checking for .env files...')
6769
const envFiles = stagedFiles.filter(
68-
f => /^\.env(\.[^/]+)?$/.test(f) && !/^\.env\.(example|test)$/.test(f),
70+
f =>
71+
/^\.env(\.[^/]+)?$/.test(f) &&
72+
!/^\.env\.(example|test|precommit)$/.test(f),
6973
)
7074
if (envFiles.length > 0) {
7175
out(red('✗ ERROR: .env file detected!'))

.husky/pre-commit

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ else
3131
fi
3232

3333
if [ -z "${DISABLE_PRECOMMIT_TEST}" ]; then
34-
# Only run tests if there are staged test files
35-
pnpm test --staged
34+
# Only run tests if there are staged test files. SOCKET_CLI_NO_API_TOKEN=1
35+
# disables the API-token requirement so contributors without a real key
36+
# configured don't see test failures during pre-commit (matches the
37+
# original .env.precommit behavior).
38+
SOCKET_CLI_NO_API_TOKEN=1 pnpm test --staged
3639
else
3740
echo "Skipping testing due to DISABLE_PRECOMMIT_TEST env var"
3841
fi

0 commit comments

Comments
 (0)