docs(arch): multi-credential PeerEntry, resolve OQ-29, dissolve OQ-35, add OQ-37
Amend ADR-030 with three changes from the auth-type analysis: 1. PeerEntry is now multi-credential: fingerprints: Vec<String> (Ed25519 and/or X.509) + auth_token_hash: Option<String> (bearer token). All resolve to the same peer_id. A peer that authenticates via Ed25519 today and via auth_token tomorrow gets the same PeerId. The 'peer bearer vs auth bearer' distinction was wrong — the correct framing is the three credential types (Ed25519, X.509, bearer token) and whether the token needs a stable logical id across rotation (PeerEntry) or not (ApiKeyEntry). 2. Fingerprint normalization (§6): quinn extracts the raw Ed25519 public key from the SPKI cert and formats as ed25519:<hex>, matching iroh. The same key has the same fingerprint regardless of transport. X.509 fingerprints stay as SHA256:<hex of DER>. This also simplifies the coming WebTransport relay work. 3. The 'API keys' section is replaced with 'Bearer tokens' — correctly framing the three auth types and the two bearer-token paths (PeerEntry.auth_token_hash vs ApiKeyEntry). Resolve OQ-29 (CallClient TLS client-auth): wire quinn client-auth (present Ed25519 key as raw public key client cert — the server-side extraction already works); key-type-aware server cert verification (raw key = fingerprint match, X.509 = CA verification via WebPkiServerVerifier — AcceptAnyServerCertVerifier is only safe for raw keys); fingerprint normalization. The iroh path already works (RFC 7250 raw keys, both sides exchange automatically); the gap was quinn-only. Dissolve OQ-35: the 'API key asymmetry' framing was wrong. PeerEntry supports multiple credential paths; ApiKeyEntry is for tokens that ARE the identity. Add OQ-37: X.509 outgoing-only case — the three auth types and how X.509 server identity fits the peer model. Not blocking the ADR-029 migration; downstream (HTTP crate phase). Update auth.md, config.md, client-and-adapters.md, call/README.md, core/README.md, open-questions.md, README.md, and call_client.rs source comment. Workspace green: 326 tests pass, build clean.
This commit is contained in:
@@ -57,12 +57,14 @@ Structured RPC over QUIC: operations, request/response, streaming subscriptions,
|
||||
| OQ-26 | OperationAdapter error type (AdapterError variants) | **resolved** | `DiscoveryFailed`, `SchemaParse`, `Transport`, `Unauthorized`, `SamePeerCollision`; `#[non_exhaustive]` |
|
||||
| OQ-27 | from_call re-import trigger | **resolved** | Auto-re-import on connection establishment; `refresh()` is a feature addition |
|
||||
| OQ-28 | from_call namespace collision | **resolved** | Same-peer collision = error; cross-peer dissolved by ADR-029 (separate sub-overlays) |
|
||||
| OQ-29 | CallClient TLS client-auth | **open (high, load-bearing on ADR-030)** | NOT "additive" — activates the `PeerEntry` fingerprint → `peer_id` path. Requires decision before ADR-029 migration. |
|
||||
| OQ-29 | CallClient TLS client-auth | **resolved** | Wire quinn client-auth; key-type-aware server cert verification; fingerprint normalization |
|
||||
| OQ-30 | `PeerRef::Any` routing policy | **resolved** | Insertion-order first-match; richer routing is a feature extension |
|
||||
| OQ-31 | `services/list-peers` re-export semantics | **resolved** | Opt-in `services/list-peers`; `services/list` is "own ops only" |
|
||||
| OQ-32 | Multi-hop federation | open (feature extension) | One-hop model is the commitment; multi-hop is a feature extension, not a deferral |
|
||||
| OQ-33 | PeerId — crypto identity vs stable logical id | **resolved** (ADR-030) | `PeerId = Identity.id = PeerEntry.peer_id` (stable across key rotation) |
|
||||
| OQ-34 | Persistent peer registry | **resolved** (ADR-030+033) | Core trait + in-memory default; persistence adapters are separate crates |
|
||||
| OQ-35 | ~~API key asymmetry~~ | **dissolved** | `PeerEntry` supports multiple credential paths; `ApiKeyEntry` is for tokens that ARE the identity |
|
||||
| OQ-37 | X.509 outgoing-only case | open | Three auth types; how X.509 server identity fits the peer model. Not blocking. |
|
||||
|
||||
## Key Design Principles
|
||||
|
||||
|
||||
@@ -631,15 +631,12 @@ See [open-questions.md](../../open-questions.md) for full details.
|
||||
- **OQ-28** (resolved): `from_call` namespace collision — same-peer
|
||||
collision = error; cross-peer dissolved by ADR-029 (separate sub-overlays).
|
||||
`namespace_prefix` is optional local-naming sugar.
|
||||
- **OQ-29** (open, **high priority, load-bearing on ADR-030**): `CallClient`
|
||||
TLS client-auth — NOT "additive" as previously framed. ADR-030's
|
||||
`PeerEntry` fingerprint → `peer_id` resolution requires the client to
|
||||
present a TLS client cert; `with_no_client_auth()` means no fingerprint,
|
||||
no `PeerEntry` resolution, no stable `peer_id`. The `auth_token` path
|
||||
resolves to `Identity.id = ApiKeyEntry.prefix`, not `peer_id`. See OQ-29
|
||||
for the three options (wire client-auth with the migration / ship
|
||||
token-only / extend PeerEntry to cover auth_token). Requires a decision
|
||||
before the ADR-029 migration lands.
|
||||
- **OQ-29** (resolved): `CallClient` TLS client-auth — wire quinn
|
||||
client-auth (present Ed25519 key as raw public key client cert);
|
||||
key-type-aware server cert verification (raw key = fingerprint match,
|
||||
X.509 = CA verification); fingerprint normalization (`ed25519:` across
|
||||
quinn/iroh). The iroh path already works; the gap was quinn-only.
|
||||
See OQ-29 in open-questions.md.
|
||||
- **OQ-30** (resolved): `PeerRef::Any` routing policy — insertion-order
|
||||
first-match. A richer `RoutingPolicy` is a feature extension.
|
||||
- **OQ-31** (resolved): `services/list-peers` — opt-in; `services/list`
|
||||
@@ -657,14 +654,17 @@ See [open-questions.md](../../open-questions.md) for full details.
|
||||
the storage boundary is `core trait + in-memory default` (config-backed
|
||||
`ConfigIdentityProvider` now; persistence adapters additive in separate
|
||||
crates). See OQ-34 in open-questions.md.
|
||||
- **OQ-35** (recorded by ADR-030): API key identity vs peer identity — the
|
||||
asymmetry between the fingerprint path (gets `PeerEntry` id-decoupling)
|
||||
and the API-key path (doesn't) is deliberate. See OQ-35 in
|
||||
open-questions.md.
|
||||
- **OQ-35** (dissolved): the "API key asymmetry" framing was wrong;
|
||||
`PeerEntry` supports multiple credential paths (fingerprints +
|
||||
auth_token_hash), `ApiKeyEntry` is for tokens that ARE the identity.
|
||||
See OQ-35 in open-questions.md.
|
||||
- **OQ-36** (open, deferred for exploration): Concrete persistence adapter
|
||||
shapes — the repo/adapter pattern is committed (ADR-033); the in-memory
|
||||
adapters ship with core; the persistence adapter shapes (SQLite, etc.)
|
||||
are deferred for exploration. See OQ-36 in open-questions.md.
|
||||
- **OQ-37** (open): X.509 outgoing-only case — the three auth types and
|
||||
how X.509 server identity fits the peer model. Not blocking the
|
||||
ADR-029 migration. See OQ-37 in open-questions.md.
|
||||
|
||||
## References
|
||||
|
||||
|
||||
Reference in New Issue
Block a user