inbuxa Relay: the downstream's inbuxa:Relay object and its permissions #249

Merged
jcoffey-dev merged 1 commits from relay/downstream-object into main 2026-10-30 04:50:28 +00:00
Owner

The first server-side part of docs/spec/features/relay.md: the object an administrator uses to add a relay, and the keys the downstream links with. Nothing dials a relay yet; that's the link service, next.

inbuxa:Relay/get and /set under urn:inbuxa:jmap, kept in the fork's own store (key prefix E), never in the registry.

  • Properties: name, the address and link port to dial, enabled, sendThrough, inboundOnly, and settings. The settings are the relay's own RelaySettings, checked the way the relay checks them. A setting changes on its own as settings/<name>, null puts it back to its default, and an unknown name is refused.
  • Create returns the join token once. The first relay makes the downstream's keys, which every node shares: a link CA, whose key pin is in every token, and the key held mail is sealed to. Each relay gets its own recipient key.
  • rejoin: true on an update issues a new token for a relay that was reset. I added this to the spec; without it, a reset relay would have to be deleted and added again.
  • Certificate: smtpCertificate and smtpPrivateKey. The key reads back as ****, and **** written back keeps it.
  • Concurrent writes: updates are compare-and-set on the stored record, so a node recording a join and an administrator's edit can't overwrite each other.

Permissions 690-693: sysRelayGet, sysRelayUpdate, sysRelayQueueGet, sysRelayQueueUpdate. Administrators get all four, granted once to existing administrator roles. Nobody in a tenant gets any, and a tenant's request is refused.

Audit: every change is recorded, as for other objects. Any property ending in privateKey is now redacted, and a relay's before-values leave out its keys. Join tokens are only ever in responses, so they never reach the log.

Tested:

  • tests/src/system/relay.rs: tokens and the shared CA pin, validation, server-set properties refused, single settings and defaults, the masked key kept, a stale write refused, rejoin, a tenant administrator refused, destroy, and an audit log with neither the key nor a token.
  • Unit tests: validation, joining, the CA pin matching the certificate's key, and the stored form.
  • The audit, compliance and mail-rules system suites, and the unit tests of features, common, registry and jmap, all still pass.
  • rustfmt and the fork checks pass, and Cargo.lock gains no packages.

Not here yet: the link service (dialing, join completion, settings and recipient push, node link certificates), the relay's status on the object, inbuxa:RelayMessage, and ingest with session context.

The first server-side part of `docs/spec/features/relay.md`: the object an administrator uses to add a relay, and the keys the downstream links with. Nothing dials a relay yet; that's the link service, next. **`inbuxa:Relay/get` and `/set`** under `urn:inbuxa:jmap`, kept in the fork's own store (key prefix `E`), never in the registry. - **Properties:** name, the address and link port to dial, `enabled`, `sendThrough`, `inboundOnly`, and `settings`. The settings are the relay's own `RelaySettings`, checked the way the relay checks them. A setting changes on its own as `settings/<name>`, `null` puts it back to its default, and an unknown name is refused. - **Create** returns the join token once. The first relay makes the downstream's keys, which every node shares: a link CA, whose key pin is in every token, and the key held mail is sealed to. Each relay gets its own recipient key. - **`rejoin: true`** on an update issues a new token for a relay that was reset. I added this to the spec; without it, a reset relay would have to be deleted and added again. - **Certificate:** `smtpCertificate` and `smtpPrivateKey`. The key reads back as `****`, and `****` written back keeps it. - **Concurrent writes:** updates are compare-and-set on the stored record, so a node recording a join and an administrator's edit can't overwrite each other. **Permissions** 690-693: `sysRelayGet`, `sysRelayUpdate`, `sysRelayQueueGet`, `sysRelayQueueUpdate`. Administrators get all four, granted once to existing administrator roles. Nobody in a tenant gets any, and a tenant's request is refused. **Audit:** every change is recorded, as for other objects. Any property ending in `privateKey` is now redacted, and a relay's before-values leave out its keys. Join tokens are only ever in responses, so they never reach the log. **Tested:** - `tests/src/system/relay.rs`: tokens and the shared CA pin, validation, server-set properties refused, single settings and defaults, the masked key kept, a stale write refused, rejoin, a tenant administrator refused, destroy, and an audit log with neither the key nor a token. - Unit tests: validation, joining, the CA pin matching the certificate's key, and the stored form. - The audit, compliance and mail-rules system suites, and the unit tests of `features`, `common`, `registry` and `jmap`, all still pass. - rustfmt and the fork checks pass, and Cargo.lock gains no packages. **Not here yet:** the link service (dialing, join completion, settings and recipient push, node link certificates), the relay's status on the object, `inbuxa:RelayMessage`, and ingest with session context.
jcoffey-dev added 1 commit 2026-10-30 04:41:34 +00:00
inbuxa Relay: the downstream's inbuxa:Relay object and its permissions
ci / fork-checks (pull_request) Skipped
ci / build (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 8m6s
6e6c6ff16f
The first server-side part of docs/spec/features/relay.md ("Registry
objects", "Joining and reset"):

- inbuxa:Relay/get and /set under urn:inbuxa:jmap, kept in the fork's
  subspace under E (crates/features/src/relay). A relay has its name,
  the address and link port the downstream dials, enabled, sendThrough,
  inboundOnly, and the settings pushed to it, which reuse the link's own
  RelaySettings and are checked the way the relay would check them.
  Settings change one at a time as settings/<name>; null puts one back
  to its default; an unknown name is refused.
- A create returns the join token once. The first relay makes the
  downstream's keys, shared by every node: a P-256 link CA, whose key
  pin goes in every token, and the X25519 key held mail is sealed to.
  Each relay gets its own recipient key. An update with rejoin: true
  issues a new token for a relay that was reset, and forgets its pinned
  key and recipient key (the spec gains this paragraph).
- smtpCertificate and smtpPrivateKey: the key reads back as ****, and
  **** written back keeps it. The audit log redacts any property ending
  in privateKey, and records a relay's before-values without its keys.
- Updates are compare-and-set on the stored bytes, retried, so a node
  recording a join and an administrator's edit can't overwrite each
  other.
- Four permissions, ids 690-693 (enum and schema labels):
  sysRelayGet/Update and sysRelayQueueGet/QueueUpdate. Administrators
  get all four, granted once to existing administrator roles; nobody in
  a tenant gets any, and a tenant is refused.
- Privacy catalog entry for inbuxa:Relay.

tests/src/system/relay.rs: tokens decode with one CA pin for every
relay, validation, server-set properties refused, single settings and
defaults, the masked key kept, the stale write refused, rejoin, a tenant
administrator refused, destroy, and an audit log without the key or a
token.
jcoffey-dev merged commit ec4dc0cead into main 2026-10-30 04:50:28 +00:00
jcoffey-dev deleted branch relay/downstream-object 2026-10-30 04:50:28 +00:00
Sign in to join this conversation.