Skip to content

Commit cfa5d32

Browse files
committed
chore(hooks): sync .claude/hooks fleet — mts conversion + new guards
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.
1 parent cd30bb0 commit cfa5d32

53 files changed

Lines changed: 5009 additions & 432 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# auth-rotation-reminder
2+
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?").
15+
16+
## Defaults
17+
18+
- **Interval**: 1 hour. Set `SOCKET_AUTH_ROTATION_INTERVAL_HOURS=4` to
19+
loosen, `=0` to run on every Stop event.
20+
- **Mode**: auto-logout (the hook *acts*, not just warns).
21+
- **Default skip-list**: `gh` is skipped because Claude Code itself
22+
uses `gh` for `gh pr edit` etc. — auto-revoking it would break the
23+
agent.
24+
- **CI**: hook short-circuits when `CI` env var is set.
25+
26+
## What's swept
27+
28+
| id | display name | detect | logout |
29+
| --------- | ----------------- | ----------------- | ------------------------------ |
30+
| npm | npm | `npm whoami` | `npm logout` |
31+
| pnpm | pnpm | `pnpm whoami` | `pnpm logout` |
32+
| yarn | yarn | `yarn --version` | `yarn npm logout` |
33+
| gcloud | gcloud | `gcloud auth list ... ACTIVE` | `gcloud auth revoke --all --quiet` |
34+
| aws-sso | aws (sso) | `aws sts get-caller-identity` | `aws sso logout` |
35+
| gh | gh (GitHub CLI) | `gh auth status` | `gh auth logout --hostname github.com` |
36+
| vault | vault | `vault token lookup` | `vault token revoke -self` |
37+
| docker | docker | `docker info \| grep Username:` | `docker logout` |
38+
| socket | socket | `socket whoami` | `socket logout` |
39+
40+
The hook never reads, prints, or compares any token value. Detection
41+
is exit-code only; logout commands' output is suppressed except for
42+
non-zero exit codes which surface as "logout failed" lines.
43+
44+
## Snoozing
45+
46+
Need to keep your auth alive for the next few hours (e.g. mid-publish)?
47+
Drop a `.snooze` file with an ISO 8601 expiry on line 1.
48+
49+
```bash
50+
# Snooze for 4 hours, project-local
51+
date -ud "+4 hours" +"%Y-%m-%dT%H:%M:%SZ" > .claude/auth-rotation.snooze
52+
53+
# Snooze globally for 8 hours (applies to every repo)
54+
mkdir -p ~/.claude/hooks/auth-rotation
55+
date -ud "+8 hours" +"%Y-%m-%dT%H:%M:%SZ" > ~/.claude/hooks/auth-rotation/snooze
56+
```
57+
58+
The hook **automatically deletes the file** once the timestamp is
59+
reached. No manual cleanup needed.
60+
61+
Snoozes that are malformed, empty, or unreadable are also auto-deleted
62+
on the next run — fail-safe so a corrupted file can't permanently
63+
disable rotation.
64+
65+
`.claude/*.snooze` is gitignored; project-local snoozes never leak into
66+
commits.
67+
68+
## Skip-list
69+
70+
Permanently skip a service:
71+
72+
```bash
73+
# Per-user: applies to every repo
74+
mkdir -p ~/.claude/hooks/auth-rotation
75+
echo gcloud >> ~/.claude/hooks/auth-rotation/services-skip
76+
77+
# Per-repo: applies just to this checkout
78+
echo vault >> .claude/auth-rotation.services-skip
79+
```
80+
81+
One id per line. Lines starting with `#` are comments. Service ids
82+
are stable — see the table above.
83+
84+
## Disable temporarily
85+
86+
```bash
87+
SOCKET_AUTH_ROTATION_DISABLED=1 # any non-empty value
88+
```
89+
90+
For pairing sessions, demos, etc. The hook short-circuits before
91+
doing any work.
92+
93+
## Wiring
94+
95+
In `.claude/settings.json`:
96+
97+
```json
98+
{
99+
"hooks": {
100+
"Stop": [
101+
{
102+
"hooks": [
103+
{
104+
"type": "command",
105+
"command": "node .claude/hooks/auth-rotation-reminder/index.mts"
106+
}
107+
]
108+
}
109+
]
110+
}
111+
}
112+
```
113+
114+
## Tests
115+
116+
```bash
117+
cd .claude/hooks/auth-rotation-reminder
118+
node --test test/*.test.mts
119+
```
120+
121+
## Reusing the snooze convention
122+
123+
Other hooks can adopt the same `.snooze` pattern. The convention is:
124+
125+
- Filename: `.claude/<hook-id>.snooze` (project) or
126+
`~/.claude/hooks/<hook-id>/snooze` (global).
127+
- Format: ISO 8601 expiry on line 1. Optional further lines ignored.
128+
- `.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.

0 commit comments

Comments
 (0)