openpencil/docs
Kayshen-X 0feab42b4c feat(collab): allow cross-account collaboration
Peer admission required the remote ticket's subject to equal the local
account on both sides, so only devices of one account could pair. That
made the product multi-device sync rather than collaboration.

The subject equality was the authorization, so it is replaced rather than
deleted. `PeerIdentityPolicy` states which accounts a peer may belong to,
and the two sides get different answers because they do not have the same
ability to tell who the peer is:

- The owner accepting a guest admits any issued account. Nothing at this
  layer decides whether the guest joins — a human does, from the approval
  prompt, which is shown the verified identity and which the admission
  state machine makes unskippable (`Active` is reachable only through
  `OwnerAuthorized`).
- A guest joining by invite or relay admits any issued account, because
  the invite's signed locator already pinned the owner's Noise static key
  and that pin is checked before admission runs. The device is
  authenticated whatever account is behind it, which is what makes joining
  a stranger's session safe.
- A guest joining over an unpinned LAN discovery still requires the same
  account. A guest has no approval prompt — whatever it accepts, it
  accepts silently — and nothing else names the peer there: mDNS is
  spoofable and no key is known in advance. Relaxing it would let anyone
  on the segment holding any valid ticket pose as the owner, undetected.
  Opening this needs a way for the guest to confirm who it is joining,
  which is a user-facing decision, not a protocol change.

Relaxing the account relaxes nothing else: issuer, expiry, and the binding
to the observed Noise static key are unchanged, and renewal still refuses
any mid-session change of issuer, subject, device id, or key. Tests cover
that a foreign subject is admitted while each of those still rejects, and
the unpinned-LAN case has its own regression guard.

Also fixes two things this uncovered. The live MCP tests in op-host-desktop
drove the endpoint with raw HTTP and no token, so they failed with 401
after bc75c765b authenticated it — they now send the instance token, which
is also a live check that the authentication works. And two constant
relations in the transport config were runtime asserts that clippy rejects
as constant-valued; they are compile-time asserts now, which is what a
relation between constants should have been.
2026-08-01 13:01:24 +08:00
..
security feat(collab): allow cross-account collaboration 2026-08-01 13:01:24 +08:00
testing feat(collab): add authenticated p2p collaboration 2026-07-29 00:06:58 +08:00