Skip to content

LIM-2424: PR #3 review fixes (local + hosted) and agent connection for local workspaces - #5

Closed
allsmog wants to merge 5 commits into
agent/LIM-2424-l0-fixesfrom
agent/LIM-2424-l0-review-fixes
Closed

allsmog wants to merge 5 commits into
agent/LIM-2424-l0-fixesfrom
agent/LIM-2424-l0-review-fixes

Conversation

@allsmog

@allsmog allsmog commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #4, which is stacked on #3. These are the fixes from Sean's PR #3 review (request-changes, 23:44Z), made in Sean's session at his request, plus the agent connection for local workspaces he asked for. The mini was asked to hold off the same items.

1. Local-merge items (9b56a56)

  • 14, CSRF: every custom write needs JSON from this Host and Origin. A text/plain form from another localhost port gets 415.
  • 15, cross-tab: a custom /api/state names its workspace (Northstar's view is unchanged). A tab drops any state that isn't its own workspace and role, so it never renders another workspace's data.
  • 16: test-tenancy refuses the main checkout and a busy port before it deletes ./data/state.json.
  • 17: a failed /api/session shows "Couldn't reach Align" with Try again, not "Loading Align..." forever.
  • 18: the passcode card needs "I've saved all three passcodes" before the open link, which opens a new tab.
  • 19, Lows:
    • a primitive JSON sign-in body is 400 again;
    • the size check runs before the audit archive append;
    • readAuth gives 500 for EMFILE or a malformed file, never "Session ended";
    • a failed event append no longer loses the passcodes;
    • workspace login says "gone" vs "couldn't reach, try again", fits a phone, and notes a demo session;
    • /setup refuses a workspace session up front;
    • /new keeps the code field when its config fetch fails.

2. Hosted items (a16c3aa)

  • 1, Northstar is off when hosted:
    • / and /setup redirect to /new;
    • Northstar sign-in is 404 and Northstar tokens are ignored;
    • the Northstar store refuses every read and write;
    • ALIGN_NORTHSTAR_PUBLIC is refused at startup.
  • 2: .dockerignore is an allowlist of the app's own source, and no AI key is used when hosted.
  • 3, a refused start exits. On the image, next start logged the register() error and kept serving 500s, so instrumentation.ts now exits 1. proxy.ts answers 503 if a refused process is ever kept up.
  • 4: passcode hashing runs at most 2 at a time, with 8 waiting (429 beyond), so a burst can't stall other workspaces.
  • 5: backoff is per workspace, role and client (Fly-Client-IP), counted before the hash, and only for workspaces that exist.
  • 6, creation:
    • single-use invite codes (ALIGN_SIGNUP_CODES), spent under the creation lock after the cap check and stored as hashes;
    • wrong codes limited per client;
    • the shared code and ALIGN_CREATE_PER_HOUR are refused when hosted.
  • 7: proxy.ts is an allowlist of tester routes, so every other path is 404 when hosted. H6 checks every route in app/.
  • 8: scripts/ws-admin.mjs lists and deletes (one, or all with --yes) the way the app does, and is safe while serving. Volume snapshots are documented.
  • 9: /new shows the notice: a test server, nothing confidential, the deletion date (ALIGN_DELETE_BY). The passcode card repeats the date. Shruti owns the wording.
  • 10: a two-stage image with production dependencies and the build output only. The server is PID 1, running as node.
  • 11: test-tenancy builds once and runs every phase on next start.
  • 12:
    • pid file on the volume, 0600;
    • files 0600 and folders 0700;
    • a Fly health check with the edge headers;
    • Fly-Client-IP required;
    • hosted logs carry only error names;
    • --ha=false documented.
  • 13: docs/HOSTING.md rewritten to match, including the go-C smoke test.

3. Agent connection for local workspaces (0af316d, 2331da3)

  • Tokens. A workspace's leadership mints an agent token per repo (POST /api/workspaces/agent-token). Minting is that repo's capture consent and leaves an audit row. The token is HMAC-signed, tied to the passcode epoch (a bump revokes it), and can't be read as a session.
  • What it opens. With the token, capture, MCP and wake-ups (poll, ack, stream) read and write that workspace only. Workspace approvals are tagged, and never reach the default store's wire view.
  • The launcher. scripts/agent-session.sh has a workspace mode: ALIGN_WORKSPACE plus its leadership passcode.
  • Hosted. None of this exists when hosted.

Gates

  • scripts/test-all.sh: 15 of 15. Tenancy is 122/122 on production servers. It adds:
    • all 19 startup refusals;
    • the allowlist against every route;
    • Northstar off, including a forged token;
    • invites and per-client limits;
    • the sign-in burst, the notice and the delete tool;
    • W1 to W6 for workspace agents;
    • R12 to R19, with a two-tab browser check;
    • spec tests 9, 18 and 20, stricter A2, A6 and A7, and browser cases U1 (no pre-login poll) and U2 (session ended) (d1d0fc7).
  • scripts/test-image.sh: 13 of 13 on the real image. It needs Docker, so it isn't in test-all. It checks:
    • nothing beyond the app in the image;
    • a misconfigured container exits 1;
    • wrong Host 421, http 403, no edge header 403;
    • / redirects, and Northstar and agent routes are 404;
    • PID 1 is the server as uid 1000;
    • the pid file is 0600.
  • Northstar UI text: 72 of 72 files identical to 850971e, now a test-all step (ui-northstar, on a production build).

Live runs (Claude Sonnet in tmux, in physical-ai, planning-only by the launcher's deny list and prompt)

  • CPSec as a real workspace (11:04 PM):
    • the agent read "not agreed" through its agent token;
    • the agreement went through with the workspace's own passcodes, with five conditions (278 characters);
    • Align woke it at 11:05:13 PM, and it replanned inside all five.
  • Align's record: delivered at 06:05:13Z and acted on at 06:05:16Z, in the workspace's own state. No Northstar state was written, and no repo file changed.

Still open

  • The clinical-screening-window fixture ("label it fictional; it keeps confirm") comes from Shruti's interview, so its wording is hers.
  • Before the first tester: the live smoke test on Fly and the snapshot retention setting. Both need Sean's deploy go.

… production build

From Sean's PR #3 review (comment of 23:44Z):
- 14 CSRF: bodyFor requires JSON from this Host and Origin for every
  custom write. A text/plain form from another localhost port is 415.
- 15 Cross-tab: a custom /api/state names its workspace (appended last;
  Northstar's view is unchanged). useAlign drops any state whose workspace
  or role differs from this tab's and asks /api/session again, so a tab
  never renders another workspace's data.
- 16 test-tenancy refuses the main checkout and a busy port before it
  deletes ./data/state.json, as its header already claimed.
- 17 A failed /api/session shows "Couldn't reach Align" with Try again,
  not "Loading Align..." forever.
- 18 The passcode card needs "I've saved all three passcodes" before the
  open link, which opens a new tab so the card stays.
- 19 Lows:
  - a primitive JSON sign-in body is 400 again, not 500;
  - writeCustom checks size before archiving audit rows, so a refused
    write no longer appends duplicates;
  - readAuth returns null only for a deleted workspace; EMFILE or a
    malformed auth.json is a 500, not a false "Session ended";
  - a failed event append after create no longer loses the passcodes;
  - workspace folders 0700, files 0600 (from 12);
  - workspace login: "gone" vs "couldn't reach, try again", phone-width
    layout, and a notice when the browser holds a demo session;
  - /setup tells a workspace session up front that it can't replace
    the demo;
  - /new keeps the signup-code field when its config fetch fails.
- 11 test-tenancy builds once and runs every phase on next start, so
  the hosted refusals are checked as production runs them (they hold).

Tests: tenancy R12, R14, R15 (API, plus a two-tab browser check), R19.
test-all 14/14, tenancy 82/82 on production servers.
- 1 Northstar is off when HOSTED=1: / and /setup redirect to /new,
  Northstar sign-in is 404, Northstar tokens are ignored, and the
  Northstar store refuses every read and write. ALIGN_NORTHSTAR_PUBLIC is
  gone (refused at startup).
- 2 The AI key can't ship or be used: .dockerignore is an allowlist of
  the app's own source, and apiKey() is null when hosted.
- 3 A refused start exits: `next start` logged a register() error but
  kept serving 500s (checked on the image). instrumentation now exits 1,
  and proxy.ts answers 503 if a refused process is ever kept up.
- 4 Passcode hashing runs at most 2 at a time with 8 waiting (429
  beyond), so a sign-in burst can't stall other workspaces' file reads.
- 5 Login backoff is per workspace, role and client (Fly-Client-IP when
  hosted), counted before the hash, and only for workspaces that exist.
- 6 Hosted creation needs single-use invite codes (ALIGN_SIGNUP_CODES),
  spent under the creation lock after the cap check and stored as
  hashes. Wrong codes are limited per client; the create bucket token is
  taken after the cap check; ALIGN_CREATE_PER_HOUR and the shared
  ALIGN_SIGNUP_CODE are refused when hosted.
- 7 proxy.ts is an allowlist of tester routes: every other path is 404
  when hosted, so a future route is closed by default (H6 walks app/).
- 8 scripts/ws-admin.mjs lists and deletes workspaces (one, or all with
  --yes) the way the app does, safe while serving; snapshots documented.
- 9 /new states the test server, no confidential details, and the
  deletion date (ALIGN_DELETE_BY, required); the passcode card repeats it.
- 10 The image is two-stage: production deps and build output only, no
  data/, sparta/, agent/ or test scripts; the server is PID 1 as node.
- 12 Pid file on the volume (0600); Fly health check with the edge
  headers; Fly-Client-IP required; hosted logs carry only error names;
  `fly deploy --ha=false` documented.
- 13 docs/HOSTING.md rewritten to match, with the go-C smoke test.

Tests: tenancy hosted phase now covers all 19 startup refusals, the
allowlist against every route, Northstar off (incl. a forged token),
invites, per-client backoff, the sign-in burst, the notice and the delete
tool (107/107 on production servers). scripts/test-image.sh checks the
real image (13/13 locally; needs Docker, not in test-all).
test-all 14/14.
…ace agent tokens

Before this, only the default store (Northstar or a /setup scenario) had
an agent connection; a /w/<id> workspace had none.

- lib/agent-token.ts: agt.<payload>.<HMAC> tokens, signed like sessions
  but with kind "agent" and no actor (neither reads as the other). Each
  names one workspace, harness and repo, and carries the workspace's
  passcode epoch, so an epoch bump revokes it. Null when hosted.
- POST /api/workspaces/agent-token: that workspace's leadership only,
  JSON from this origin. Records the repo's capture consent and an audit
  row (harness and repo only), and returns the token once.
- Capture: a valid token routes the event into its workspace (its repo
  only); a revoked agt. token is 401, never a Northstar event.
- MCP: the server token reads the default store; an agent token reads
  only its workspace, for every tool.
- Wake-ups: poll, ack and stream use the token's workspace. Approvals in
  a workspace emit an event tagged with its id; the default store's wire
  view never shows them (tenancy B17 unchanged).
- Hooks send ALIGN_AGENT_TOKEN when set; scripts/agent-session.sh has a
  workspace mode (ALIGN_WORKSPACE + its leadership passcode) that mints
  the token and wires it in.
- Hosted: none of these routes exist (proxy allowlist; H6 includes the
  new route).

Tests: tenancy W1 to W6. test-all 14/14, tenancy 115/115.
@allsmog allsmog changed the title LIM-2424: PR #3 review fixes (local merge first, hosted next) LIM-2424: PR #3 review fixes (local + hosted) and agent connection for local workspaces Oct 22, 2026
@allsmog
allsmog marked this pull request as ready for review October 22, 2026 06:06
…r A2/A6/A7, UI cases, UI gate

- Spec section 11 test 9: a Northstar leadership token can't export,
  rotate or delete a workspace (no such routes in this build; every call
  fails closed) and data/ is unchanged.
- Test 18: at the size cap a growing write is 413 and changes nothing,
  with no audit rows archived; below it, 1500 audit rows trim to the
  newest 1000 and 501 go to the archive.
- Test 20: an 850971e Northstar state.json loads, and a pure read
  leaves it byte-identical.
- A2 now checks the write succeeds and lands in A; A6's reverse
  direction checks the Northstar actions succeed; A7 checks all 40
  statuses and that each workspace records all 8 actor/action touches
  (the old action spread gave each role only two of the four).
- U1: /w/<id> before sign-in never requests /api/state. U2: a session
  ended server-side says so in the page.
- ui-northstar (new test-all step): Northstar's rendered UI text for
  every role, view and stage, against 850971e's 72 files, on a
  production build.

test-all 15/15, tenancy 122/122, Northstar UI 72/72.
@liminalshruti

Copy link
Copy Markdown
Collaborator

Landed via #9: merge commit 95c43be on main (Oct 23 03:03Z), whose second parent is Sean-approved 3cd7f8a. This PR's head is an ancestor of 3cd7f8a, so all its commits are on main. Closed rather than merged separately, per the founder ruling on LIM-2424.

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.

2 participants