Skip to content

v12.6 — the passkey is gone, the installer never stops, and the product stops lying about itself

Choose a tag to compare

@paracoding-ai paracoding-ai released this 05 Sep 05:31
· 8 commits to main since this release

103 files. 27 paths move, one is removed (control-plane/src/locked.html); the other 75 are byte identical to 12.5. MANIFEST.txt lists every file and its digest. Cut deterministically from source commit bf9255e5; the same image digest served the dev lane at 100% before it served production.

WebAuthn is deleted, not disabled

IAP at the front door, a Google identity on the approver allow-list, then a session cookie with a TTL. No passkey on top of that. Fourteen /api/webauthn/* routes, ten helpers, five WA_RP_* constants, PC_REQUIRE_PASSKEY and every branch it guarded, the @simplewebauthn dependency on server and console, and locked.html are gone in one commit. There is no switch that re-arms it. /api/webauthn/status becomes /api/auth/status. Route baseline 88 → 74 registered, 17 → 16 public; the audit passes against it. The auth-path diagram is re-rendered.

What stays, named so nobody mistakes it for a leftover: the gate_session cookie under WA_SESSION_SECRET (not rotated — live sessions survive the upgrade), and the executor's own gate-exec/pcwebauthn.py behind PC_REQUIRE_ASSERTION=0, which is a separate service with a separate deploy and gets its own release. install.sh therefore still creates the webauthn-creds secret the executor reads by name. The release build now greps the emitted tree for the whole passkey vocabulary and refuses to build on a hit, with those executor-side files as asserted allowances that must still match.

The installer prompts for nothing

Step 6d/10 stopped on stdin asking for more allowed Google accounts. It now seeds the account running the install and moves on. --approver-emails a@b,c@d and PC_APPROVER_EMAILS cover the non-default case (validated, de-duplicated, flag beats env, in --help); the Settings page adds and removes accounts afterwards. Note: re-running install.sh with --approver-emails replaces the list; it does not merge with accounts added in Settings. The only stdin read left is the opt-in --plan confirmation.

The product tells the truth about itself

Fifteen strings sent to a model or returned as tool results said a human approves each staged job "with their passkey", or that a job "sits on the gate until a human approves it". Under PC_AUTO_APPROVE=1 a staged job is KMS-signed and executed in the same call; under =0 it sits at pending where nothing comes to approve it. All fifteen now say what happens, the journal line for a staged job names the posture instead of an approver, a refused lockout-class job relays the executor's rule ids and reasons instead of rule(s): unnamed, and two runbooks that claimed protections the system does not have now say what is true and what actually bounds it.

put_file cannot write a corrupt binary

Models corrupt long base64 in tool arguments (measured: one wrong character at 10,011; a dropped one at 60,000; a 64KB chunk that degenerated into filler and landed, in a store with no delete). The decoded size is now bounded at 40,000 bytes, the refusal names the byte-exact route (POST /git/blob then git_propose uploaded{blob_oid, sha256}), an optional sha256 over the decoded bytes is checked, and the payload is re-encoded and compared.

One temporary measurement, labelled as such in the source

One log line per POST /mcp records whether an Mcp-Session-Id header was present, a 12-hex hash of it, and whether it changed — never the value, never the session key. Binding a chat on that header unmeasured would trade a paste-loss bug for a cross-chat identity leak.

Proven before publishing

gen.py cut twice, diff -r zero. Bus gate 0 (negative control 4/4). Passkey gate 0 (negative control 7/7, four asserted allowances). Route audit 74 / 58 guarded / 16 public. Dev lane on this digest: console 51 routes, mcp 28, /api/auth/status 200, /api/webauthn/* 404, clean boot. Then production, same digest.

Apache-2.0. Your project, your bill, your key.