Skip to content

Commit 5ddc43a

Browse files
committed
chore: sync to socket-repo-template@3e20767
- 9 hook READMEs rewritten to junior-dev approachable level - programmatic-claude-lockdown SKILL.md backtick-fix for npx scanner - xport.schema.json regenerated from template - xport.json created (empty rows — single-package npm-only repo) - package.json: add xport + xport:emit-schema scripts - pnpm-workspace.yaml: add resolutionMode: highest Verified: 0 findings against template.
1 parent ed383ac commit 5ddc43a

14 files changed

Lines changed: 562 additions & 232 deletions

File tree

.claude/hooks/auth-rotation-reminder/README.md

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
# auth-rotation-reminder
22

3-
Claude Code `Stop` hook that periodically logs you out of authenticated
4-
CLIs (npm, pnpm, gcloud, vault, aws sso, docker, socket, …) so stale
5-
long-lived tokens don't sit in your dotfiles or keychain for days.
6-
7-
## Why
8-
9-
Long-lived auth tokens live in well-known locations: `~/.npmrc`,
10-
`~/.config/gh/hosts.yml`, `~/.config/gcloud/`, `~/.docker/config.json`.
11-
A compromised dev workstation has a wide blast radius on those files.
12-
Periodic auto-revocation tightens the window and forces explicit
13-
re-authentication, which is itself a small phishing-defense moment
14-
("did I really mean to publish?").
3+
A **Claude Code hook** that runs at the *end* of every Claude turn,
4+
notices when you've been logged into a CLI for "too long," and
5+
automatically logs you out so stale long-lived tokens don't sit in
6+
your dotfiles or keychain for days.
7+
8+
> If you haven't worked with Claude Code hooks before: hooks are tiny
9+
> scripts that run at specific lifecycle points. A `Stop` hook like
10+
> this one fires *after* Claude finishes a turn. Stop hooks are a
11+
> good place for periodic maintenance — they have access to your
12+
> shell environment but don't gate any tool calls.
13+
14+
## Why automatic logout
15+
16+
Long-lived auth tokens live in well-known files: `~/.npmrc`,
17+
`~/.config/gh/hosts.yml`, `~/.config/gcloud/`, `~/.docker/config.json`,
18+
your OS keychain. A compromised dev workstation has a wide blast
19+
radius on those files. Periodic auto-revocation tightens the window
20+
where a stolen token is useful, and forces explicit re-authentication
21+
— which is itself a small phishing-defense moment ("did I really
22+
mean to publish?").
1523

1624
## Defaults
1725

@@ -120,12 +128,20 @@ node --test test/*.test.mts
120128

121129
## Reusing the snooze convention
122130

123-
Other hooks can adopt the same `.snooze` pattern. The convention is:
131+
Other hooks can adopt the same `.snooze` pattern. The convention:
124132

125133
- Filename: `.claude/<hook-id>.snooze` (project) or
126134
`~/.claude/hooks/<hook-id>/snooze` (global).
127135
- Format: ISO 8601 expiry on line 1. Optional further lines ignored.
128136
- `.gitignore`: `.claude/*.snooze`.
129-
- Cleanup: hook auto-deletes expired files via `safeDelete`.
130-
- The `checkSnoozes` / `tryUnlink` helpers in `index.mts` are easy to
131-
copy into a sibling hook.
137+
- Cleanup: hook auto-deletes expired files via `safeDelete` from
138+
`@socketsecurity/lib/fs`.
139+
- The `checkSnoozes` helper in `index.mts` is easy to copy into a
140+
sibling hook.
141+
142+
## Cross-fleet sync
143+
144+
This README and the hook itself live in
145+
[`socket-repo-template`](https://github.com/SocketDev/socket-repo-template/tree/main/template/.claude/hooks/auth-rotation-reminder)
146+
and are required to be byte-identical across every fleet repo.
147+
`scripts/sync-scaffolding.mts` flags drift; `--fix` rewrites it.
Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,41 @@
1-
# check-new-deps Hook
2-
3-
A Claude Code pre-tool hook that checks new dependencies against [Socket.dev](https://socket.dev) before they're added to the project. It runs automatically every time Claude tries to edit or create a dependency manifest file.
4-
5-
## What it does
6-
7-
When Claude edits a file like `package.json`, `requirements.txt`, `Cargo.toml`, or any of 17+ supported ecosystems, this hook:
8-
9-
1. **Detects the file type** and extracts dependency names from the content
10-
2. **Diffs against the old content** (for edits) so only *newly added* deps are checked
11-
3. **Queries the Socket.dev API** to check for malware and critical security alerts
12-
4. **Blocks the edit** (exit code 2) if malware or critical alerts are found
13-
5. **Warns** (but allows) if a package has a low quality score
14-
6. **Allows** (exit code 0) if everything is clean or the file isn't a manifest
15-
16-
## How it works
1+
# check-new-deps
2+
3+
A **Claude Code hook** that runs whenever Claude tries to edit or
4+
create a dependency manifest (`package.json`, `requirements.txt`,
5+
`Cargo.toml`, and 14+ other ecosystems). It extracts the
6+
*newly added* dependencies, asks [Socket.dev](https://socket.dev) if
7+
any of them are known malware or have critical security alerts, and
8+
**blocks** the edit if so.
9+
10+
> If you haven't worked with Claude Code hooks before: hooks are tiny
11+
> scripts that run at specific lifecycle points. A `PreToolUse` hook
12+
> like this one fires *before* Claude calls a tool (here, `Edit` or
13+
> `Write`). It can either **prime** (write to stderr, exit 0, model
14+
> carries on) or **block** (exit 2, edit never happens). This one
15+
> blocks for malware/critical findings and primes for low-quality
16+
> warnings.
17+
18+
## What it does, step by step
19+
20+
1. Claude tries to edit `package.json` (or any other supported
21+
manifest).
22+
2. The hook reads the proposed edit from stdin.
23+
3. It detects the file type and extracts dependency names from the
24+
new content.
25+
4. For an `Edit` (not a `Write`), it diffs new content vs. old, so
26+
only *newly added* dependencies get checked — existing deps
27+
aren't re-scanned every time you bump an unrelated version.
28+
5. It builds a [Package URL (PURL)](https://github.com/package-url/purl-spec)
29+
for each new dep and calls Socket.dev's `checkMalware` API.
30+
6. Three outcomes:
31+
- **Malware or critical alert** → exit `2`. Edit is blocked,
32+
Claude reads the alert reason from stderr and either picks a
33+
different package or asks the user.
34+
- **Low quality score** → exit `0` with a warning. Edit proceeds.
35+
- **Clean (or file isn't a manifest)** → exit `0` silently. Edit
36+
proceeds.
37+
38+
## Flow diagram
1739

1840
```
1941
Claude wants to edit package.json
@@ -23,25 +45,25 @@ Hook receives the edit via stdin (JSON)
2345
2446
2547
Extract new deps from new_string
26-
Diff against old_string (if Edit)
48+
Diff against old_string (if Edit, not Write)
2749
2850
2951
Build Package URLs (PURLs) for each dep
3052
3153
3254
Call sdk.checkMalware(components)
3355
- ≤5 deps: parallel firewall API (fast, full data)
34-
- >5 deps: batch PURL API (efficient)
56+
- >5 deps: batch PURL API (efficient)
3557
3658
├── Malware/critical alert → EXIT 2 (blocked)
37-
├── Low score → warn, EXIT 0 (allowed)
38-
└── Clean → EXIT 0 (allowed)
59+
├── Low score → warn, EXIT 0 (allowed)
60+
└── Clean → EXIT 0 (allowed)
3961
```
4062

4163
## Supported ecosystems
4264

43-
| File | Ecosystem | Example dep format |
44-
|------|-----------|-------------------|
65+
| File pattern | Ecosystem | Example |
66+
|-------------|-----------|---------|
4567
| `package.json` | npm | `"express": "^4.19"` |
4668
| `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock` | npm | lockfile entries |
4769
| `requirements.txt`, `pyproject.toml`, `setup.py` | PyPI | `flask>=3.0` |
@@ -51,7 +73,7 @@ Call sdk.checkMalware(components)
5173
| `composer.json`, `composer.lock` | Composer (PHP) | `"vendor/package": "^3.0"` |
5274
| `pom.xml`, `build.gradle` | Maven (Java) | `<artifactId>commons</artifactId>` |
5375
| `pubspec.yaml`, `pubspec.lock` | Pub (Dart) | `flutter_bloc: ^8.1` |
54-
| `.csproj` | NuGet (.NET) | `<PackageReference Include="..."/>` |
76+
| `.csproj` | NuGet (.NET) | `<PackageReference Include="..." />` |
5577
| `mix.exs` | Hex (Elixir) | `{:phoenix, "~> 1.7"}` |
5678
| `Package.swift` | Swift PM | `.package(url: "...", from: "4.0")` |
5779
| `*.tf` | Terraform | `source = "hashicorp/aws"` |
@@ -60,7 +82,13 @@ Call sdk.checkMalware(components)
6082
| `flake.nix` | Nix | `github:owner/repo` |
6183
| `.github/workflows/*.yml` | GitHub Actions | `uses: owner/repo@ref` |
6284

63-
## Configuration
85+
## Caching
86+
87+
API responses are cached in-memory for 5 minutes (max 500 entries)
88+
to avoid redundant network calls when Claude touches the same
89+
manifest a few times in one session.
90+
91+
## Wiring
6492

6593
The hook is registered in `.claude/settings.json`:
6694

@@ -84,19 +112,23 @@ The hook is registered in `.claude/settings.json`:
84112

85113
## Dependencies
86114

87-
All dependencies use `catalog:` references from the workspace root (`pnpm-workspace.yaml`):
115+
All dependencies use `catalog:` references from the workspace root
116+
(`pnpm-workspace.yaml`):
88117

89-
- `@socketsecurity/sdk` — Socket.dev SDK v4 with `checkMalware()` API
90-
- `@socketsecurity/lib` — shared constants and path utilities
91-
- `@socketregistry/packageurl-js` — Package URL (PURL) parsing and stringification
118+
- `@socketsecurity/sdk` — Socket.dev SDK v4, exposes `checkMalware()`.
119+
- `@socketsecurity/lib` — shared constants and path utilities.
120+
- `@socketregistry/packageurl-js` — Package URL (PURL) parsing.
92121

93-
## Caching
122+
## Exit codes
94123

95-
API responses are cached in-memory for 5 minutes (max 500 entries) to avoid redundant network calls when Claude checks the same dependency multiple times in a session.
124+
| Code | Meaning | What Claude does next |
125+
|------|---------|----------------------|
126+
| `0` | Allow | Edit/Write proceeds normally. |
127+
| `2` | Block | Edit/Write is rejected; Claude reads the block reason from stderr. |
96128

97-
## Exit codes
129+
## Cross-fleet sync
98130

99-
| Code | Meaning | Claude behavior |
100-
|------|---------|----------------|
101-
| 0 | Allow | Edit/Write proceeds normally |
102-
| 2 | Block | Edit/Write is rejected, Claude sees the error message |
131+
This README and the hook itself live in
132+
[`socket-repo-template`](https://github.com/SocketDev/socket-repo-template/tree/main/template/.claude/hooks/check-new-deps)
133+
and are required to be byte-identical across every fleet repo.
134+
`scripts/sync-scaffolding.mts` flags drift; `--fix` rewrites it.
Lines changed: 75 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,62 @@
11
# logger-guard
22

3-
Claude Code `PreToolUse` hook that blocks `Edit`/`Write` tool calls
4-
introducing direct stream writes (`process.stderr.write`,
5-
`process.stdout.write`, `console.log/error/warn/info/debug`) into
6-
source files.
3+
A **Claude Code hook** that runs before `Edit` or `Write` tool calls
4+
on TypeScript source files and **blocks** edits that introduce direct
5+
stream writes — `process.stderr.write`, `process.stdout.write`,
6+
`console.log` / `error` / `warn` / `info` / `debug` — into source
7+
code that's supposed to use a logger.
78

8-
## Why
9+
> If you haven't worked with Claude Code hooks before: hooks are tiny
10+
> scripts that run at specific lifecycle points. A `PreToolUse` hook
11+
> like this one fires *before* Claude calls a tool. It can either
12+
> **prime** (write to stderr, exit 0, model carries on) or **block**
13+
> (exit 2, edit never happens). This one blocks.
914
10-
Source code uses `getDefaultLogger()` from `@socketsecurity/lib/logger`
11-
for all output. Direct stream writes bypass:
15+
## Why a logger and not console.log
1216

13-
- Color/theme handling
14-
- Indentation tracking
15-
- Stream redirection in tests
16-
- Counter increments used by spinners and progress bars
17+
Source code in this fleet uses `getDefaultLogger()` from
18+
`@socketsecurity/lib/logger` for all output. That logger handles:
1719

18-
so they produce inconsistent output that breaks layout-sensitive
19-
workflows (spinner clears, footer rendering).
20+
- **Color and theme.** Terminal colors honor the user's environment
21+
(no-color, light/dark, etc.). Direct `console.log` doesn't.
22+
- **Indentation tracking.** Nested operations indent their output.
23+
Direct writes don't, so you get unaligned messages.
24+
- **Stream redirection in tests.** Vitest captures and asserts on
25+
logger output. Direct writes go to the real stdout/stderr and
26+
pollute test reports.
27+
- **Layout-sensitive features.** Spinners, progress bars, and footer
28+
rendering all increment counters the logger maintains. Bypassing
29+
the logger leaves those counters wrong, which produces visual
30+
artifacts (a spinner that doesn't clear, a footer that
31+
duplicates).
32+
33+
The block is what keeps the logger as the single source of truth.
34+
If even one file directly writes to stdout, the next person on a
35+
related file sees the precedent and follows it; the convention
36+
erodes.
2037

2138
## Scope
2239

23-
- Only fires on `Edit` / `Write` tools.
24-
- Only inspects files matching `*.{ts,mts,tsx,cts}` under repo
25-
source. Hooks (`.claude/hooks/`), git-hooks (`.git-hooks/`), build
26-
scripts (`scripts/`), tests, fixtures, and external/vendored code
27-
are exempt.
28-
- Lines containing `# socket-hook: allow logger` are exempt
29-
(canonical opt-out). The bare `# socket-hook: allow` form also
30-
works.
31-
- Lines that look like documentation (`*` / `//` / `#` comments,
32-
JSDoc tags, fully-backticked code spans) are exempt.
40+
The hook is intentionally narrow:
41+
42+
- **Fires** on `Edit` and `Write` calls.
43+
- **Inspects** files matching `*.{ts,mts,tsx,cts}` under repo source.
44+
- **Exempts** `.claude/hooks/`, `.git-hooks/`, `scripts/`, tests,
45+
fixtures, and external/vendored code — those have legitimate
46+
reasons to write directly.
47+
- **Exempts** lines tagged `# socket-hook: allow logger` (canonical
48+
per-line opt-out). The bare form `# socket-hook: allow` also
49+
works for blanket suppression.
50+
- **Exempts** lines that look like documentation: lines starting
51+
with `*`, `//`, or `#`; JSDoc tags; fully-backticked code spans.
3352

3453
## Suggested replacements
3554

55+
When the hook blocks, it surfaces a concrete rewrite per hit so the
56+
agent can apply it directly:
57+
3658
| Direct call | Logger equivalent |
37-
| --- | --- |
59+
|-------------|-------------------|
3860
| `process.stderr.write(s)` | `logger.error(s)` |
3961
| `process.stdout.write(s)` | `logger.info(s)` |
4062
| `console.error(...)` | `logger.error(...)` |
@@ -43,12 +65,38 @@ workflows (spinner clears, footer rendering).
4365
| `console.debug(...)` | `logger.debug(...)` |
4466
| `console.log(...)` | `logger.info(...)` |
4567

46-
The hook surfaces the rewrite as a `Fix:` line per hit so the agent
47-
can apply it directly.
68+
## Wiring
69+
70+
`.claude/settings.json`:
4871

49-
## Tests
72+
```json
73+
{
74+
"hooks": {
75+
"PreToolUse": [
76+
{
77+
"matcher": "Edit|Write",
78+
"hooks": [
79+
{
80+
"type": "command",
81+
"command": "node .claude/hooks/logger-guard/index.mts"
82+
}
83+
]
84+
}
85+
]
86+
}
87+
}
88+
```
89+
90+
## Testing
5091

5192
```bash
5293
cd .claude/hooks/logger-guard
5394
node --test test/*.test.mts
5495
```
96+
97+
## Cross-fleet sync
98+
99+
This README and the hook itself live in
100+
[`socket-repo-template`](https://github.com/SocketDev/socket-repo-template/tree/main/template/.claude/hooks/logger-guard)
101+
and are required to be byte-identical across every fleet repo.
102+
`scripts/sync-scaffolding.mts` flags drift; `--fix` rewrites it.

0 commit comments

Comments
 (0)