Tokens: one keyring item per token, read back; the bridge says a locked keyring; token check
check / check (push) Canceled after 0s

On the live books a reconnected bridge got no token from a keyring that
couldn't be read, was told to "make a token", and after
`token create --replace` kept on with the new token in memory while
`download` read a revoked one from the keyring.

- tokens.rs INVARIANT 4: keeping a token removes every item for its
  account in every collection, makes one and reads it back; reading finds
  every item and, finding several, refuses with how to keep one again; a
  locked or unreachable keyring is KeyringError::Unavailable, never
  "no token". The logic is shared by the OS keyring and the test files
  (now a folder per collection a test can lock, make unreachable, or
  plant a second item in).
- make_token reads the token back before saying anything, or revokes it.
- The bridge tells the agent the keyring is locked or unreachable and the
  token is fine (or that it holds several items), never to make a token;
  it reads the keyring again before every new session, even with a token
  held.
- `wanderbooks token check --book ID [--name N]`: whether the token kept
  here is the books' live one, asked by its SHA-256 (admin op
  token_check), never its text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
This commit is contained in:
swaitsandClaude Opus 5.5 committed 2026-10-22 04:17:22 -06:00
1 parent 321b94562a
commit d24653558c
9 files changed
+871 -95

No files matched your search

+23
View File
@@ -491,6 +491,29 @@ recorded once with refusals, a damaged token log refusing every agent),
`open_while_held.rs` (the bridge picking up a token made mid-session),
`setup.rs` (the passphrase prompts, at a real terminal).
**One keyring item per token (2026-10-22).** On the live books a
reconnected bridge got no token from a keyring that couldn't be read,
was told to "make a token", and after `token create --replace` ran on a
token the keyring no longer gave while `download` read a revoked one.
The test keyring is now a folder per collection that a test can lock,
make unreachable, or plant a second item in (tokens.rs INVARIANT 4), and
the keeping and reading logic is shared with the OS keyring's.
`tokens.rs` unit tests (two items are said, never one of them given;
keeping removes every item first and reads back; a keyring that keeps
something else is refused; locked or unreachable is an error, never no
token), `bridge.rs` `a_keyring_that_cant_be_read_is_said_never_make_a_token`
and `each_new_session_reads_the_keyring_again` (against the scripted
server), `local.rs` `a_token_check_says_whether_the_text_is_the_live_one`,
`admin.rs` (`token_check` carries a hash, never a text), and
`open_while_held.rs`
`token_check_one_item_per_token_and_a_keyring_that_cant_be_read` (`token
check`'s every state end to end, a planted second item refused by
`check` and by the bridge and repaired by `--replace`, a bridge with an
unreachable keyring told so, a token the keyring can't keep revoked
again). The real Secret Service stays behind the ignored
`os_keyring_keeps_and_forgets`: tests never touch this computer's
keyring.
**Slice 5, files in and out.** Uploads by hash and size, exports handed
over by the server (`ledger-store` `uploads.rs`, `exports.rs`; `ledger-mcp`
`tools/files.rs`; `wanderbooks upload`/`download`): unit tests (expiry,