diff --git a/.claude/agents/code-reviewer.md b/.claude/agents/code-reviewer.md index 1f3433334..e40362300 100644 --- a/.claude/agents/code-reviewer.md +++ b/.claude/agents/code-reviewer.md @@ -1,3 +1,9 @@ +--- +name: code-reviewer +description: Reviews code in socket-cli against CLAUDE.md rules and reports style violations, logic bugs, and test gaps. Spawned by the quality-scan skill or invoked directly on a diff. +tools: Read, Grep, Glob, Bash(git:*), Bash(rg:*), Bash(grep:*), Bash(find:*), Bash(ls:*), Bash(wc:*), Bash(cat:*), Bash(head:*), Bash(tail:*) +--- + You are a code reviewer for a Node.js/TypeScript monorepo (socket-cli). Apply the rules from CLAUDE.md sections listed below. Reference the full section in CLAUDE.md for details — these are summaries, not the complete rules. diff --git a/.claude/agents/refactor-cleaner.md b/.claude/agents/refactor-cleaner.md index 7f823bd75..68e6b0a08 100644 --- a/.claude/agents/refactor-cleaner.md +++ b/.claude/agents/refactor-cleaner.md @@ -1,3 +1,9 @@ +--- +name: refactor-cleaner +description: Refactor specialist for socket-cli. Removes dead code first, batches changes into ≤5-file phases, verifies each with the project's check + test scripts. Use after quality-scan or before structural refactors. +tools: Read, Edit, Write, Grep, Glob, Bash(git:*), Bash(rg:*), Bash(grep:*), Bash(find:*), Bash(ls:*), Bash(pnpm run:*), Bash(pnpm test:*), Bash(pnpm exec:*), Bash(node:*), Bash(cat:*), Bash(head:*), Bash(tail:*) +--- + You are a refactoring specialist for a Node.js/TypeScript monorepo (socket-cli). Apply these rules from CLAUDE.md exactly: diff --git a/.claude/agents/security-reviewer.md b/.claude/agents/security-reviewer.md index a56250453..83137fd62 100644 --- a/.claude/agents/security-reviewer.md +++ b/.claude/agents/security-reviewer.md @@ -1,10 +1,16 @@ +--- +name: security-reviewer +description: Reviews findings from AgentShield + zizmor against socket-cli's CLAUDE.md security rules and grades the result A-F. Spawned by the security-scan skill after the static scans run. +tools: Read, Grep, Glob, Bash(git:*), Bash(rg:*), Bash(grep:*), Bash(find:*), Bash(ls:*), Bash(pnpm exec agentshield:*), Bash(zizmor:*), Bash(command -v:*), Bash(cat:*), Bash(head:*), Bash(tail:*) +--- + You are a security reviewer for Socket Security Node.js repositories. Apply these rules from CLAUDE.md exactly: **Safe File Operations**: Use safeDelete()/safeDeleteSync() from @socketsecurity/lib/fs. NEVER fs.rm(), fs.rmSync(), or rm -rf. Use os.tmpdir() + fs.mkdtemp() for temp dirs. NEVER use fetch() — use httpJson/httpText/httpRequest from @socketsecurity/lib/http-request. -**Absolute Rules**: NEVER use npx, pnpm dlx, or yarn dlx. Use pnpm exec or pnpm run with pinned devDeps. +**Absolute Rules**: NEVER use npx, pnpm dlx, or yarn dlx. Use pnpm exec or pnpm run with pinned devDeps. # zizmor: documentation-prohibition **Work Safeguards**: Scripts modifying multiple files must have backup/rollback. Git operations that rewrite history require explicit confirmation. @@ -12,7 +18,7 @@ Apply these rules from CLAUDE.md exactly: 1. **Secrets**: Hardcoded API keys, passwords, tokens, private keys in code or config 2. **Injection**: Command injection via shell: true or string interpolation in spawn/exec. Path traversal in file operations. -3. **Dependencies**: npx/dlx usage. Unpinned versions (^ or ~). Missing minimumReleaseAge bypass justification. +3. **Dependencies**: npx/dlx usage. Unpinned versions (^ or ~). Missing minimumReleaseAge bypass justification. # zizmor: documentation-checklist 4. **File operations**: fs.rm without safeDelete. process.chdir usage. fetch() usage (must use lib's httpRequest). 5. **GitHub Actions**: Unpinned action versions (must use full SHA). Secrets outside env blocks. Template injection from untrusted inputs. 6. **Error handling**: Sensitive data in error messages. Stack traces exposed to users. diff --git a/.claude/settings.json b/.claude/settings.json index 3490c309f..c969b131c 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -24,5 +24,18 @@ ] } ] + }, + "permissions": { + "deny": [ + "Bash(gh release create:*)", + "Bash(gh release delete:*)", + "Bash(gh workflow dispatch:*)", + "Bash(gh workflow run:*)", + "Bash(git push --force:*)", + "Bash(git push -f:*)", + "Bash(npm publish:*)", + "Bash(pnpm publish:*)", + "Bash(yarn publish:*)" + ] } } diff --git a/.claude/skills/programmatic-claude-lockdown/SKILL.md b/.claude/skills/programmatic-claude-lockdown/SKILL.md new file mode 100644 index 000000000..f2561013a --- /dev/null +++ b/.claude/skills/programmatic-claude-lockdown/SKILL.md @@ -0,0 +1,84 @@ +--- +name: programmatic-claude-lockdown +description: Reference for locking down programmatic Claude invocations (the `claude` CLI in workflows/scripts, the `@anthropic-ai/claude-agent-sdk` `query()` in code). Loads on demand when writing or reviewing any callsite that runs Claude programmatically. Source: https://code.claude.com/docs/en/agent-sdk/permissions. +user-invocable: false +allowed-tools: Read, Grep, Glob +--- + +# Programmatic Claude lockdown + +**Rule:** every programmatic Claude callsite sets four flags. Skip any one and a future edit silently widens the surface. + +## The four flags + +| Layer | SDK option | CLI flag | What it does | +|---|---|---|---| +| Definition | `tools` | `--tools` | Base set the model is told about. Tools not listed are invisible — no `tool_use` block possible. | +| Auto-approve | `allowedTools` | `--allowedTools` | Step 4. Listed tools run without invoking `canUseTool`. | +| Deny | `disallowedTools` | `--disallowedTools` | Step 2. Wins even against `bypassPermissions`. Defense-in-depth. | +| Mode | `permissionMode: 'dontAsk'` | `--permission-mode dontAsk` | Step 3. Unmatched tools denied without falling through to a missing `canUseTool`. | + +The official permission flow (1) hooks → (2) deny rules → (3) permission mode → (4) allow rules → (5) `canUseTool`. In `dontAsk` mode step 5 is skipped — denied. The doc states verbatim: *"`allowedTools` and `disallowedTools` ... control whether a tool call is approved, not whether the tool is available."* Availability is `tools`. + +## Recipe — read-only agent (audit, classify, summarize) + +```ts +import { query } from '@anthropic-ai/claude-agent-sdk' + +query({ + prompt: '...', + options: { + tools: ['Read', 'Grep', 'Glob'], + allowedTools: ['Read', 'Grep', 'Glob'], + disallowedTools: ['Agent', 'Bash', 'Edit', 'NotebookEdit', 'Task', 'WebFetch', 'WebSearch', 'Write'], + permissionMode: 'dontAsk', + }, +}) +``` + +CLI form for workflow YAML / shell scripts: + +```yaml +claude --print \ + --tools "Read" "Grep" "Glob" \ + --allowedTools "Read" "Grep" "Glob" \ + --disallowedTools "Agent" "Bash" "Edit" "NotebookEdit" "Task" "WebFetch" "WebSearch" "Write" \ + --permission-mode dontAsk \ + --model "$MODEL" \ + --max-turns 25 \ + "" +``` + +## Recipe — agent that needs Bash (e.g. `/updating`: pnpm + git + jq) + +Narrow `Bash(...)` patterns surgically. Block dangerous Bash patterns explicitly. Fleet rules: no `npx`/`pnpm dlx`/`yarn dlx`; no `curl`/`wget` exfil; no destructive `rm -rf`; no `sudo`. Build the deny list as shell vars so the npx/dlx denials can carry the `# zizmor:` exemption marker (the pre-commit `scanNpxDlx` hook treats those literal strings as the prohibited tools, not as exemptions, unless the line is tagged): + +```yaml +DISALLOW_BASE='Agent Task NotebookEdit WebFetch WebSearch Bash(curl:*) Bash(wget:*) Bash(rm -rf*) Bash(sudo:*)' +DISALLOW_PKG_EXEC='Bash(npx:*) Bash(pnpm dlx:*) Bash(yarn dlx:*)' # zizmor: documentation-prohibition +claude --print \ + --tools "Bash" "Read" "Write" "Edit" "Glob" "Grep" \ + --allowedTools "Bash(pnpm:*)" "Bash(git:*)" "Bash(jq:*)" "Read" "Write" "Edit" "Glob" "Grep" \ + --disallowedTools $DISALLOW_BASE $DISALLOW_PKG_EXEC \ + --permission-mode dontAsk \ + --model "$MODEL" --max-turns 25 \ + "" +``` + +## Never + +- ❌ `permissionMode: 'default'` in headless contexts — falls through to a missing `canUseTool`. Behavior undefined. +- ❌ `permissionMode: 'bypassPermissions'` / `allowDangerouslySkipPermissions: true`. +- ❌ Omitting `tools` — SDK default is the full claude_code preset. +- ❌ `Agent` / `Task` permitted — sub-agents inherit modes and can escape per-subagent restrictions when the parent is `bypassPermissions`/`acceptEdits`/`auto`. + +## Reference implementation + +`socket-lib/tools/prim/src/disambiguate.mts` — canonical SDK-form callsite. The file header documents each flag against the eval-flow step it enforces. + +`socket-lib/tools/prim/test/disambiguate.test.mts` — source-text guards that fail the build if `BASE_TOOLS` widens, if `tools: BASE_TOOLS` is unwired, if `permissionMode` drifts from `'dontAsk'`, or if `bypassPermissions` / `allowDangerouslySkipPermissions: true` ever appears. Mirror this pattern in any new callsite. + +## Existing fleet callsites + +- `socket-registry/.github/workflows/weekly-update.yml` — two `claude --print` invocations (run `/updating` skill, fix test failures). Bash recipe above. +- `socket-lib/tools/prim/src/disambiguate.mts` — read-only recipe above (`query()` SDK form). diff --git a/.claude/skills/quality-scan/SKILL.md b/.claude/skills/quality-scan/SKILL.md index 4dafcdf72..034198ced 100644 --- a/.claude/skills/quality-scan/SKILL.md +++ b/.claude/skills/quality-scan/SKILL.md @@ -5,6 +5,7 @@ description: > and committing changes until zero issues remain or 5 iterations complete. Use when improving code quality, investigating regressions, or before releases. +allowed-tools: Task, Skill, Read, Edit, Grep, Glob, AskUserQuestion, Bash(pnpm run check:*), Bash(pnpm run test:*), Bash(pnpm test:*), Bash(pnpm run fix:*), Bash(git status:*), Bash(git diff:*), Bash(git log:*), Bash(git add:*), Bash(git commit:*), Bash(rg:*), Bash(grep:*), Bash(find:*), Bash(ls:*) --- # quality-scan diff --git a/.claude/skills/security-scan/SKILL.md b/.claude/skills/security-scan/SKILL.md index 7f2fd77e8..10a3ac3f2 100644 --- a/.claude/skills/security-scan/SKILL.md +++ b/.claude/skills/security-scan/SKILL.md @@ -2,6 +2,7 @@ name: security-scan description: Runs a multi-tool security scan — AgentShield for Claude config, zizmor for GitHub Actions, and optionally Socket CLI for dependency scanning. Produces an A-F graded security report. Use after modifying `.claude/` config, hooks, agents, or GitHub Actions workflows, and before releases. user-invocable: true +allowed-tools: Task, Read, Bash(pnpm exec agentshield:*), Bash(zizmor:*), Bash(command -v:*), Bash(find .cache/external-tools/zizmor:*) --- # Security Scan diff --git a/.claude/skills/updating-checksums/SKILL.md b/.claude/skills/updating-checksums/SKILL.md index 97777b04c..8d1bc0309 100644 --- a/.claude/skills/updating-checksums/SKILL.md +++ b/.claude/skills/updating-checksums/SKILL.md @@ -5,7 +5,7 @@ description: > Triggers when user mentions "update checksums", "sync checksums", or after releasing new tool versions. user-invocable: true -allowed-tools: Bash, Read, Edit +allowed-tools: Read, Edit, Bash(node packages/cli/scripts/sync-checksums.mjs:*), Bash(git diff:*), Bash(git status:*), Bash(git add:*), Bash(git commit:*) --- # updating-checksums diff --git a/.claude/skills/updating/SKILL.md b/.claude/skills/updating/SKILL.md index f8d50f96f..40795259e 100644 --- a/.claude/skills/updating/SKILL.md +++ b/.claude/skills/updating/SKILL.md @@ -5,7 +5,7 @@ description: > Triggers when user asks to "update everything", "update dependencies", or prepare for a release. user-invocable: true -allowed-tools: Task, Skill, Bash, Read, Grep, Glob, Edit +allowed-tools: Task, Skill, Read, Edit, Bash(pnpm run:*), Bash(pnpm install:*), Bash(pnpm test:*), Bash(claude --version), Bash(node .claude/hooks/setup-security-tools/update.mts:*), Bash(git status:*), Bash(git diff:*), Bash(git add:*), Bash(git commit:*) --- # updating diff --git a/.config/tsconfig.check.json b/.config/tsconfig.check.json index e19788a4f..2f0e97d1b 100644 --- a/.config/tsconfig.check.json +++ b/.config/tsconfig.check.json @@ -12,6 +12,8 @@ "../packages/cli/.config/*.mts" ], "exclude": [ + "../.cache/**", + "../packages/cli/.cache/**", "../packages/cli/**/*.tsx", "../packages/cli/**/*.d.mts", "../packages/cli/src/commands/analytics/output-analytics.mts", diff --git a/.env.example b/.env.example index 691c00890..de9adb650 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,6 @@ # Copy this file to .env.local and customize for your local environment. # Node.js Configuration (optional overrides). -NODE_COMPILE_CACHE="./.cache" NODE_OPTIONS="--max-old-space-size=8192 --max-semi-space-size=1024" # Socket API Configuration (for e2e testing). diff --git a/.env.precommit b/.env.precommit index 1ee9eda75..75db740a8 100644 --- a/.env.precommit +++ b/.env.precommit @@ -8,5 +8,4 @@ SOCKET_CLI_NO_API_TOKEN=1 VITEST=1 # Node.js optimization for test performance. -NODE_COMPILE_CACHE="./.cache" NODE_OPTIONS="--max-old-space-size=8192" diff --git a/.gitignore b/.gitignore index 7e31376b4..00cca54ed 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ Thumbs.db .env .env.* !.env.example +!.env.precommit +!.env.test /.env.local # ============================================================================ @@ -34,6 +36,7 @@ yarn-error.log* # ============================================================================ **/.build-checkpoints **/*.build-signature +**/.cache/ /.rollup.cache **/.type-coverage/ **/build/ diff --git a/CLAUDE.md b/CLAUDE.md index cf06225ff..efdf83a22 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -29,6 +29,7 @@ - **REQUIRED for staging**: surgical `git add […]` with explicit paths. Never `-A` / `.`. - **If you need a quick WIP save**: commit on a new branch from inside a worktree, not a stash. +- **NEVER revert files you didn't touch.** If `git status` shows files you didn't modify, those belong to another session, an upstream pull, or a hook side-effect — leave them alone. Specifically: do not run `git checkout -- ` to "clean up" the diff before committing, and do not include unrelated paths in `git add`. Stage only the explicit files you edited. The umbrella rule: never run a git command that mutates state belonging to a path other than the file you just edited. @@ -101,6 +102,9 @@ The umbrella rule: never run a git command that mutates state belonging to a pat - 🚨 **NEVER use `npx`, `pnpm dlx`, or `yarn dlx`** — use `pnpm exec ` or `pnpm run