Repository navigation
fix(daemon): let an installed version stand as its whole code identity - #2569
Conversation
Two installs of one published version signed their identical bytes differently, because the fingerprint is size:mtime and an installer stamps a fresh mtime on every file. The second client therefore read "code-signature mismatch" and replaced a daemon that already ran exactly its code, dropping the live session on it (#2458). An installed tree's version already fixes its bytes, so it now answers with no fingerprint and the version alone decides reuse. A source checkout, where code does move under an unchanged version, keeps the check. The predicate that tells the two trees apart moves beside the project-root walk it shares, and the takeover ladder moves beside the answer it consumes so the order lives in one place. The packaging gate proves the premise against a clean install: the published tree ships no src/daemon.ts. Closes #2458
|
Size Report
Startup median (7 runs, lower is better):
|
|
The signature bypass at daemon-launch-spec.ts:113 only checks the client. With an explicit shared --state-dir, a modified source checkout can start a daemon under the published version, and an installed client now reuses that modified code. #2458 scopes the bypass to both sides being installed. Record the daemon’s code origin or equivalent package identity and bypass fingerprints only for two matching installed versions; add the source-daemon → installed-client case. Checks are green, but this remains a code blocker at 5fef822. |
An installed client declined the code comparison on the strength of its own tree alone, which left whatever is already running unverified: a source checkout that shares an explicit --state-dir can publish any code it likes under a published version string, and the installed client would have run it (#2458 review). A daemon now records which tree it started from beside its signature, and the bypass is pairwise — it holds only where both sides say they are installs of that version. A checkout still judges a checkout by signature; a pair whose trees cannot match at all restarts the daemon rather than run code it cannot identify, which is also the rule a daemon too old to report an origin is judged by. Closes #2458
|
Fixed in A running daemon publishes Proof against two clean installs of one packed version, one shared The third line is the case you flagged. Two tests pin it ( Local: |
|
The previous blocker is fixed at edff907: fingerprint bypass now requires both client and daemon to be installed copies of the same version. The origin round trip, cross-origin rejection tests, and reported two-install field checks cover the failure case. Review is clean, all checks pass, and there are no merge conflicts. |
Summary
Two installs of one published version signed their identical bytes differently: the fingerprint is
size:mtime, and an installer stamps a fresh mtime on every file. The second client readcode-signature mismatch, replaced a daemon already running exactly its code, and dropped the live session on it.The bypass is pairwise, not one-sided. A running daemon now publishes
codeOrigin: 'installed' | 'checkout'beside its signature, and a client declines the comparison only where both sides are installs of the version they report — the only pair whose shared version already fixes the bytes both run. Every other pair is judged: checkout against checkout by signature as before, and a pair whose trees cannot match at all restarts the daemon rather than run code it cannot identify. A daemon too old to carry the field is judged by its signature, so nothing is trusted by silence.Users see
Replacing daemondisappear between two installs of one version;security-trust.mdstates what remains undetected (an install hand-patched under its own version).16 files, +498/-68 across two commits, one command family.
Validation
Commit
edff9074af.pnpm check:quick,check:layering,check:package,check:production-exportspass. The packaging assertion proves a clean install ships nosrc/daemon.ts.pnpm gate vitest-related <changed files>: 4228 passed; the one failure is the knownrunner-client.test.tssubprocess contention timeout (50/50 in isolation).--state-dir: install B reuses A's daemon pid silently; a checkout client against the installed daemon printscode origin mismatch (daemon installed, client checkout); an installed client against a checkout daemon printscode origin mismatch (daemon checkout, client installed).info.codeSignature !== await ...compare fails the Same published version installed twice replaces the daemon and drops the live session #2458 reuse case.Unresolved:
mutation-modelfails at merge-baseab3d11e069too (gestures.test.tsno longer reachesscroll-edge-state) — advisory-only per #1457, and its workflow is path-filtered away from this diff.