Skip to content

[#974] Setup hardening#984

Merged
realproject7 merged 1 commit into
mainfrom
task/974-setup-hardening
Jul 6, 2026
Merged

[#974] Setup hardening#984
realproject7 merged 1 commit into
mainfrom
task/974-setup-hardening

Conversation

@realproject7

Copy link
Copy Markdown
Owner

Closes #974

Setup hardening — 5 confirmed setup/start defects + 2 folded lows. Changes are confined to the setup / start paths (bin/quadwork.js, the server create-worktrees/ensureGitHeadForSetup setup route, and server.listen). No steady-state runtime, agent-spawn, or orchestrator behavior changes.

Changes

  1. Stale-branch brick (bin/quadwork.js, server/routes.js create-worktrees) — if a worktree-<agent> branch survived after its directory was deleted, setup ran git branch <name> HEAD, which fails already exists, and aborted the whole re-run with no rollback. Both paths now reuse an existing branch: prune any stale worktree registration still holding it, then git worktree add re-attaches. Setup is re-runnable. Server logic extracted to createAgentWorktree (injectable execFn for tests).

  2. CLI shipped an agent with no AGENTS.mdif (fs.existsSync(seedSrc)) silently skipped a missing seed, launching the agent with no role definition. Now hard-fails (mirrors the server seed-files route, which already did).

  3. Reviewer token never collected — the wizard asked for the token file path but never the token, so RE1/RE2 launched pointed at an empty/nonexistent file and PR reviews failed. Now prompts via the existing askSecret and writes the token 0600 (same as the server save-token endpoint); if skipped, prints a clear "add it later in Settings" step naming the exact path.

  4. No server.listen error handler — a second quadwork start (or any process already on the port) threw a raw EADDRINUSE stack trace. Adds server.on("error") → friendly, actionable message + exit 1.

  5. No origin-mismatch check — pointing setup at a clone of a different repo than the entered slug silently seeded worktrees/branches into the wrong project. ensureGitHeadForSetup (CLI and server) now compares git remote get-url origin to the entered slug and fails clearly. New repoSlugFromRemote normalizes https, ssh (scp + url), .git, and trailing-slash forms.

Folds:

  • Don't force sudo npm i -g when the global npm prefix is user-writable (nvm/fnm/volta/Homebrew installs); fall back to sudo only when the prefix genuinely needs root (npmGlobalNeedsSudo).
  • Use stdio: "inherit" for auto-installs so sudo apt install … password/confirmation prompts actually reach the TTY (the old piped run() swallowed them and hung/failed silently).

EPIC Alignment (#967)

EPIC #967 Phase 3 — isolated setup/start hardening. No steady-state runtime change, per the ticket's safety invariant: the agent spawn path and running orchestrator are untouched; every change lives in first-run setup, the reviewer-credential prompt, or the one-time server.listen. The createAgentWorktree/repoSlugFromRemote extractions keep the CLI wizard and server setup wizard behaviourally symmetric (defect 1 & 5 fixed in both).

Self-Verification

  • npm test (server suite, what CI runs) → 60 passed, 0 failed, 2 skipped (includes the new server/routes.setupHardening.test.js, 6 cases: slug normalization; origin match vs mismatch guard; worktree fresh-branch / stale-reuse / detached-fallback). pack-smoke green — no new runtime requires added.
  • node --check on all three edited files → clean.
  • Defect 4 end-to-end: started the real server/index.js (temp HOME, config port pre-occupied) → exits 1 with QuadWork: port N is already in use… on stderr, no raw stack. ✅
  • Defect 1 end-to-end: reproduced the brick against a real git repo (git worktree add -b worktree-dev …rm -rf the dir → git branch worktree-dev HEAD fails already exists), then confirmed the fix (rev-parse --verifyworktree pruneworktree add) re-creates the worktree. ✅

🤖 Generated with Claude Code

Fixes 5 confirmed setup/start defects + 2 folded lows. Changes confined
to setup/start paths (bin/quadwork.js, server setup route, server listen);
no steady-state runtime or agent-spawn behavior changes.

1. Stale-branch brick — if a `worktree-<agent>` branch survives after its
   dir was deleted, setup aborted with no rollback ("branch already exists").
   Both the CLI wizard and the server create-worktrees route now reuse an
   existing branch (prune stale registration + `worktree add` re-attach),
   making setup re-runnable. Server logic extracted to createAgentWorktree.

2. CLI silently shipped an agent with no AGENTS.md when its seed template was
   missing; now hard-fails (matches the server seed-files route).

3. CLI collected a reviewer-token *path* but never the token itself, so
   RE1/RE2 launched pointed at an empty file. Now prompts via askSecret and
   writes it 0600 (matching the server save-token endpoint), or prints a
   clear "set it in Settings" step when skipped.

4. No server.listen error handler — a second `quadwork start` threw a raw
   EADDRINUSE stack. Adds server.on('error') → friendly message + exit 1.

5. No origin-mismatch check — pointing setup at a clone of a different repo
   than the entered slug silently seeded the wrong project. ensureGitHeadForSetup
   (CLI + server) now compares `git remote get-url origin` to the slug and
   fails clearly. New repoSlugFromRemote normalizes https/ssh/.git forms.

Folds: don't force `sudo npm i -g` when the global prefix is user-writable
(nvm/fnm/volta/brew); use stdio:inherit for installs so `sudo apt` password
prompts actually reach the TTY.

Tests: server/routes.setupHardening.test.js (6 cases — slug normalization,
origin-match/mismatch guard, worktree fresh/stale-reuse/detached). Full
suite 60 passed / 0 failed. EADDRINUSE + stale-branch reuse also verified
end-to-end against a live server and a real git repo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@project7-interns project7-interns left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE

Epic Alignment: PASS

EPIC #967 Phase 3 calls for isolated setup/start hardening without steady-state runtime regression; PR #984 is confined to bin/quadwork.js, setup routes, server.listen, and setup tests.

Checked (evidence)

  • Structural gate: gh pr view 984 --json body,headRefOid -> head 3f7b3cc7feffd91d030a27204e72c67872e3dae4; required ## EPIC Alignment and ## Self-Verification are filled.
  • Context: issue #974 and epic #967 read live; scope is stale worktree branch reuse, missing-seed hard fail, reviewer-token setup, friendly EADDRINUSE, and origin mismatch guard.
  • Scope: gh pr diff 984 --name-only -> bin/quadwork.js, server/index.js, server/routes.js, server/routes.setupHardening.test.js; no agent spawn or steady-state runtime path changed.
  • Acceptance coverage: CLI origin guard at bin/quadwork.js:121, reviewer token write 0600 at bin/quadwork.js:650, stale branch reuse at bin/quadwork.js:690, seed hard-fail at bin/quadwork.js:711, server worktree helper at server/routes.js:3766, setup route use at server/routes.js:3905, EADDRINUSE handler at server/index.js:2123.
  • Tests: server/routes.setupHardening.test.js:51 covers slug normalization; :64 origin-match; :75 mismatch; :92/:105/:118 fresh/reuse/detached worktree paths. server/run-tests.js discovers every *.test.js, so this is included in npm test.
  • Riskiest part of this diff: reusing existing worktree-* branches; acceptable because both CLI/server prune stale registrations, attempt branch reattach first, and retain detached fallback for checked-out branches.
  • Kill-list: scanned all items — clean; raw scan found no added TODO/FIXME/HACK, debugger, sensitive values, or runtime mocks.
  • CI: gh pr checks 984 -> test pass, 54s.

Findings

None.

Decision

APPROVE. The implementation matches #974 and #967 constraints, covers both CLI and server setup paths where required, and has focused regression coverage for the highest-risk setup cases.

@realproject7

Copy link
Copy Markdown
Owner Author

APPROVE at 3f7b3cc7feffd91d030a27204e72c67872e3dae4

Full independent review — issue #974 Setup hardening (EPIC #967 Phase 3). Changes confined to setup/start paths (bin/quadwork.js wizard, server/routes.js /api/setup, server/index.js server.listen); no steady-state runtime, agent-spawn, or orchestrator change. Verified each fix:

  1. Stale-branch brick — CLI and server now check rev-parse --verify --quiet refs/heads/<branch>; existing branch → worktree prune + worktree add (re-attach), else create. Server logic extracted to createAgentWorktree(execFn injectable); detached fallback preserved. Re-runnable after a deleted worktree dir. CLI/server logic is consistent.
  2. Missing AGENTS.md seed — CLI now hard-fails (wtFailed + break) instead of silently skipping, matching the server route.
  3. Reviewer token — collected via askSecret, written mode 0600 (+ chmodSync), dir created via ensureSecureDir; blank input prints the exact Settings fallback path. No more empty-file reviewers.
  4. EADDRINUSEserver.on("error") prints a friendly "port N in use / run quadwork stop" and exit(1) for EADDRINUSE; rethrows anything else. Listen callback body preserved.
  5. Origin-mismatchensureGitHeadForSetup (CLI + server) compares git remote get-url origin (normalized via new repoSlugFromRemote) to the entered slug; clear error before any seeding. Guard skipped safely when origin is unreadable.

Folds: npmGlobalNeedsSudo() gates sudo on prefix writability (safe sudo default when prefix unknown); tryInstall switched to execFileSync(stdio:"inherit") so sudo/apt prompts reach the TTY.

Contracts checked: execFileSync/askSecret/ensureSecureDir all defined/imported in bin; repoSlugFromRemote regex verified against https/scp-ssh/ssh-url/.git/trailing-slash forms; new server/routes.setupHardening.test.js is auto-discovered by run-tests.js (recursive *.test.js).

Verification: node --check clean on all 4 files; ran the new test locally → 6/6 pass; full suite 60 passed, 0 failed (shared deps); CI test SUCCESS. No findings.

@realproject7

Copy link
Copy Markdown
Owner Author

APPROVE at 3f7b3cc7feffd91d030a27204e72c67872e3dae4

Re-issuing my verdict in the compliant format (comment-based approval — the shared reviewer GH identity blocks a formal Approve). Full independent review of issue #974 Setup hardening (EPIC #967 Phase 3); changes confined to setup/start paths, no steady-state runtime / agent-spawn change.

Checked (evidence)

  • Stale-branch reuse (defect 1)server/routes.js:3766-3778 createAgentWorktree checks rev-parse --verify --quiet refs/heads/<branch> (:3767); existing branch → worktree prune + worktree add, else create; detached fallback preserved. CLI mirror at bin/quadwork.js:690-700. Re-runnable after a deleted worktree dir.
  • CLI hard-fail on missing seed (defect 2)bin/quadwork.js:710-713: missing templates/seeds/<agent>.AGENTS.md now sets wtFailed + break instead of silently skipping (matches server seed route).
  • Reviewer token collection (defect 3)bin/quadwork.js:650-666: prompted via askSecret and written mode 0600 (+ chmodSync); blank input prints the exact Settings fallback path.
  • EADDRINUSE handler (defect 4)server/index.js:2123-2131: server.on("error") → friendly "port N in use" message + process.exit(1) for EADDRINUSE (:2124), rethrows anything else.
  • Origin-mismatch guard (defect 5)bin/quadwork.js:118-127 and server/routes.js:3715-3724: compare git remote get-url origin (normalized by repoSlugFromRemote, bin:103 / routes.js:3697) against the entered slug; clear error before any seeding; skipped safely when origin is unreadable.
  • Foldsbin/quadwork.js:87-99 npmGlobalNeedsSudo() gates sudo on prefix writability, used at :395; bin/quadwork.js:299 tryInstall uses execFileSync(stdio:"inherit") so sudo/apt prompts reach the TTY.
  • Testsserver/routes.setupHardening.test.js (6 cases: slug normalization, origin match/mismatch, worktree fresh/reuse/detached); auto-discovered by server/run-tests.js:29-35 recursive *.test.js.

Verification

node --check clean on all 4 files; ran the new test locally → 6/6 pass; full suite 60 passed, 0 failed (shared deps); CI test SUCCESS. No findings.

@realproject7 realproject7 merged commit ce7fc0c into main Jul 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[#S8] Setup hardening (stale-branch reuse, seed hard-fail, reviewer-token, EADDRINUSE)

2 participants