Repository navigation
Desk v0.7.0
A desk's decision record can now be handed to someone outside, and Desk holds the record to what was handed over. Jobs runs are signed with a key of Runner's own, their chain of runs can be handed over the same way, and a Jobs record beside the decision record checks that chain with the runtime's own verifier over Desk's private copy. The pinned Runtime, Runner and Gateway are unchanged from v0.6.0.
Updating from v0.6.0 needs no backup step: nothing here changes a desk's jpack.json, a Jobs store or a lock. Updating from v0.5.x or earlier: see v0.6.0's notes and back up every desk's Jobs store first.
What changes for you
- Hand-over (Admin → Project → Decision record). You add holders by a label and a channel in your own words. For each holder, Download checkpoints saves the runtime's checkpoint lines after that holder's cursor, as the exact bytes the runtime printed; Confirm records that the file went to the holder, and only then does the cursor move. The decision record then holds the trail to what was handed over, and its coverage says which records a held checkpoint witnesses.
- Jobs runs are signed. Each desk's Runner is started with a signing key of its own, kept by Desk outside the project. Help & About → Gates shows Runner's public key, or why runs are not signed. A run's version-5 export carries its signature;
jpack-runner verify-run --public-key <key> --require-signedchecks it. - The Jobs chain in hand-over. Where a desk has a Runner, each holder has a second row, "Jobs runs", with its own cursor: the checkpoints of Runner's chain of runs, from Desk's private copy of it.
- Jobs record (Admin → Project, after the decision record). On request, Desk takes a fresh private copy of Runner's chain of runs and runs
jpack audit verify --trail <copy>with the Jobs checkpoints it holds for each holder. It shows the runtime's status, coverage, findings and sentences verbatim, Runner's key state, and offers the chain for download. It never runs on a timer. - Key rotation follow-ups. The list of public keys is checked again immediately before the next key is put in place; a rotation the runtime did not write now says Desk kept the current key; a failure inside a rotation leaves the key lock released.
What a hand-over establishes, and what it does not
- A held checkpoint, kept by a holder the operator does not control: the records up to it are the ones that existed when it was handed over. It establishes nothing after it, and nothing about a holder who did not keep every checkpoint, or about when it was made.
- Desk's record of hand-overs: nothing to anyone but you. You keep it and can change it. The decision record says so beside the list: "This is Desk's own record. You keep it, and you can change it, so it proves nothing to a holder or to anyone else. Only the holder's own copy counts."
- A Jobs run's signature: a holder of Runner's key signed that record. It binds nothing against the operator, who holds the key. The chain of runs itself carries no signature; the Jobs record passes no key, and says that each run's signature is checked by
verify-runon that run's export. - Desk's verification, decision record and Jobs record alike: what your own copies show, with the keys and checkpoints you keep. It is not evidence to anyone who does not trust you.
Hand-over by download or copy (#241, ADR-0010 PR 5)
- Holders and Desk's record live in
<project>/.desk-private/handover/, owner-only, refused by the file API, in no backup, like the trail. GET /api/audit/checkpoints?holder=<id>runsjpack audit checkpoint --since <cursor> --limit 300in the human form, batch after batch, and answers the concatenated standard output asapplication/jsonl, never re-encoded; a download cuts at the record the first call read, so every byte is the runtime's.- A confirmation regenerates the same bytes and compares digests: records added since, a rewrite, another trail identity or a replayed confirmation are refused as stale, and nothing is written.
- Each holder's held file is read whole and held to the holder's record (complete lines, the record's trail, increasing sequences, the last sequence and the digest) before it is passed to
--expect; one that does not match is named and passed to nothing. An unreadable record is said as such, never as "no holders". - Desk's lists are written within the 64 KiB they are read with; a holder past that bound is refused in plain words.
Runner's signing key (#232, ADR-0010 row 11)
<Desk configuration folder>/secrets/signing/runner/<name>.seed, under the same custody as the desks' keys, made at Runner's start where none is kept, under the one signing lock. A key is named to Runner only where, under the lock, no creation marker is left, the seed and its list agree, and the runtime reads the seed under its own rules.- A key the runtime or Runner refuses, or a lock that is held, never refuses or fails a run: Runner is started again without the key, the run is recorded unsigned, and Gates says why.
The Jobs chain, and the Jobs record (#254, ADR-0010 rows 8b and 12)
- Desk's private copy of
GET /v1/run-chainis held whole within Desk's bound and replaced on each use; a transfer that ends early is an error, never a report over a shorter chain. - The Jobs cursor, held files and record are kept apart from the decision record's, by chain.
- The Jobs record's sentence: "Desk ran this over its own copy of the runner's chain of runs, with the checkpoints it keeps. It shows what a holder would see. It is not evidence to anyone who does not trust this installation."
Also in this release
- The web suite holds under machine load (#242); the mutation harness ends a hung suite's whole process tree at its bound (#245).
Verification
CI ran frontend behaviour, all twelve locale catalogues, the Go chassis tests, the Jobs companion against the pinned Runner and Runtime, the local Gateway checks and the native archive builds.
- Review: each change to keys, hand-over or verification had one cross-vendor round, recorded on its pull request with a disposition for every finding.
- #232 (on its predecessor #229): two HIGH findings on the key's custody lock, fixed before merge.
- #241: one HIGH (a held file passed on its metadata alone) and two MEDIUM, all fixed before merge.
- #244: two MEDIUM, fixed before merge.
- #254: one HIGH (the check after a confirmation of the chain joined a check already in flight, so the panel could show the earlier report) and two MEDIUM, all in the page, fixed before merge.
- Mutation checks: every safeguard has a row in
scripts/mutation-check.sh. #232: 29 rows caught before merge, 212 of 214 after (the two others hang or panic the suite rather than fail, #252). #241: 83 new rows and 198 of 199 existing rows caught before merge, 29 of 29 of the review round's. #244: 65 Go and 36 web. #254: 69 new rows (34 Go, 35 web) and 17 existing rows in changed lines, all caught before merge; the 163 other rows in touched files run after merge.
Not exercised: macOS and Windows for key custody and hand-over; two Desk processes on one project at once; a holder who does not keep the file; the page in a real browser beyond jsdom; a native speaker's reading of the new messages.
See installation and updates and release verification.
| Component | Pin |
|---|---|
| Runtime | v0.27.1 |
| Runner and source worker | v0.6.0 |
| Gateway and required Desk adapters | v0.9.1 |
Platforms
This release contains complete Linux/amd64, macOS Apple Silicon (arm64), and
macOS Intel (amd64) archives. All three archives were built and smoke-tested on
native GitHub-hosted runners before publication; neither macOS archive is merely
cross-compiled. Component versions come from the same release lock.
macOS executables are not Developer ID signed or notarized. Gatekeeper may block
downloaded executables; verify the release and checksums, then use Apple's
Privacy & Security → Open Anyway procedure
for the blocked executable. Native CI does not exercise these dialogs. The Codex
subscription subprocess bridge remains Linux-only.
No Windows archive is published. Windows execution is untested, and the managed
installer supports only Linux and macOS.