Skip to content

Commit ac5746d

Browse files
committed
chore(deps): bump catalog + oxfmt sweep
oxlint 1.63.0, oxfmt 0.48.0, taze 19.11.0, ts-preview 20260510.1. Cascade from socket-wheelhouse bbea704.
1 parent 09108a4 commit ac5746d

914 files changed

Lines changed: 9192 additions & 9875 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/agents/code-reviewer.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Apply the rules from CLAUDE.md sections listed below. Reference the full section
1919
**Test Style**: Functional tests over source scanning. Never read source files and assert on contents. Verify behavior with real function calls.
2020

2121
For each file reviewed, report:
22+
2223
- **Style violations** with file:line
2324
- **Logic issues** (bugs, edge cases, missing error handling)
2425
- **Test gaps** (untested code paths)

.claude/agents/refactor-cleaner.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Apply these rules from CLAUDE.md exactly:
1717
5. **Verify nothing broke**: Run `pnpm run check` and `pnpm test` after each phase
1818

1919
**What to look for:**
20+
2021
- Unused exports (exported but never imported elsewhere)
2122
- Dead imports (imported but never used)
2223
- Unreachable code paths

.claude/hooks/setup-security-tools/update.mts

Lines changed: 101 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import { tmpdir } from 'node:os'
1313
import path from 'node:path'
1414
import { fileURLToPath } from 'node:url'
1515

16-
import { httpDownload, httpRequest } from '@socketsecurity/lib-stable/http-request'
16+
import {
17+
httpDownload,
18+
httpRequest,
19+
} from '@socketsecurity/lib-stable/http-request'
1720
import { getDefaultLogger } from '@socketsecurity/lib-stable/logger'
1821
import { spawn } from '@socketsecurity/lib-stable/spawn'
1922

@@ -38,14 +41,18 @@ function readCooldownMs(): number {
3841
} catch {
3942
// Read error.
4043
}
41-
logger.warn(`Could not read minimumReleaseAge from ${candidate}, defaulting to ${DEFAULT_COOLDOWN_MINUTES} minutes`)
44+
logger.warn(
45+
`Could not read minimumReleaseAge from ${candidate}, defaulting to ${DEFAULT_COOLDOWN_MINUTES} minutes`,
46+
)
4247
return DEFAULT_COOLDOWN_MINUTES * MS_PER_MINUTE
4348
}
4449
const parent = path.dirname(dir)
4550
if (parent === dir) break
4651
dir = parent
4752
}
48-
logger.warn(`pnpm-workspace.yaml not found, defaulting cooldown to ${DEFAULT_COOLDOWN_MINUTES} minutes`)
53+
logger.warn(
54+
`pnpm-workspace.yaml not found, defaulting cooldown to ${DEFAULT_COOLDOWN_MINUTES} minutes`,
55+
)
4956
return DEFAULT_COOLDOWN_MINUTES * MS_PER_MINUTE
5057
}
5158

@@ -71,9 +78,7 @@ async function ghApiLatestRelease(repo: string): Promise<GhRelease> {
7178
{ stdio: 'pipe' },
7279
)
7380
const stdout =
74-
typeof result.stdout === 'string'
75-
? result.stdout
76-
: result.stdout.toString()
81+
typeof result.stdout === 'string' ? result.stdout : result.stdout.toString()
7782
return JSON.parse(stdout) as GhRelease
7883
}
7984

@@ -108,7 +113,11 @@ function readConfig(): Config {
108113
}
109114

110115
async function writeConfig(config: Config): Promise<void> {
111-
await fs.writeFile(CONFIG_FILE, JSON.stringify(config, undefined, 2) + '\n', 'utf8')
116+
await fs.writeFile(
117+
CONFIG_FILE,
118+
JSON.stringify(config, undefined, 2) + '\n',
119+
'utf8',
120+
)
112121
}
113122

114123
// ── Checksum computation ──
@@ -119,7 +128,10 @@ async function computeSha256(filePath: string): Promise<string> {
119128
}
120129

121130
async function downloadAndHash(url: string): Promise<string> {
122-
const tmpFile = path.join(tmpdir(), `security-tools-update-${Date.now()}-${Math.random().toString(36).slice(2)}`)
131+
const tmpFile = path.join(
132+
tmpdir(),
133+
`security-tools-update-${Date.now()}-${Math.random().toString(36).slice(2)}`,
134+
)
123135
try {
124136
await httpDownload(url, tmpFile, { retries: 2 })
125137
return await computeSha256(tmpFile)
@@ -146,7 +158,8 @@ async function updateZizmor(config: Config): Promise<UpdateResult> {
146158
return { tool, skipped: true, updated: false, reason: 'not in config' }
147159
}
148160

149-
const repo = toolConfig.repository?.replace(/^[^:]+:/, '') ?? 'zizmorcore/zizmor'
161+
const repo =
162+
toolConfig.repository?.replace(/^[^:]+:/, '') ?? 'zizmorcore/zizmor'
150163

151164
let release: GhRelease
152165
try {
@@ -169,10 +182,20 @@ async function updateZizmor(config: Config): Promise<UpdateResult> {
169182

170183
// Respect cooldown for third-party tools.
171184
if (!isOlderThanCooldown(release.published_at)) {
172-
const daysOld = ((Date.now() - new Date(release.published_at).getTime()) / 86_400_000).toFixed(1)
185+
const daysOld = (
186+
(Date.now() - new Date(release.published_at).getTime()) /
187+
86_400_000
188+
).toFixed(1)
173189
const cooldownDays = (COOLDOWN_MS / 86_400_000).toFixed(0)
174-
logger.log(`v${latestVersion} is only ${daysOld} days old (need ${cooldownDays}). Skipping.`)
175-
return { tool, skipped: true, updated: false, reason: `too new (${daysOld} days, need ${cooldownDays})` }
190+
logger.log(
191+
`v${latestVersion} is only ${daysOld} days old (need ${cooldownDays}). Skipping.`,
192+
)
193+
return {
194+
tool,
195+
skipped: true,
196+
updated: false,
197+
reason: `too new (${daysOld} days, need ${cooldownDays})`,
198+
}
176199
}
177200

178201
logger.log(`Updating to v${latestVersion}...`)
@@ -199,7 +222,9 @@ async function updateZizmor(config: Config): Promise<UpdateResult> {
199222

200223
// Compute checksums for each asset in the config.
201224
const currentChecksums = toolConfig.checksums ?? {}
202-
const newChecksums: Record<string, string> = { __proto__: null } as unknown as Record<string, string>
225+
const newChecksums: Record<string, string> = {
226+
__proto__: null,
227+
} as unknown as Record<string, string>
203228
let allFound = true
204229

205230
for (const assetName of Object.keys(currentChecksums)) {
@@ -235,23 +260,35 @@ async function updateZizmor(config: Config): Promise<UpdateResult> {
235260
newChecksums[assetName] = newHash
236261
const oldHash = currentChecksums[assetName]
237262
if (oldHash && oldHash !== newHash) {
238-
logger.log(` ${assetName}: ${oldHash.slice(0, 12)}... -> ${newHash.slice(0, 12)}...`)
263+
logger.log(
264+
` ${assetName}: ${oldHash.slice(0, 12)}... -> ${newHash.slice(0, 12)}...`,
265+
)
239266
} else if (oldHash === newHash) {
240267
logger.log(` ${assetName}: unchanged`)
241268
}
242269
}
243270

244271
if (!allFound) {
245272
logger.warn('Some assets could not be verified. Skipping version bump.')
246-
return { tool, skipped: true, updated: false, reason: 'incomplete asset checksums' }
273+
return {
274+
tool,
275+
skipped: true,
276+
updated: false,
277+
reason: 'incomplete asset checksums',
278+
}
247279
}
248280

249281
// Update config.
250282
toolConfig.version = latestVersion
251283
toolConfig.checksums = newChecksums
252284
logger.log(`Updated zizmor: ${currentVersion} -> ${latestVersion}`)
253285

254-
return { tool, skipped: false, updated: true, reason: `${currentVersion} -> ${latestVersion}` }
286+
return {
287+
tool,
288+
skipped: false,
289+
updated: true,
290+
reason: `${currentVersion} -> ${latestVersion}`,
291+
}
255292
}
256293

257294
// ── SFW update ──
@@ -262,12 +299,22 @@ async function updateSfwTool(
262299
): Promise<UpdateResult> {
263300
const toolConfig = config.tools[toolName]
264301
if (!toolConfig) {
265-
return { tool: toolName, skipped: true, updated: false, reason: 'not in config' }
302+
return {
303+
tool: toolName,
304+
skipped: true,
305+
updated: false,
306+
reason: 'not in config',
307+
}
266308
}
267309

268310
const repo = toolConfig.repository?.replace(/^[^:]+:/, '')
269311
if (!repo) {
270-
return { tool: toolName, skipped: true, updated: false, reason: 'no repository' }
312+
return {
313+
tool: toolName,
314+
skipped: true,
315+
updated: false,
316+
reason: 'no repository',
317+
}
271318
}
272319

273320
let release: GhRelease
@@ -276,15 +323,24 @@ async function updateSfwTool(
276323
} catch (e) {
277324
const msg = e instanceof Error ? e.message : String(e)
278325
logger.warn(`Failed to fetch ${toolName} releases: ${msg}`)
279-
return { tool: toolName, skipped: true, updated: false, reason: `API error: ${msg}` }
326+
return {
327+
tool: toolName,
328+
skipped: true,
329+
updated: false,
330+
reason: `API error: ${msg}`,
331+
}
280332
}
281333

282-
logger.log(` ${toolName}: latest ${release.tag_name} (published ${release.published_at.slice(0, 10)})`)
334+
logger.log(
335+
` ${toolName}: latest ${release.tag_name} (published ${release.published_at.slice(0, 10)})`,
336+
)
283337

284338
const currentChecksums = toolConfig.checksums ?? {}
285339
const platforms = toolConfig.platforms ?? {}
286340
const prefix = toolName === 'sfw-enterprise' ? 'sfw' : 'sfw-free'
287-
const newChecksums: Record<string, string> = { __proto__: null } as unknown as Record<string, string>
341+
const newChecksums: Record<string, string> = {
342+
__proto__: null,
343+
} as unknown as Record<string, string>
288344
let changed = false
289345
let allFound = true
290346

@@ -300,7 +356,9 @@ async function updateSfwTool(
300356
const hash = await downloadAndHash(url)
301357
newChecksums[sfwPlatform] = hash
302358
if (currentChecksums[sfwPlatform] !== hash) {
303-
logger.log(` ${sfwPlatform}: ${(currentChecksums[sfwPlatform] ?? '').slice(0, 12)}... -> ${hash.slice(0, 12)}...`)
359+
logger.log(
360+
` ${sfwPlatform}: ${(currentChecksums[sfwPlatform] ?? '').slice(0, 12)}... -> ${hash.slice(0, 12)}...`,
361+
)
304362
changed = true
305363
}
306364
} catch (e) {
@@ -311,17 +369,34 @@ async function updateSfwTool(
311369
}
312370

313371
if (!allFound) {
314-
logger.warn(` Some ${toolName} assets could not be downloaded. Skipping update.`)
315-
return { tool: toolName, skipped: true, updated: false, reason: 'incomplete downloads' }
372+
logger.warn(
373+
` Some ${toolName} assets could not be downloaded. Skipping update.`,
374+
)
375+
return {
376+
tool: toolName,
377+
skipped: true,
378+
updated: false,
379+
reason: 'incomplete downloads',
380+
}
316381
}
317382

318383
if (changed) {
319384
toolConfig.version = release.tag_name
320385
toolConfig.checksums = newChecksums
321-
return { tool: toolName, skipped: false, updated: true, reason: 'checksums updated' }
386+
return {
387+
tool: toolName,
388+
skipped: false,
389+
updated: true,
390+
reason: 'checksums updated',
391+
}
322392
}
323393

324-
return { tool: toolName, skipped: false, updated: false, reason: 'already current' }
394+
return {
395+
tool: toolName,
396+
skipped: false,
397+
updated: false,
398+
reason: 'already current',
399+
}
325400
}
326401

327402
async function updateSfw(config: Config): Promise<UpdateResult[]> {

.claude/hooks/token-hygiene/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ Claude Code `PreToolUse` hook that refuses Bash tool calls that would leak secre
44

55
## What it blocks
66

7-
| Rule | Example | Fix |
8-
|------|---------|-----|
9-
| Literal token in command | `echo vtwn_abc123…` | Rotate the exposed token; read tokens from `.env.local` at spawn time, never inline them |
10-
| `env`/`printenv`/`export -p`/`set` dumping everything | `env \| grep FOO` (unredacted) | `env \| sed 's/=.*/=<redacted>/'` or filter specific keys |
11-
| `.env*` read without redactor | `cat .env.local` | `sed 's/=.*/=<redacted>/' .env.local` or `grep -v '^#' .env.local \| cut -d= -f1` |
12-
| `curl -H "Authorization:"` with unfiltered stdout | `curl -H "Authorization: Bearer $TOKEN" api.example.com` | Redirect to file/`/dev/null`, or pipe to `jq`/`grep`/`head`/`wc`/`cut`/`awk` |
13-
| References sensitive env var name writing unredacted to stdout | `echo $API_KEY` | Same as above |
7+
| Rule | Example | Fix |
8+
| -------------------------------------------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
9+
| Literal token in command | `echo vtwn_abc123…` | Rotate the exposed token; read tokens from `.env.local` at spawn time, never inline them |
10+
| `env`/`printenv`/`export -p`/`set` dumping everything | `env \| grep FOO` (unredacted) | `env \| sed 's/=.*/=<redacted>/'` or filter specific keys |
11+
| `.env*` read without redactor | `cat .env.local` | `sed 's/=.*/=<redacted>/' .env.local` or `grep -v '^#' .env.local \| cut -d= -f1` |
12+
| `curl -H "Authorization:"` with unfiltered stdout | `curl -H "Authorization: Bearer $TOKEN" api.example.com` | Redirect to file/`/dev/null`, or pipe to `jq`/`grep`/`head`/`wc`/`cut`/`awk` |
13+
| References sensitive env var name writing unredacted to stdout | `echo $API_KEY` | Same as above |
1414

1515
## What it allows
1616

.claude/hooks/token-hygiene/test/token-hygiene.test.mts

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
/**
2-
* @fileoverview Tests for the token-hygiene hook.
3-
*
4-
* Runs the hook as a subprocess (node --test), piping a tool-use
5-
* payload on stdin and asserting on the exit code + stderr. Exit 2
6-
* means the hook refused the command; exit 0 means it passed it
7-
* through.
2+
* @file Tests for the token-hygiene hook. Runs the hook as a subprocess (node
3+
* --test), piping a tool-use payload on stdin and asserting on the exit code
4+
* + stderr. Exit 2 means the hook refused the command; exit 0 means it passed
5+
* it through.
86
*/
97

108
import { describe, it } from 'node:test'
@@ -19,7 +17,10 @@ if (!nodeBin) {
1917
throw new Error('"node" not found on PATH')
2018
}
2119

22-
function runHook(command: string, toolName = 'Bash'): {
20+
function runHook(
21+
command: string,
22+
toolName = 'Bash',
23+
): {
2324
code: number | null
2425
stdout: string
2526
stderr: string
@@ -55,16 +56,10 @@ describe('token-hygiene hook', () => {
5556
assert.equal(runHook('node scripts/build.mts').code, 0)
5657
})
5758
it('sed with redaction on .env', () => {
58-
assert.equal(
59-
runHook("sed 's/=.*/=<redacted>/' .env.local").code,
60-
0,
61-
)
59+
assert.equal(runHook("sed 's/=.*/=<redacted>/' .env.local").code, 0)
6260
})
6361
it('grep key-names-only on .env', () => {
64-
assert.equal(
65-
runHook("grep -v '^#' .env.local | cut -d= -f1").code,
66-
0,
67-
)
62+
assert.equal(runHook("grep -v '^#' .env.local | cut -d= -f1").code, 0)
6863
})
6964
it('curl without Authorization header', () => {
7065
assert.equal(runHook('curl -sS https://api.example.com').code, 0)
@@ -102,9 +97,7 @@ describe('token-hygiene hook', () => {
10297
assert.match(r.stderr, /Linear API token/)
10398
})
10499
it('GitHub PAT', () => {
105-
const r = runHook(
106-
'echo ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcd1234',
107-
)
100+
const r = runHook('echo ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcd1234')
108101
assert.equal(r.code, 2)
109102
assert.match(r.stderr, /GitHub personal access token/)
110103
})
@@ -175,10 +168,7 @@ describe('token-hygiene hook', () => {
175168
assert.equal(runHook('echo $API_KEY').code, 2)
176169
})
177170
it('ruby -e with $TOKEN', () => {
178-
assert.equal(
179-
runHook('ruby -e "puts ENV[\'ACCESS_TOKEN\']"').code,
180-
2,
181-
)
171+
assert.equal(runHook('ruby -e "puts ENV[\'ACCESS_TOKEN\']"').code, 2)
182172
})
183173
})
184174

.claude/skills/guarding-paths/reference/claude-md-rule.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ This file is the rule snippet that goes into every Socket repo's CLAUDE.md
66

77
## 1 path, 1 reference
88

9-
**A path is *constructed* exactly once. Everywhere else *references* the constructed value.**
9+
**A path is _constructed_ exactly once. Everywhere else _references_ the constructed value.**
1010

11-
Referencing a single computed path many times is fine — that's the whole point of computing it once. What's banned is *re-constructing* the same path in multiple places, because that's where drift is born.
11+
Referencing a single computed path many times is fine — that's the whole point of computing it once. What's banned is _re-constructing_ the same path in multiple places, because that's where drift is born.
1212

1313
Three concrete shapes:
1414

@@ -18,7 +18,7 @@ Three concrete shapes:
1818

1919
3. **Workflows, Dockerfiles, shell scripts** — they can't `import` TS, so they construct the string once and reference it everywhere downstream. Workflows: a "Compute paths" step exposes `steps.paths.outputs.final_dir`; later steps read `${{ steps.paths.outputs.final_dir }}`. Dockerfiles/shell: assign once to a variable / `ENV`, reference by name thereafter. Each canonical construction carries a comment naming the source-of-truth `paths.mts`. **Re-building** the same path in a second step is the violation, not referring to the constructed value many times.
2020

21-
Comments may describe path *structure* with placeholders ("`<mode>/<arch>`" or "`${BUILD_MODE}/${PLATFORM_ARCH}`") but should not encode a complete literal path string. Code execution takes priority over docs: violations in `.mts`/`.cts`, Makefiles, Dockerfiles, workflow YAML, and shell scripts are blocking. README and doc-comment violations are advisory unless they contain a fully-qualified path with no parametric placeholders.
21+
Comments may describe path _structure_ with placeholders ("`<mode>/<arch>`" or "`${BUILD_MODE}/${PLATFORM_ARCH}`") but should not encode a complete literal path string. Code execution takes priority over docs: violations in `.mts`/`.cts`, Makefiles, Dockerfiles, workflow YAML, and shell scripts are blocking. README and doc-comment violations are advisory unless they contain a fully-qualified path with no parametric placeholders.
2222

2323
### Three-level enforcement
2424

0 commit comments

Comments
 (0)