Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ded720b7b | ||
|
|
8e6aa79736 |
No files matched your search
@@ -241,7 +241,7 @@ directions:
|
|||||||
## Architecture Context
|
## Architecture Context
|
||||||
|
|
||||||
- `docs/architecture/` — the authoritative spec. Read it before
|
- `docs/architecture/` — the authoritative spec. Read it before
|
||||||
non-trivial changes. ADRs are numbered 001..054; OQs (open questions)
|
non-trivial changes. ADRs are numbered 001..055; OQs (open questions)
|
||||||
track resolved/deferred decisions (OQ-01..43; OQ-43 tracks the
|
track resolved/deferred decisions (OQ-01..43; OQ-43 tracks the
|
||||||
composition layer's ownership and shape after the alknet replacement,
|
composition layer's ownership and shape after the alknet replacement,
|
||||||
deferred(scope)).
|
deferred(scope)).
|
||||||
@@ -338,6 +338,11 @@ directions:
|
|||||||
(verifier selection by `PeerEntry` presence; `RemoteIdentity`
|
(verifier selection by `PeerEntry` presence; `RemoteIdentity`
|
||||||
`None` semantics — re-owned in-crate from the source repo's
|
`None` semantics — re-owned in-crate from the source repo's
|
||||||
alknet ADR-034; the dial/composition layer implements it)
|
alknet ADR-034; the dial/composition layer implements it)
|
||||||
|
- ADR-055 — one identity per connection, dial after auth
|
||||||
|
(`set_identity` once-only is contract; no post-construction
|
||||||
|
identity seam; per-auth doors dial one fabric connection per
|
||||||
|
authentication and set identity at establishment; resolves
|
||||||
|
review 014)
|
||||||
|
|
||||||
- If a TODO references a "Phase B" or a design direction that an ADR
|
- If a TODO references a "Phase B" or a design direction that an ADR
|
||||||
has since decided against, the TODO is stale — remove it and align
|
has since decided against, the TODO is stale — remove it and align
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
status: draft
|
status: draft
|
||||||
last_updated: 2026-10-13 (composition re-key, ADR-054, alkcall reframing of ported docs)
|
last_updated: 2026-11-01 (ADR-055: one identity per connection ruling, review 014 resolution)
|
||||||
---
|
---
|
||||||
|
|
||||||
# alkcall
|
# alkcall
|
||||||
@@ -83,7 +83,7 @@ conventions: see the provenance note at the end of this document.)
|
|||||||
| [032](decisions/032-one-way-door-decision-framework.md) | One-Way Door Decision Framework | Reversal cost classification |
|
| [032](decisions/032-one-way-door-decision-framework.md) | One-Way Door Decision Framework | Reversal cost classification |
|
||||||
| [033](decisions/033-rust-canonical-implementation.md) | Rust as Canonical Implementation Language | Rust canonical, TS reference |
|
| [033](decisions/033-rust-canonical-implementation.md) | Rust as Canonical Implementation Language | Rust canonical, TS reference |
|
||||||
|
|
||||||
### Channels, pub/sub, and later amendments — ADR-034..054
|
### Channels, pub/sub, and later amendments — ADR-034..055
|
||||||
|
|
||||||
| ADR | Title | Relevance |
|
| ADR | Title | Relevance |
|
||||||
|-----|-------|-----------|
|
|-----|-------|-----------|
|
||||||
@@ -108,6 +108,7 @@ conventions: see the provenance note at the end of this document.)
|
|||||||
| [052](decisions/052-channel-control-surface.md) | `channel/control` Control-Handle Surface | Establisher-contributed `ChannelControl` (`Establishment::with_control`), wrapper-installed/teardown-removed in the manager; `channel:no_control_handle` capability answer; resolves OQ-39 |
|
| [052](decisions/052-channel-control-surface.md) | `channel/control` Control-Handle Surface | Establisher-contributed `ChannelControl` (`Establishment::with_control`), wrapper-installed/teardown-removed in the manager; `channel:no_control_handle` capability answer; resolves OQ-39 |
|
||||||
| [053](decisions/053-resource-enumerators.md) | Live Resource Enumerators | `ResourceEnumerators` (peer-shared registry); snapshot-then-changes enumerator contract; scan-once aggregation; empty seed; resolves OQ-40 |
|
| [053](decisions/053-resource-enumerators.md) | Live Resource Enumerators | `ResourceEnumerators` (peer-shared registry); snapshot-then-changes enumerator contract; scan-once aggregation; empty seed; resolves OQ-40 |
|
||||||
| [054](decisions/054-outgoing-only-x509-three-remote-roles.md) | Outgoing-Only X.509 and the Three Remote Roles (Re-Owned) | Verifier-selection by `PeerEntry` presence; three remote roles; `RemoteIdentity` `None` semantics — re-owned in-crate (provenance: alknet ADR-034); resolves OQ-21's cross-repo authority gap |
|
| [054](decisions/054-outgoing-only-x509-three-remote-roles.md) | Outgoing-Only X.509 and the Three Remote Roles (Re-Owned) | Verifier-selection by `PeerEntry` presence; three remote roles; `RemoteIdentity` `None` semantics — re-owned in-crate (provenance: alknet ADR-034); resolves OQ-21's cross-repo authority gap |
|
||||||
|
| [055](decisions/055-one-identity-per-connection.md) | One Identity per Connection; Dial After Auth | `set_identity` once-only is contract — no post-construction identity seam; dial-after-auth is the per-auth-door norm; connection-per-auth composition; scopes token carriage to its carve-out; resolves review 014 |
|
||||||
|
|
||||||
## Relevant Open Questions
|
## Relevant Open Questions
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
# ADR-055: One Identity per Connection; Dial After Auth
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted (2026-11-01). Resolves review 014 (post-construction identity
|
||||||
|
seam — consumer input from alkssh). No API change; this is a semantics
|
||||||
|
ruling.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Review 014 (`docs/reviews/014-post-construction-identity-seam-alkssh-input.md`)
|
||||||
|
filed two coupled findings from alkssh's SSH-server direction:
|
||||||
|
|
||||||
|
**(a)** There is no non-detaching way to attach identity to a
|
||||||
|
connection after construction. `Connection::set_identity` is once-only
|
||||||
|
(`src/core/types.rs:541` — a second call errors); the only post-construction
|
||||||
|
route to a held `ChannelClient`'s connection is `take_call_connection`
|
||||||
|
(`src/channels/client.rs:521`), which detaches the client's calling
|
||||||
|
surface. The hub's establisher hook (`src/channels/hub_leg.rs:213`) has
|
||||||
|
an identity composition point, but it is accept-side, pre-serving.
|
||||||
|
|
||||||
|
**(b)** The once-per-connection identity model does not fit "one fabric
|
||||||
|
connection, many per-session authentications" — an SSH door's shape:
|
||||||
|
the fabric connection can be dialed once by the assembly before any SSH
|
||||||
|
client exists, while russh's auth hooks fire per session and resolve
|
||||||
|
distinct `Identity` values per client key.
|
||||||
|
|
||||||
|
The review framed (a) as a possible seam to build and (b) as the model
|
||||||
|
behind it, and listed three candidate resolutions: a non-detaching
|
||||||
|
seam, an identity-model decision (per-open carriage, connection-per-auth,
|
||||||
|
or a ruling that dial-time identity is substrate truth), and stating the
|
||||||
|
shared-handle corollary explicitly.
|
||||||
|
|
||||||
|
What this ADR adds to the review's framing: **(a) and (b) are not
|
||||||
|
independent, and (a) is not a defect.** A mutable connection-level
|
||||||
|
identity setter would be last-writer-wins under N concurrent
|
||||||
|
authentications — the substrate's `AccessControl::check`
|
||||||
|
(ADR-024) would see whichever session authenticated last, racing
|
||||||
|
concurrent opens and flapping mid-connection, in a way that looks like
|
||||||
|
it works. The once-only slot is a load-bearing property, not a
|
||||||
|
limitation waiting for a seam: identity is set by whoever establishes
|
||||||
|
(or, for a door, whoever dials) the connection, at establishment time.
|
||||||
|
The alkssh review scenario that motivated (a) — a shared
|
||||||
|
`Arc<ChannelClient>` over one pre-dialed fabric connection serving all
|
||||||
|
sessions — is a consumer-side composition in which the fabric
|
||||||
|
connection, and therefore its identity, predates every auth it will
|
||||||
|
serve. Framed inside that composition, every solution is a patch on the
|
||||||
|
wrong layer. The correct composition for a per-auth door is to dial
|
||||||
|
after auth; then the once-only slot is exactly right and no
|
||||||
|
construction is shared.
|
||||||
|
|
||||||
|
This is consistent with the crate's transport-agnostic posture: alkcall
|
||||||
|
does not care where the bytes come from (ADR-007 `from_stream`,
|
||||||
|
ADR-008/009 — TCP+TLS, QUIC, iroh, or "stream an alk protocol crate
|
||||||
|
over an SSH channel" are all equally out of scope at this layer). The
|
||||||
|
ruling below is about when an identity becomes part of a connection's
|
||||||
|
truth, not about any transport.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
### 1. A connection carries exactly one peer identity, consumed at establishment
|
||||||
|
|
||||||
|
`Identity` (`{ id, scopes, resources }`, `src/core/auth.rs`) is set
|
||||||
|
once per `Connection` via `set_identity` and never changed. This
|
||||||
|
stays. **There is no post-construction identity mechanism, and none
|
||||||
|
will be added**: no non-detaching attach on a held `ChannelClient`, no
|
||||||
|
connection-level setter variant, no establisher-hook equivalent on the
|
||||||
|
consumer side that runs after serving starts. The absence is the
|
||||||
|
design. `take_call_connection`'s detach-on-take remains intentional
|
||||||
|
(ownership transfer, not identity surgery).
|
||||||
|
|
||||||
|
The substrate truth for everything riding a connection is the identity
|
||||||
|
present at establishment. `AccessControl::check(peer_identity)`
|
||||||
|
(ADR-024) evaluates that identity and nothing else.
|
||||||
|
|
||||||
|
### 2. Dial-after-auth composition rule (the per-auth door pattern)
|
||||||
|
|
||||||
|
A door that must present a *per-session* resolved identity to the
|
||||||
|
substrate ACL dials one fabric connection per authentication and sets
|
||||||
|
the resolved identity at establishment (before wrapping in
|
||||||
|
`ChannelClient` / registering imported ops / spawning dispatch). N
|
||||||
|
authentications → N connections. Because the connection is dialed
|
||||||
|
after the auth it represents, the once-only slot is consumed exactly
|
||||||
|
once, with the correct value — no seam needed.
|
||||||
|
|
||||||
|
This is the norm case for doors built like alkssh, not a workaround:
|
||||||
|
doors presenting N authentications-per-connection will always present
|
||||||
|
per-session auth; the connection is what the substrate authorizes, so
|
||||||
|
sessions that need distinct substrate identities ride distinct
|
||||||
|
connections. Native consumers hold real key material (e.g. the ed25519
|
||||||
|
key a russh endpoint shares with the TLS and iroh endpoints); they
|
||||||
|
present it at establishment and never need token carriage.
|
||||||
|
|
||||||
|
### 3. Connections that pre-date an auth: the substrate sees dial-time identity
|
||||||
|
|
||||||
|
A door that dials once before any auth exists (shared
|
||||||
|
`Arc<ChannelClient>`) has chosen a composition in which the substrate
|
||||||
|
sees the assembly's dial-time identity. Per-session gates are then the
|
||||||
|
door's job. This is a valid posture when the substrate-side identity is
|
||||||
|
not the boundary the deployment cares about — the door-side gate is.
|
||||||
|
It is the contract now: documented, deliberate, and not silently
|
||||||
|
upgradeable — nothing in alkcall will let such a door claim a different
|
||||||
|
substrate identity later.
|
||||||
|
|
||||||
|
### 4. Token carriage stays scoped to its carve-out
|
||||||
|
|
||||||
|
The payload `auth_token` → `IdentityProvider` path (CF-005's serving
|
||||||
|
identity machinery, ADR-017 §7) exists for transports where in-band key
|
||||||
|
auth of the *end client* is impossible — alkhttp browser clients, git
|
||||||
|
LFS over HTTP. It is not the native path, and it does not extend onto
|
||||||
|
consumers that hold key material: `ChannelClient::{call_open_op,
|
||||||
|
pub_open}` gain no token parameter. A native consumer presents its
|
||||||
|
identity at establishment per §1–2.
|
||||||
|
|
||||||
|
### 5. The shared-handle corollary, stated
|
||||||
|
|
||||||
|
Doors that pre-dial serve N sessions over one connection by
|
||||||
|
composition, not by accident of the API. Whatever shape lands must
|
||||||
|
assume this exists as a norm (review 014 §point 3): `peer_identity` is
|
||||||
|
the *connection's* peer, and "one application session per connection"
|
||||||
|
is explicitly not assumed anywhere in this crate.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
**Positive:**
|
||||||
|
- No API change, no wire change. The resolution is a ruling — walk-back
|
||||||
|
cost is doc edits only (ADR-032's cheap-reversal class).
|
||||||
|
- The once-only `IdentityAlreadySet` design is now load-bearing
|
||||||
|
contract rather than an incidental convenience; the review's "gap"
|
||||||
|
cannot recur as a feature request against it.
|
||||||
|
- Doors get an explicit choice: dial-after-auth (per-session substrate
|
||||||
|
identities) or pre-dial (door-side gates, dial identity at the
|
||||||
|
substrate). Both are contracts.
|
||||||
|
- Consistent with ADR-024 (peer identity = connection peer) and ADR-026
|
||||||
|
(forwarded_for is metadata, never ACL authority — per-op carriage of
|
||||||
|
an *authenticated* end-client identity remains the token path's job
|
||||||
|
on transports that need it).
|
||||||
|
|
||||||
|
**Negative:**
|
||||||
|
- Per-auth doors pay one fabric connection per session. Substrate
|
||||||
|
connections are cheap at this layer (no TLS config, no endpoint —
|
||||||
|
ADR-007); the assembly decides whether that cost matters.
|
||||||
|
- "One identity per connection" means a shared-connection door cannot
|
||||||
|
get substrate-side per-session ACL without changing its composition.
|
||||||
|
Consumers needing that must re-dial; this ADR does not soften §1.
|
||||||
|
|
||||||
|
## Door type
|
||||||
|
|
||||||
|
**Two-way** (ADR-032). No code, wire, or published-API change — a
|
||||||
|
semantics ruling documented in prose. If a real deployment shows
|
||||||
|
connection-per-auth is wrong for a door class, reversing this is a doc
|
||||||
|
edit plus, at most, a future ADR. (Contrast: a `set_identity`-style
|
||||||
|
safety-valve API would have been one-way — added surface is nearly
|
||||||
|
impossible to remove from a published crate once a consumer depends on
|
||||||
|
it, and it would have locked in the flapping-ACL behavior under the
|
||||||
|
shared-handle case.)
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- review 014 (`docs/reviews/014-post-construction-identity-seam-alkssh-input.md`)
|
||||||
|
— the consumer input this ADR resolves; alkssh's shipped no-detach
|
||||||
|
posture (`set_identity`/`take_call_connection` absent from its code)
|
||||||
|
is the §3 posture, now contract
|
||||||
|
- CF-005 / CF-006 (`docs/reviews/consumer-findings-ledger.md`) — the
|
||||||
|
connect-side serving-identity precedence chain (payload token →
|
||||||
|
`ServingConfig.identity` → transport identity) whose token tier §4
|
||||||
|
scopes; the connection-half (§1) and channel-0-copy (§2) behaviors
|
||||||
|
already match this ruling
|
||||||
|
- ADR-024 — Peer-Graph Routing Model (AccessControl peer authorization;
|
||||||
|
`peer_identity` is the connection's peer)
|
||||||
|
- ADR-026 — Forwarded-For Identity (metadata, never ACL authority)
|
||||||
|
- ADR-017 §7 — the token path's origin (hub-forwarding / browser-token
|
||||||
|
fallback)
|
||||||
|
- ADR-003/006 — Identity/AuthToken/AuthContext structure (identity is
|
||||||
|
a resolved value; the key material stays transport-side)
|
||||||
|
- ADR-007/008/009 — transport-agnostic connection construction
|
||||||
|
(`from_stream`, `BidiStreamSource`, `BiStream`); the dial is
|
||||||
|
consumer-side, TLS is transport detail
|
||||||
|
- ADR-045 — the dial seam (spawn_dispatch / from_connection take-over;
|
||||||
|
dial lives in the consumer — the composition point §2 relies on)
|
||||||
|
- ADR-032 — One-Way Door Decision Framework (the two-way classification)
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
# Review 014 — The post-construction identity seam: consumer input from alkssh's SSH server direction
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Resolved 2026-11-01 — ADR-055
|
||||||
|
(`docs/architecture/decisions/055-one-identity-per-connection.md`).
|
||||||
|
No API change. See the Resolution section below before reading the
|
||||||
|
finding sections, which stand as filed (historical).
|
||||||
|
|
||||||
|
Filed 2026-10-31. Consumer input from alkssh 0.1.0 (published
|
||||||
|
2026-10-31), under the family's upstream posture (file asks, never
|
||||||
|
absorb silently). Booked alkssh-side at its wave-3 review gate (item 5)
|
||||||
|
as the "non-detaching post-construction identity seam" note and carried
|
||||||
|
unabsorbed through the alkssh 0.1.0 release; this is that filing.
|
||||||
|
|
||||||
|
## Resolution
|
||||||
|
|
||||||
|
ADR-055 rules the review's §"What a resolution decides" as follows:
|
||||||
|
|
||||||
|
- **Point 1 (the seam): denied.** Fact (a) is reclassified: not a
|
||||||
|
defect — a post-construction identity mechanism on a shared handle
|
||||||
|
would be last-writer-wins under the N-auth case this review itself
|
||||||
|
surfaced (fact (b)), making the substrate's `AccessControl::check`
|
||||||
|
see whichever session authenticated last. `set_identity`'s
|
||||||
|
once-only design is load-bearing contract. The review's §the finding
|
||||||
|
framing ("(a) no seam exists" / "(b) even with one, the
|
||||||
|
once-per-connection model does not fit") is resolved as: the
|
||||||
|
shared-handle composition is the thing that does not fit, and the
|
||||||
|
correct fix is consumer-side composition (dial-after-auth), not a
|
||||||
|
seam.
|
||||||
|
- **Point 2 (the identity model): the ruling.** A connection carries
|
||||||
|
exactly one peer identity, consumed at establishment; dial-after-auth
|
||||||
|
(one fabric connection per authentication, identity set before
|
||||||
|
wrapping) is the norm-case composition for per-auth doors; doors that
|
||||||
|
pre-dial have a contract — per-session gates are the door's job and
|
||||||
|
the substrate sees dial-time identity (the review's option 3, plus
|
||||||
|
connection-per-auth as the native composition).
|
||||||
|
- **Point 3 (the shared-handle corollary): stated** in ADR-055 §5 —
|
||||||
|
`peer_identity` means the connection's peer; "one application session
|
||||||
|
per connection" is not assumed anywhere.
|
||||||
|
- **Token carriage: out of scope for this class.** The ADR scopes the
|
||||||
|
payload `auth_token` path to its carve-out (alkhttp, git LFS —
|
||||||
|
transports where in-band key auth of the end client is impossible);
|
||||||
|
`ChannelClient` open surfaces gain no token parameter.
|
||||||
|
|
||||||
|
alkssh's shipped posture (no-detach, door-side gates, dial-time
|
||||||
|
identity at the substrate) is now contract rather than "happened to
|
||||||
|
work." The alkssh-side wave-3 item 5 can close against this ADR; if a
|
||||||
|
real deployment later shows a door class where connection-per-auth does
|
||||||
|
not fit, ADR-055 is a two-way decision (doc-edit reversal cost).
|
||||||
|
|
||||||
|
This is the server-direction sibling of the identity-capture class the
|
||||||
|
alkhttp ledger recorded as CF-005 ("no caller-identity capture on the
|
||||||
|
connect-side serving path"): there, the transport-authenticated peer
|
||||||
|
could not be captured *at acceptance*; here, a correctly resolved
|
||||||
|
application-identity cannot be attached *after dialing*. Same boundary
|
||||||
|
(transport connection identity vs. per-session/per-op truth), opposite
|
||||||
|
end of the connection's lifecycle.
|
||||||
|
|
||||||
|
## The finding
|
||||||
|
|
||||||
|
A consumer that authenticates **after** the fabric connection exists —
|
||||||
|
an SSH front door, where the russh auth hooks fire per-session while
|
||||||
|
the substrate connection is dialed once by the assembly — has no
|
||||||
|
correct surface to make its resolved identity the one the fabric's ACL
|
||||||
|
sees.
|
||||||
|
|
||||||
|
The pieces, verified against 0.10.1 source:
|
||||||
|
|
||||||
|
- `Connection::set_identity` is once-only (`src/core/types.rs:541` —
|
||||||
|
a second call errors `IdentityAlreadySet`). The identity slot is
|
||||||
|
consumed at construction/establishment time; the hub template
|
||||||
|
demonstrates the intended composition point: the establisher
|
||||||
|
closure receives `channel0_conn` and may set identity at the
|
||||||
|
transport-establish event (`src/channels/hub_leg.rs:206-221` —
|
||||||
|
"transport connection's identity propagates to channel 0 …
|
||||||
|
dispatch's fallback resolves through it").
|
||||||
|
- The only post-construction way to reach an already-held
|
||||||
|
`ChannelClient`'s connection is `ChannelClient::take_call_connection`
|
||||||
|
(`src/channels/client.rs:521`), which **detaches the client's own
|
||||||
|
calling surface** ("after this, `call_open_op` returns an error").
|
||||||
|
For a hub that is at least arguable (the relay note flags the detach
|
||||||
|
as wrong there too). For a long-lived door it is disqualifying:
|
||||||
|
alkssh rejected this surface on exactly that ground — "the detach
|
||||||
|
would strand every later session."
|
||||||
|
|
||||||
|
## The consumer scenario, concretely (alkssh server direction)
|
||||||
|
|
||||||
|
1. The assembly dials the substrate and configures the door with an
|
||||||
|
`Arc<ChannelClient>` (alkssh `ServeConfig::channel_client`). The
|
||||||
|
fabric connection — and its identity slot — exist and are composed
|
||||||
|
**before any SSH client has connected**. The assembly's dial-time
|
||||||
|
identity ("once at dial, propagated to channel 0 at
|
||||||
|
`from_connection`") is what `AccessControl::check(peer_identity)`
|
||||||
|
on the substrate sees from then on.
|
||||||
|
2. Each SSH session authenticates later, via `auth_publickey`
|
||||||
|
(post-verification; fingerprint → `Identity` resolution,
|
||||||
|
fail-closed). alkssh ties into these hooks correctly — the
|
||||||
|
resolution, the door-side `no-identity` guard, and the gate at the
|
||||||
|
door all work and need no alkcall change.
|
||||||
|
3. The gap is only the second gate: the admitted mapped open rides
|
||||||
|
the dialed fabric connection, and the substrate's ACL re-checks
|
||||||
|
`peer_identity` (CF-005/CF-006). There is no non-detaching,
|
||||||
|
post-construction way to attach the per-auth resolved identity —
|
||||||
|
and structurally there cannot be a single one for a session with
|
||||||
|
a **shared** handle: `set_identity` is once-only, so even a
|
||||||
|
hypothetical setter cannot represent N sessions' identities on one
|
||||||
|
connection.
|
||||||
|
|
||||||
|
So this review documents two coupled facts, not one bug: **(a)** no
|
||||||
|
seam exists to attach identity post-dialing without detaching the
|
||||||
|
calling surface; **(b)** even with one, the once-per-connection
|
||||||
|
identity model does not fit "one fabric connection, many
|
||||||
|
per-session authentications."
|
||||||
|
|
||||||
|
## What the consumer shipped instead (the current honest posture)
|
||||||
|
|
||||||
|
- The no-detach posture preserved (`set_identity`/`take_call_connection`
|
||||||
|
appear nowhere in alkssh `src/`; recorded in alkssh
|
||||||
|
`review-wave-3.md`, item 5's disposition and `w3-tunnel-direct`'s
|
||||||
|
mechanics record).
|
||||||
|
- Identity gated at the door (fail-closed `no-identity` guard,
|
||||||
|
unreachable on the wire) with the substrate gate seeing dial-time
|
||||||
|
composition — the composed-gate arrangement is documented in
|
||||||
|
alkssh `config.rs`'s module docs (§the identity ride) as a decided
|
||||||
|
posture, not a drift risk. Safety degrades to the door-side gate
|
||||||
|
plus the assembly's dial-time identity semantics; nothing
|
||||||
|
anonymous passes at either gate unless the assembly composes it.
|
||||||
|
- One incidental hardening alkssh took that touches this crate's
|
||||||
|
surface in spirit: the door's listen router refuses a colliding
|
||||||
|
token mint fail-closed (never replaces; alkssh `w4-router-collision`
|
||||||
|
— in-depth defense, safety otherwise resting on this crate's
|
||||||
|
ADR-008 mint discipline). No alkcall change asked; recorded for
|
||||||
|
the trail.
|
||||||
|
|
||||||
|
## What a resolution decides (framing, not prescription)
|
||||||
|
|
||||||
|
Any resolution is an API/semantics decision in a published crate —
|
||||||
|
ADR-class in this repo, one-way from alkssh's consumer:
|
||||||
|
|
||||||
|
1. **A seam**: a non-detaching post-construction identity mechanism on
|
||||||
|
a held `ChannelClient`/connection (the hub's establisher hook has
|
||||||
|
no consumer-side equivalent today). Whether that is connection- or
|
||||||
|
op-scoped decides nothing else below by itself.
|
||||||
|
2. **The identity model behind it**: what `peer_identity` *means* when
|
||||||
|
one dialed connection serves many per-session identities —
|
||||||
|
per-open identity carriage (op-scoped, the CF-005 payload-token
|
||||||
|
path's shape), connection-per-auth, or an explicit ruling that
|
||||||
|
dial-time identity is always the substrate-truth and per-session
|
||||||
|
gates are the door's job. A ruling alone (option 3) is a valid
|
||||||
|
resolution: it converts the current arrangement from "happened to
|
||||||
|
work" to contract.
|
||||||
|
3. **The shared-handle corollary**: N-authentications-per-connection
|
||||||
|
is what doors built like alkssh will always present. Whatever
|
||||||
|
shape lands should state this case explicitly rather than assume
|
||||||
|
one identity per connection is the norm.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- alkssh `docs/architecture/auth.md` §Server direction step 4 (the
|
||||||
|
auth-hook resolution; the visible-surface invariant)
|
||||||
|
- alkssh `src/config.rs` module docs §the identity ride (the shipped
|
||||||
|
posture; why `take_call_connection` was rejected) and
|
||||||
|
`src/tunnel_map.rs` (the no-detach posture in code: no
|
||||||
|
`set_identity` calls)
|
||||||
|
- alkssh `tasks/implementation/review-wave-3.md` item 5 (the original
|
||||||
|
booking) and `tasks/implementation/w3-tunnel-direct.md` (the
|
||||||
|
mechanics record); `tasks/implementation/review-wave-5.md` /
|
||||||
|
`docs/plans/implementation.md` (carried unabsorbed through release)
|
||||||
|
- `src/core/types.rs:541-549` (`set_identity` once-only),
|
||||||
|
`src/channels/client.rs:514-523` (`take_call_connection` detach),
|
||||||
|
`src/channels/hub_leg.rs:213-221` (the establisher's identity
|
||||||
|
composition point)
|
||||||
|
- `docs/reviews/consumer-findings-ledger.md` CF-005 (the
|
||||||
|
connect-side sibling of this class; its resolution is the
|
||||||
|
payload-token/CF-005 precedence machinery alkssh's scenario rides)
|
||||||
|
- ADR-047/ADR-048 class precedents for how a published-crate
|
||||||
|
semantics ruling ships (loud default precedent, ADR-048)
|
||||||
Reference in new issue
Block a user