diff --git a/.claude/agents/code-reviewer.md b/.claude/agents/code-reviewer.md new file mode 100644 index 00000000..1a8c0728 --- /dev/null +++ b/.claude/agents/code-reviewer.md @@ -0,0 +1,25 @@ +You are a code reviewer for a Node.js/TypeScript monorepo (socket-lib). + +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. + +**Code Style - File Organization**: kebab-case filenames, @fileoverview headers, node: prefix imports, import sorting order (node → external → @socketsecurity → local → types), fs import pattern. + +**Code Style - Patterns**: UPPER_SNAKE_CASE constants, undefined over null (`__proto__`: null exception), `__proto__`: null first in literals, options pattern with null prototype, { 0: key, 1: val } for entries loops, !array.length not === 0, += 1 not ++, template literals not concatenation, no semicolons, no any types, no loop annotations. + +**Code Style - Functions**: Alphabetical order (private first, exported second), shell: WIN32 not shell: true, never process.chdir(), use @socketsecurity/registry/lib/spawn not child_process. + +**Code Style - Comments**: Default NO comments. Only when WHY is non-obvious. Multi-sentence comments end with periods; single phrases may not. Single-line only. JSDoc: description + @throws only. + +**Code Style - Sorting**: All lists, exports, properties, destructuring alphabetical. Type properties: required first, optional second. + +**Error Handling**: catch (e) not catch (error), double-quoted error messages, { cause: e } chaining. + +**Backward Compatibility**: FORBIDDEN — actively remove compat shims, don't maintain them. + +**Test Style**: Functional tests over source scanning. Never read source files and assert on contents. Verify behavior with real function calls. + +For each file reviewed, report: +- **Style violations** with file:line +- **Logic issues** (bugs, edge cases, missing error handling) +- **Test gaps** (untested code paths) +- Suggested fix for each finding diff --git a/.claude/agents/refactor-cleaner.md b/.claude/agents/refactor-cleaner.md new file mode 100644 index 00000000..3c37365d --- /dev/null +++ b/.claude/agents/refactor-cleaner.md @@ -0,0 +1,25 @@ +You are a refactoring specialist for a Node.js/TypeScript monorepo (socket-lib). + +Apply these rules from CLAUDE.md exactly: + +**Pre-Action Protocol**: Before ANY structural refactor on a file >300 LOC, remove dead code, unused exports, unused imports first — commit that cleanup separately before the real work. Multi-file changes: break into phases (≤5 files each), verify each phase. + +**Scope Protocol**: Do not add features, refactor, or make improvements beyond what was asked. Try simplest approach first. + +**Verification Protocol**: Run the actual command after changes. State what you verified. Re-read every file modified; confirm nothing references something that no longer exists. + +**Procedure:** + +1. **Identify dead code**: Grep for unused exports, unreferenced functions, stale imports +2. **Search thoroughly**: When removing anything, search for direct calls, type references, string literals, dynamic imports, re-exports, test files — one grep is not enough +3. **Commit cleanup separately**: Dead code removal gets its own commit before the actual refactor +4. **Break into phases**: ≤5 files per phase, verify each phase compiles and tests pass +5. **Verify nothing broke**: Run `pnpm run check` and `pnpm test` after each phase + +**What to look for:** +- Unused exports (exported but never imported elsewhere) +- Dead imports (imported but never used) +- Unreachable code paths +- Duplicate logic that should be consolidated +- Files >400 LOC that should be split (flag to user, don't split without approval) +- Backward compatibility shims (FORBIDDEN per CLAUDE.md — actively remove) diff --git a/.claude/agents/security-reviewer.md b/.claude/agents/security-reviewer.md new file mode 100644 index 00000000..a5625045 --- /dev/null +++ b/.claude/agents/security-reviewer.md @@ -0,0 +1,26 @@ +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. + +**Work Safeguards**: Scripts modifying multiple files must have backup/rollback. Git operations that rewrite history require explicit confirmation. + +**Review checklist:** + +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. +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. + +For each finding, report: +- **Severity**: CRITICAL / HIGH / MEDIUM / LOW +- **Location**: file:line +- **Issue**: what's wrong +- **Fix**: how to fix it + +Run `pnpm audit` for dependency vulnerabilities. Run `pnpm run security` for config/workflow scanning. diff --git a/.claude/commands/quality-loop.md b/.claude/commands/quality-loop.md index a818f350..ddd59375 100644 --- a/.claude/commands/quality-loop.md +++ b/.claude/commands/quality-loop.md @@ -1,46 +1,21 @@ -Run the quality-scan skill and fix all issues found. Repeat until zero issues remain or 5 iterations complete. +Run the `/quality-scan` skill and fix all issues found. Repeat until zero issues remain or 5 iterations complete. + +**Interactive only** — this command makes code changes and commits. Do not use as an automated pipeline gate. ## Process -1. Run quality-scan skill -2. If issues found: fix ALL of them -3. Run quality-scan again -4. Repeat until: +1. Run `/quality-scan` skill (all scan types) +2. If issues found: spawn the `refactor-cleaner` agent (see `agents/refactor-cleaner.md`) to fix them, grouped by category +3. Run verify-build (see `_shared/verify-build.md`) after fixes +4. Run `/quality-scan` again +5. Repeat until: - Zero issues found (success), OR - 5 iterations completed (stop) -5. Commit all fixes with message: "fix: resolve quality scan issues (iteration N)" +6. Commit all fixes: `fix: resolve quality scan issues (iteration N)` ## Rules -- Fix every issue, not just "easy" ones -- Do not skip architectural fixes +- Fix every issue, not just easy ones +- Spawn refactor-cleaner with CLAUDE.md's pre-action protocol: dead code first, then structural changes, ≤5 files per phase - Run tests after fixes to verify nothing broke - Track iteration count and report progress - -## Outstanding Architectural Issue (Requires Design Review) - -### Checkpoint Cache Invalidation (High Severity) - -**Issue**: Source package changes don't invalidate checkpoints properly. - -**Root Cause**: Cache keys are computed AFTER `prepareExternalSources()` syncs source packages to additions/. Since cache keys hash files in additions/ (which are now synced), they match the checkpoint even though source packages changed. - -**Scenario**: -1. Developer modifies `packages/binject/src/socketsecurity/binject/file.c` -2. Runs `pnpm --filter node-smol-builder clean && pnpm build` -3. `prepareExternalSources()` syncs binject → additions/source-patched/src/socketsecurity/binject/ -4. Cache key computed from additions/ files matches old checkpoint -5. Build restores stale checkpoint, skips recompilation -6. **Result**: Binary contains old binject code - -**Impact**: Silent build incorrectness when modifying source packages - -**Proposed Solutions** (require architectural review): -- Option 1: Include source package mtimes in cache key metadata -- Option 2: Make `prepareExternalSources()` idempotent, always re-sync - -**Files Affected**: -- packages/node-smol-builder/scripts/common/shared/build.mjs (collectBuildSourceFiles) -- packages/node-smol-builder/scripts/common/shared/checkpoints.mjs (cache key generation) - -**Status**: Documented for architectural review and future implementation diff --git a/.claude/commands/security-scan.md b/.claude/commands/security-scan.md new file mode 100644 index 00000000..6c629680 --- /dev/null +++ b/.claude/commands/security-scan.md @@ -0,0 +1,3 @@ +Run the `/security-scan` skill. This chains AgentShield (Claude config audit) → zizmor (GitHub Actions security) → security-reviewer agent (grading). + +For a quick manual run without the full pipeline: `pnpm run security` diff --git a/.claude/ops/queue.yaml b/.claude/ops/queue.yaml new file mode 100644 index 00000000..0358c2e9 --- /dev/null +++ b/.claude/ops/queue.yaml @@ -0,0 +1,10 @@ +schema_version: 1 + +phase_order: + quality-scan: [env-check, scans, report] + security-scan: [env-check, agentshield, zizmor, grade-report] + updating: [env-check, npm-update, validate, report] + +# Completed runs are appended here by skills. Prune periodically — +# keep the last 10 entries and delete older ones to avoid unbounded growth. +runs: [] diff --git a/.claude/skills/_shared/env-check.md b/.claude/skills/_shared/env-check.md new file mode 100644 index 00000000..ee2c203d --- /dev/null +++ b/.claude/skills/_shared/env-check.md @@ -0,0 +1,27 @@ +# Environment Check + +Shared prerequisite validation for all pipelines. Run at the start of every skill. + +## Steps + +1. Run `git status` to check working directory state +2. Detect CI mode: check for `GITHUB_ACTIONS` or `CI` environment variables +3. Verify `node_modules/` exists (run `pnpm install` if missing) +4. Verify on a valid branch (`git branch --show-current`) + +## Behavior + +- **Clean working directory**: proceed normally +- **Dirty working directory**: warn and continue (most skills are read-only or create their own commits) +- **CI mode**: set `CI_MODE=true` — skills should skip interactive prompts and local-only validation +- **Missing node_modules**: run `pnpm install` before proceeding + +## Queue Tracking + +Write a run entry to `.claude/ops/queue.yaml` with: +- `id`: `{pipeline}-{YYYY-MM-DD}-{NNN}` +- `pipeline`: the invoking skill name +- `status`: `in-progress` +- `started`: current UTC timestamp +- `current_phase`: `env-check` +- `completed_phases`: `[]` diff --git a/.claude/skills/_shared/report-format.md b/.claude/skills/_shared/report-format.md new file mode 100644 index 00000000..3e8cdce7 --- /dev/null +++ b/.claude/skills/_shared/report-format.md @@ -0,0 +1,47 @@ +# Report Format + +Shared output format for all scan and review pipelines. + +## Finding Format + +Each finding: +``` +- **[SEVERITY]** file:line — description + Fix: how to fix it +``` + +Severity levels: CRITICAL, HIGH, MEDIUM, LOW + +## Grade Calculation + +Based on finding severity distribution: +- **A** (90-100): 0 critical, 0 high +- **B** (80-89): 0 critical, 1-3 high +- **C** (70-79): 0 critical, 4+ high OR 1 critical +- **D** (60-69): 2-3 critical +- **F** (< 60): 4+ critical + +## Pipeline HANDOFF + +When a skill completes as part of a larger pipeline (e.g., quality-scan within release), +output a structured handoff block: + +``` +=== HANDOFF: {skill-name} === +Status: {pass|fail} +Grade: {A-F} +Findings: {critical: N, high: N, medium: N, low: N} +Summary: {one-line description} +=== END HANDOFF === +``` + +The parent pipeline reads this to decide whether to proceed (gate check) or abort. + +## Queue Completion + +When the final phase completes, update `.claude/ops/queue.yaml`: +- `status`: `done` (or `failed`) +- `completed`: current UTC timestamp +- `current_phase`: `~` (null) +- `completed_phases`: full list +- `findings_count`: `{critical: N, high: N, medium: N, low: N}` diff --git a/.claude/skills/_shared/security-tools.md b/.claude/skills/_shared/security-tools.md new file mode 100644 index 00000000..9a1f0271 --- /dev/null +++ b/.claude/skills/_shared/security-tools.md @@ -0,0 +1,41 @@ +# Security Tools + +Shared tool detection for security scanning pipelines. + +## AgentShield + +Installed as a pinned devDependency (`ecc-agentshield` in pnpm-workspace.yaml catalog). +Run via: `pnpm exec agentshield scan` +No install step needed — available after `pnpm install`. + +## Zizmor + +Not an npm package. Installed via `pnpm run setup` which downloads the pinned version +from GitHub releases with SHA256 checksum verification (see `external-tools.json`). + +The binary is cached at `.cache/external-tools/zizmor/{version}-{platform}/zizmor`. + +Detection order: +1. `command -v zizmor` (if already on PATH, e.g. via brew) +2. `.cache/external-tools/zizmor/*/zizmor` (from `pnpm run setup`) + +Run via the full path if not on PATH: +```bash +ZIZMOR="$(find .cache/external-tools/zizmor -name zizmor -type f 2>/dev/null | head -1)" +if [ -z "$ZIZMOR" ]; then ZIZMOR="$(command -v zizmor 2>/dev/null)"; fi +if [ -n "$ZIZMOR" ]; then "$ZIZMOR" .github/; else echo "zizmor not installed — run pnpm run setup"; fi +``` + +If not available: +- Warn: "zizmor not installed — run `pnpm run setup` to install" +- Skip the zizmor phase (don't fail the pipeline) + +## Socket CLI + +Optional. Used for dependency scanning in the updating and security-scan pipelines. + +Detection: `command -v socket` + +If not available: +- Skip socket-scan phases gracefully +- Note in report: "Socket CLI not available — dependency scan skipped" diff --git a/.claude/skills/_shared/verify-build.md b/.claude/skills/_shared/verify-build.md new file mode 100644 index 00000000..5dc82c03 --- /dev/null +++ b/.claude/skills/_shared/verify-build.md @@ -0,0 +1,22 @@ +# Verify Build + +Shared build/test/lint validation. Referenced by skills that modify code or dependencies. + +## Steps + +Run in order, stop on first failure: + +1. `pnpm run fix --all` — auto-fix lint and formatting issues +2. `pnpm run check --all` — lint + typecheck + validation (read-only, fails on violations) +3. `pnpm test` — full test suite + +## CI Mode + +When `CI_MODE=true` (detected by env-check), skip this validation entirely. +CI runs these checks in its own matrix (Node 20/22/24 × ubuntu/windows). + +## On Failure + +- Report which step failed with the error output +- Do NOT proceed to the next pipeline phase +- Mark the pipeline run as `status: failed` in `.claude/ops/queue.yaml` diff --git a/.claude/skills/security-scan/SKILL.md b/.claude/skills/security-scan/SKILL.md new file mode 100644 index 00000000..0ba403fe --- /dev/null +++ b/.claude/skills/security-scan/SKILL.md @@ -0,0 +1,82 @@ +--- +name: security-scan +description: Run 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. +--- + +# Security Scan + +Multi-tool security scanning pipeline for the repository. + +## When to Use + +- After modifying `.claude/` config, settings, hooks, or agent definitions +- After modifying GitHub Actions workflows +- Before releases (called as a gate by the release pipeline) +- Periodic security hygiene checks + +## Prerequisites + +See `_shared/security-tools.md` for tool detection and installation. + +## Process + +### Phase 1: Environment Check + +Follow `_shared/env-check.md`. Initialize a queue run entry for `security-scan`. + +--- + +### Phase 2: AgentShield Scan + +Scan Claude Code configuration for security issues: + +```bash +pnpm exec agentshield scan +``` + +Checks `.claude/` for: +- Hardcoded secrets in CLAUDE.md and settings +- Overly permissive tool allow lists (e.g. `Bash(*)`) +- Prompt injection patterns in agent definitions +- Command injection risks in hooks +- Risky MCP server configurations + +Capture the grade and findings count. + +Update queue: `current_phase: agentshield` → `completed_phases: [env-check, agentshield]` + +--- + +### Phase 3: Zizmor Scan + +Scan GitHub Actions workflows for security issues. + +See `_shared/security-tools.md` for zizmor detection. If not installed, skip with a warning. + +```bash +zizmor .github/ +``` + +Checks for: +- Unpinned actions (must use full SHA, not tags) +- Secrets used outside `env:` blocks +- Injection risks from untrusted inputs (template injection) +- Overly permissive permissions + +Capture findings. Update queue phase. + +--- + +### Phase 4: Grade + Report + +Spawn the `security-reviewer` agent (see `agents/security-reviewer.md`) with the combined output from AgentShield and zizmor. + +The agent: +1. Applies CLAUDE.md security rules to evaluate the findings +2. Calculates an A-F grade per `_shared/report-format.md` +3. Generates a prioritized report (CRITICAL first) +4. Suggests fixes for HIGH and CRITICAL findings + +Output a HANDOFF block per `_shared/report-format.md` for pipeline chaining. + +Update queue: `status: done`, write `findings_count` and final grade. diff --git a/.git-hooks/pre-commit b/.git-hooks/pre-commit index 6b3b7db2..b6feeac8 100755 --- a/.git-hooks/pre-commit +++ b/.git-hooks/pre-commit @@ -112,6 +112,22 @@ echo "$STAGED_FILES" | while IFS= read -r file; do fi done +# Check for npx/dlx usage (use pnpm exec or pnpm run instead). +printf "Checking for npx/dlx usage...\n" +for file in $STAGED_FILES; do + if [ -f "$file" ]; then + if echo "$file" | grep -qE 'node_modules/|pnpm-lock\.yaml|\.git-hooks/'; then + continue + fi + if grep -nE '\bnpx\b|\bpnpm dlx\b|\byarn dlx\b' "$file" 2>/dev/null | grep -v '# zizmor:' | grep -q .; then + printf "${RED}✗ ERROR: npx/dlx usage found in: $file${NC}\n" + grep -nE '\bnpx\b|\bpnpm dlx\b|\byarn dlx\b' "$file" | grep -v '# zizmor:' | head -3 + printf "Use 'pnpm exec ' or 'pnpm run