Relay: a new link CA without a new join (RL-34) #273

Merged
jcoffey-dev merged 1 commits from relay/link-ca-replace into main 2026-10-31 02:36:47 +00:00
Owner

RL-34: replace the link CA every relay shares, without a new join on each relay.

How it goes

  • The API. An update of any inbuxa:Relay with replaceLinkCa (start, finish or cancel), sent on its own, acts on the shared link CA. A new JMAP object for one action on a shared key was about 600 lines of wiring, so it stays on the relay. On create, or with other properties, it is refused; an action that changes nothing is refused too.
  • Start makes the next CA. Each node pushes its pin as nextLinkCaPin, and the relay trusts both CAs, listing them in status.linkCaPins.
  • Every relay shows linkCaReplacing and its own linkCa: current, both, or old (it needs a new join; this includes a join whose token named a CA since replaced).
  • Finish happens by itself once every enabled, joined relay says both. The link service then emits relay.link-ca-replaced (event 659). Each node takes a certificate from the new CA and links again.
  • On the relay, nextLinkCaPin: null pushed over a link on the next CA makes that CA its only one. It is saved in the identity first, every link on the old CA is ended, and the event is recorded. From the current CA, null is a cancel. A link on the next CA can't name another. So the old CA is only dropped once the new one is proven end to end, and a leaked old certificate stops working.
  • Fix: the link service now sends settings it has cleared as explicit null. The relay merges a push, so a setting left out stayed as it was. That was also a latent bug: a certificate removed on the server stayed on the relay.

Tests

  • cargo fmt --check; clippy (--tests) on the changed crates; the fork checks and their tests; expr-schema --check.
  • Relay unit and end to end tests (28), with RL-T26 covering both CAs trusted, the refusals, the promotion, and the old CA's link cut and refused.
  • system::relay::relay_tests and relay_link_tests against the real relay binary. The latter covers start, the finish by itself, the relay's identity on the new CA, and the relay still joined.
  • Unit test link_ca_states; features and services relay tests.

The console part (a "Replace link CA…" action and the per-relay state) follows in inbuxa-admin.

RL-34: replace the link CA every relay shares, without a new join on each relay. ## How it goes - **The API.** An update of any `inbuxa:Relay` with `replaceLinkCa` (`start`, `finish` or `cancel`), sent on its own, acts on the shared link CA. A new JMAP object for one action on a shared key was about 600 lines of wiring, so it stays on the relay. On create, or with other properties, it is refused; an action that changes nothing is refused too. - **Start** makes the next CA. Each node pushes its pin as `nextLinkCaPin`, and the relay trusts both CAs, listing them in `status.linkCaPins`. - **Every relay shows** `linkCaReplacing` and its own `linkCa`: `current`, `both`, or `old` (it needs a new join; this includes a join whose token named a CA since replaced). - **Finish happens by itself** once every enabled, joined relay says `both`. The link service then emits `relay.link-ca-replaced` (event 659). Each node takes a certificate from the new CA and links again. - **On the relay**, `nextLinkCaPin: null` pushed over a link on the next CA makes that CA its only one. It is saved in the identity first, every link on the old CA is ended, and the event is recorded. From the current CA, null is a cancel. A link on the next CA can't name another. So the old CA is only dropped once the new one is proven end to end, and a leaked old certificate stops working. - **Fix:** the link service now sends settings it has cleared as explicit null. The relay merges a push, so a setting left out stayed as it was. That was also a latent bug: a certificate removed on the server stayed on the relay. ## Tests - `cargo fmt --check`; clippy (`--tests`) on the changed crates; the fork checks and their tests; `expr-schema --check`. - Relay unit and end to end tests (28), with RL-T26 covering both CAs trusted, the refusals, the promotion, and the old CA's link cut and refused. - `system::relay::relay_tests` and `relay_link_tests` against the real relay binary. The latter covers start, the finish by itself, the relay's identity on the new CA, and the relay still joined. - Unit test `link_ca_states`; features and services relay tests. The console part (a "Replace link CA…" action and the per-relay state) follows in inbuxa-admin.
jcoffey-dev added 1 commit 2026-10-31 02:07:54 +00:00
Relay: a new link CA without a new join (RL-34)
ci / fork-checks (pull_request) Skipped
ci / build (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 9m26s
a33580cec7
An update of any inbuxa:Relay with replaceLinkCa, sent on its own, acts
on the link CA every relay shares: start makes the next CA, finish makes
it the link CA, cancel drops it. Every relay shows linkCaReplacing and
its own linkCa (current, both, or old: it needs a new join).

While one is under way, each node pushes the next CA's pin as
nextLinkCaPin, and the relay trusts both, listing them in
status.linkCaPins. Once every enabled, joined relay says both, the link
service finishes it (relay.link-ca-replaced, event 659): each node takes
a certificate from the new CA and links again. Its push of
nextLinkCaPin: null, from a link on the next CA, makes that CA the
relay's only one: saved in its identity, every link on the old CA ended,
and relay.link-ca-replaced recorded. From the current CA, null is a
cancel; a link on the next CA can't name another.

The link service now sends settings it has cleared as null: the relay
merges a push, so one left out stayed as it was. That also fixes a
certificate removed here staying on the relay.

A join whose token named a CA since replaced shows linkCa old.

Tested: the relay's end to end test (both CAs trusted, the refusals,
the promotion, the old CA's link cut and refused), the server's relay
link test against the real relay binary (start, finished by itself,
the relay's identity on the new CA, still joined), relay_tests, and a
unit test of the linkCa states.
jcoffey-dev merged commit 47dbb34514 into main 2026-10-31 02:36:47 +00:00
jcoffey-dev deleted branch relay/link-ca-replace 2026-10-31 02:36:47 +00:00
Sign in to join this conversation.