chore: consume alkcall 0.7.0; W1/CF-005 resolved — identity seam validated

alkcall 0.7.0 resolved every open downstream-consumer finding,
including this crate's reverse-flow POC W1 (filed as ledger CF-005,
with the CF-006 corollary):
- CF-005 (a): ServingConfig.identity — the explicit override
- CF-005 (b): transport Connection::identity() propagates to
  channel 0 — set_identity before dialing is the mTLS/QUIC path
- CF-006: the establisher/pump handler receive the per-call opener
  identity (dispatch-resolved), not the install-time context
- CF-007: ADR-016 code list completed (doc-only)
- F-1 (POC finding): the ChannelPlan type doc now carries the
  Send + Sync payload constraint

alktunnels updates:
- Cargo.toml: alkcall 0.6.0 -> 0.7.0 (lockfile resolves 0.7.0)
- AGENTS.md convention 11: pin note updated; the 0.7.0 identity
  surface marked load-bearing (precedence order + per-call opener)
- AGENTS.md architecture context: CF-005/CF-006 row added; the
  'What the POC does NOT settle' list replaced with the accurate
  settled state (Phase 0 complete; Phase 1 = the spec)
- reverse-poc-summary: W1 marked RESOLVED with the remediation
  validated from the POC's topology (16 tests over 0.7.0: transport
  identity alone authorizes, ServingConfig.identity overrides,
  identity-less fails closed, CF-006 witness); F-1 marked documented
  upstream; what-the-POC-does-not-validate and verification blocks
  updated
- phase-0-findings OQ-TN-10: reverse POC entry notes the 0.7.0
  re-validation and W1 resolution

The reverse POC (/workspace/alktunnels-reverse-poc, 8b35818) re-
validated: the default harness now authorizes on transport identity
alone — the 0.6.0-era auth_token workaround is dead code.

Verification: cargo test, clippy --all-targets -D warnings,
fmt --check, wasm32 check, doc --no-deps — all clean
This commit is contained in:
2026-09-07 17:59:53 +00:00
parent 603f398f6d
commit dc2eab3b21
5 changed files with 114 additions and 70 deletions
+22 -12
View File
@@ -167,14 +167,22 @@ just spawned implementation agents.
`alkcall::core`. Do not vendor copies into this crate. alkcall is `alkcall::core`. Do not vendor copies into this crate. alkcall is
v0.5.x — breaking changes are expected at this major-zero stage; v0.5.x — breaking changes are expected at this major-zero stage;
this is an early consumer, so we find and fix issues upstream this is an early consumer, so we find and fix issues upstream
rather than working around them. Pin `alkcall = "0.6.0"` and bump rather than working around them. Pin `alkcall = "0.7.0"` and bump
deliberately. The 0.6.0 establishment surface (ADR-049 + amendment deliberately. The 0.6.0 establishment surface (ADR-049 + amendment
2) is load-bearing for this crate: tunnel opens use 2) is load-bearing for this crate: tunnel opens use
`register_openable_with_establisher` so a refused target dial is `register_openable_with_establisher` so a refused target dial is
a typed `channel:open_failed` call error, never a phantom channel, a typed `channel:open_failed` call error, never a phantom channel,
and the establisher returns the dialed handle via and the establisher returns the dialed handle via
`Establishment::new(plan)` (typed-opaque `ChannelPlan`)no `Establishment::new(plan)` (typed-opaque `ChannelPlan` — its
side-channel handoff. `Send + Sync` bound constrains plan payloads; socket handles carry
`+ Sync`) — no side-channel handoff. The 0.7.0 identity surface
(ledger CF-005/CF-006) is load-bearing for the serving side: a
connect-side serving op resolves the caller identity in
precedence order — payload `auth_token` >
`ServingConfig.identity` > transport identity (set via
`Connection::set_identity` before dialing) — and the establisher/
pump handler receive the per-call opener identity, not the
install-time context.
12. **BAST document for the wire format** — when the tunnel wire format 12. **BAST document for the wire format** — when the tunnel wire format
gains binary framing (if any beyond pass-through), it carries a gains binary framing (if any beyond pass-through), it carries a
@@ -286,18 +294,20 @@ non-backend module changes.
channel 0; `params` carries the tunnel target) channel 0; `params` carries the tunnel target)
- alkcall ADR-042 — hub relay (byte-for-byte data-channel forwarding - alkcall ADR-042 — hub relay (byte-for-byte data-channel forwarding
with ID rewrite — tunnels traverse relays transparently) with ID rewrite — tunnels traverse relays transparently)
- alkcall ledger CF-005/CF-006 (0.7.0) — the connect-side serving
identity seam: caller identity precedence (token >
`ServingConfig.identity` > transport), per-call opener identity
on the open-op hooks (the reverse-flow POC's W1, resolved)
- alknet ADR-085 — workspace scope: `alknet/tunnel` was flagged - alknet ADR-085 — workspace scope: `alknet/tunnel` was flagged
"POC-validated, minimal spec needed, not yet specced"; this crate "POC-validated, minimal spec needed, not yet specced"; this crate
is that spec is that spec
- What the POC does NOT settle (open work for Phase 0/1): - What the POCs settled (Phase 0 complete — 2026-09-07): both POCs
- UDP and Unix-socket substrates (the POC only exercised TCP) — the ran clean (forward UDP POC + reverse-flow POC; see
pump pattern is expected to generalize, but datagram boundary `docs/research/poc-summary.md` and `reverse-poc-summary.md`). The
preservation and addressing bookkeeping are unspecced remaining Phase 1 work is the spec: OQ promotion, params JSON ADR,
- The "no forced local binding" requirement (SSH `-R`/dynamic flows) ALPN ADR, codec ADR (UDP framing mandatory per F-2), and the
is not covered by the POC at all producer/consumer API surface (the consumer session type owns
- Target addressing format (what a tunnel `params` looks like) — teardown — reverse POC W3).
alknet ADR-071 §ALPN table noted `alknet/tunnel` as `[0, 1]` data
in/out only, but the addressing scheme was never decided
- If a TODO references a design direction that an ADR has since decided - If a TODO references a design direction that an ADR has since decided
against, the TODO is stale — remove it and align with the ADR. Do not against, the TODO is stale — remove it and align with the ADR. Do not
implement the rejected design. implement the rejected design.
Generated
+2 -2
View File
@@ -27,9 +27,9 @@ dependencies = [
[[package]] [[package]]
name = "alkcall" name = "alkcall"
version = "0.6.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44500900b82904d2a870e444051fc041a042e42ff7190803bbc5b3973f4feeb" checksum = "5162a10144df65b03b887e30f77eb30d956ca1ca460a3f81b409128cbcae3199"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
+1 -1
View File
@@ -18,7 +18,7 @@ name = "alktunnels"
default = [] default = []
[dependencies] [dependencies]
alkcall = "0.6.0" alkcall = "0.7.0"
tokio = { version = "1", default-features = false, features = ["rt", "sync", "io-util", "macros", "time"] } tokio = { version = "1", default-features = false, features = ["rt", "sync", "io-util", "macros", "time"] }
bytes = "1" bytes = "1"
futures = "0.3" futures = "0.3"
+15 -10
View File
@@ -773,11 +773,15 @@ Phase 0 may need (in rough priority order, per the SDD process's
closes: no advertisement op needed — the listener is the hub's own closes: no advertisement op needed — the listener is the hub's own
local resource; a far-side listener is a producer-side listen local resource; a far-side listener is a producer-side listen
establisher over the same open op. Findings: F-1 (plan payloads establisher over the same open op. Findings: F-1 (plan payloads
must be `Send + Sync`), F-2 (UDP raw pass-through cannot carry must be `Send + Sync` — documented upstream in 0.7.0), F-2 (UDP
empty datagrams — the length-framed codec is mandatory, second raw pass-through cannot carry empty datagrams — the length-framed
validation of the codec decision). W1 (connect-side serving path codec is mandatory, second validation of the codec decision). W1
resolves identity only via payload `auth_token`) filed for the (connect-side serving path resolves identity only via payload
alkcall ledger. `auth_token`) filed for the alkcall ledger — **RESOLVED by alkcall
0.7.0 (CF-005/CF-006)**; the POC re-validated over 0.7.0 (16
tests): transport identity authorizes alone, `ServingConfig.
identity` overrides, identity-less fails closed, and the
establisher sees the per-call opener identity.
3. **Unix socket + stdio bridge POC** — cheap; validates "substrate 3. **Unix socket + stdio bridge POC** — cheap; validates "substrate
agnostic" beyond IP substrates. agnostic" beyond IP substrates.
4. **Two-pump helper extraction spike** — OQ-TN-06, only after 13. 4. **Two-pump helper extraction spike** — OQ-TN-06, only after 13.
@@ -880,11 +884,12 @@ Candidate reading for the research specialist (to be expanded):
- [x] Targeted POC(s) run + summary (OQ-TN-10) — UDP POC DONE - [x] Targeted POC(s) run + summary (OQ-TN-10) — UDP POC DONE
(2026-09-06, `poc-summary.md`); reverse-flow POC DONE (2026-09-06, `poc-summary.md`); reverse-flow POC DONE
(2026-09-07, `reverse-poc-summary.md` — the `-R` shape validated (2026-09-07, `reverse-poc-summary.md` — the `-R` shape validated
end-to-end over alkcall 0.6.0; findings F-1/F-2; W1 filed for end-to-end over alkcall 0.6.0, re-validated over 0.7.0 with the
the upstream ledger). Remaining items (#3 unix/stdio, #4 helper CF-005/CF-006 identity remediation; findings F-1/F-2; W1 filed
spike) are spec-scope: #3 folds into the real crate's tests upstream and RESOLVED). Remaining items (#3 unix/stdio, #4
(pump agnosticism confirmed twice), #4 resolved by alkcall 0.6.0 helper spike) are spec-scope: #3 folds into the real crate's
(ADR-050) tests (pump agnosticism confirmed twice), #4 resolved by
alkcall 0.6.0 (ADR-050)
- [x] Two-pump helper convergence input gathered (OQ-TN-06) — the POC - [x] Two-pump helper convergence input gathered (OQ-TN-06) — the POC
gives both shapes (producer `pump_halves`, consumer gives both shapes (producer `pump_halves`, consumer
`take_halves` + copy): same shape modulo channel side; the `take_halves` + copy): same shape modulo channel side; the
+74 -45
View File
@@ -7,11 +7,15 @@ last_updated: 2026-09-07
**Status:** Research complete — the `-R` shape (the hub opens tunnel **Status:** Research complete — the `-R` shape (the hub opens tunnel
channels *toward* a connect-side worker that serves its own open op) channels *toward* a connect-side worker that serves its own open op)
validated end-to-end over alkcall 0.6.0. 14 tests pass; clippy validated end-to-end over alkcall 0.6.0 (2026-09-07 pass, 14 tests)
and re-validated over alkcall 0.7.0 (16 tests) after the CF-005/CF-006
identity remediation landed — the W1 `auth_token` workaround is dead;
the primary caller-identity path is transport identity. Clippy
`-D warnings` clean; fmt clean. The review 007 non-finding trace `-D warnings` clean; fmt clean. The review 007 non-finding trace
("no upstream mechanism is missing") is confirmed by execution — ("no upstream mechanism is missing") is confirmed by execution —
and the POC surfaced two real findings the forward POC could not and the POC surfaced two real findings the forward POC could not
(one an upstream sharpness question, one a spec-mandate). (one an upstream sharpness question — F-1, documented upstream in
0.7.0; one a spec-mandate — F-2).
**Date:** 2026-09-07 **Date:** 2026-09-07
**Scope:** Validates the OQ-TN-10 #2 POC — the SSH `tcpip-forward` **Scope:** Validates the OQ-TN-10 #2 POC — the SSH `tcpip-forward`
template (register → per-accept channel-open → cancel) mapped onto template (register → per-accept channel-open → cancel) mapped onto
@@ -23,7 +27,8 @@ selected from the mechanism trace; findings F-1/F-2 below.
## Executive summary ## Executive summary
A POC (`alktunnels-reverse-poc`, `/workspace/alktunnels-reverse-poc`) A POC (`alktunnels-reverse-poc`, `/workspace/alktunnels-reverse-poc`)
validated the reverse flow end-to-end over alkcall 0.6.0: validated the reverse flow end-to-end over alkcall 0.6.0 (re-validated
over 0.7.0 — see §W1):
1. **The worker (connect side, serving side)** — dials the transport, 1. **The worker (connect side, serving side)** — dials the transport,
`ChannelClient::from_connection_with_serving` + `ChannelClient::from_connection_with_serving` +
@@ -38,42 +43,56 @@ validated the reverse flow end-to-end over alkcall 0.6.0:
2. **The hub (accept side, reverse-flow initiator)** 2. **The hub (accept side, reverse-flow initiator)**
`ChannelsAdapter` + install hook that captures the hub's channel-0 `ChannelsAdapter` + install hook that captures the hub's channel-0
`CallConnection` and `ChannelManager`. Per local accept: call the `CallConnection` and `ChannelManager`. Per local accept: call the
worker's open op (`call_with_payload` + `auth_token`), adopt the worker's open op (`call_with_payload` — the caller identity rides
the transport identity by default (0.7.0); the payload
`auth_token` is the optional hub-forwarding path), adopt the
worker-allocated channel ID, pump the accepted socket against the worker-allocated channel ID, pump the accepted socket against the
adopted halves via `pump_bidi` spawned locally. adopted halves via `pump_bidi` spawned locally.
3. **The ADR-047 §5 orientation under test holds:** the reverse 3. **The ADR-047 §5 orientation under test holds:** the reverse
channels are allocated by the worker (connect side — odd IDs) and channels are allocated by the worker (connect side — odd IDs) and
adopted by the hub (accept side). "Connection owner allocates" adopted by the hub (accept side). "Connection owner allocates"
exercised in the Pub-like orientation. exercised in the Pub-like orientation.
4. **14 tests:** TCP round trip, 1 MiB backpressure, half-close 4. **16 tests (0.7.0 pass):** TCP round trip, 1 MiB backpressure,
semantics, concurrent same-resource channels (the R-01 race-killer half-close semantics, concurrent same-resource channels (the R-01
proven: two opens of one resource, distinct channels, distinct race-killer proven: two opens of one resource, distinct channels,
dialed handles), UDP round trip, TCP+UDP concurrent, typed distinct dialed handles), UDP round trip, TCP+UDP concurrent,
establishment errors (`unknown_resource`, `dial_failed`, typed establishment errors (`unknown_resource`, `dial_failed`),
`FORBIDDEN` ×2), out-of-band `channel/close`, worker outbound the identity precedence chain (transport identity alone /
calls resolving while serving, late-registration visibility, and `ServingConfig.identity` override / token override / identity-less
two finding-pinning tests (F-1 compiler-pinned, F-2 below). fail-closed), CF-006 per-call opener witness, out-of-band
`channel/close`, worker outbound calls resolving while serving,
late-registration visibility, and two finding-pinning tests
(F-1 compiler-pinned, F-2 below).
## Wrinkle probes (W1..W4) — results ## Wrinkle probes (W1..W4) — results
- **W1 identity on the serving path — CONFIRMED, upstream question.** - **W1 identity on the serving path — CONFIRMED 2026-09-07 against
`from_connection_with_serving` builds channel 0 internally; its 0.6.0; RESOLVED by alkcall 0.7.0 (ledger CF-005 + CF-006).**
`Connection::identity()` is empty and `ServingConfig` has no auth Original finding: `from_connection_with_serving` built channel 0
capture point. The serving dispatcher resolves the caller identity internally; its `Connection::identity()` was empty and
ONLY from the payload `auth_token` `ServingConfig` had no auth capture point — the serving dispatcher
`ServingConfig.identity_provider` (verified: scoped token → open resolved the caller identity ONLY from the payload `auth_token`
proceeds; absent/foreign token → `FORBIDDEN`). The establisher and `ServingConfig.identity_provider`, and the establisher/pump handler
pump handler receive the connection-establishment-time `AuthContext` received the install-time `AuthContext`, never the per-call opener.
closed over at `register_openable` — NOT the per-call opener. **The 0.7.0 remediation (validated from this POC's topology, 16
Consequences: (a) a scope-gated reverse-flow open op is satisfiable tests):**
today only via payload tokens (hub-side: attach - `ServingConfig.identity: Option<Identity>` — the explicit
`auth_token` to `call_with_payload`); (b) transport-level override (remediation (a)).
authentication (mTLS/QUIC peer identity) never reaches the - The transport `Connection::identity()` (set before dialing — the
open-op ACL on the connect-side serving path. This is the same mTLS/QUIC posture) propagates to channel 0 automatically
asymmetry the accept side resolved with the install hook's (remediation (b)). Validated: the POC's default harness now
`channel0_conn.set_identity`. Candidate follow-ups: `ServingConfig` authorizes the scope-gated open on transport identity ALONE — no
gaining an identity capture, or documented token-only posture. token payload.
→ alkcall review ledger (W1). - Precedence (alkcall cf005 tests + POC probes): payload token >
`ServingConfig.identity` > transport identity; none → fail-closed
`FORBIDDEN` (validated).
- CF-006 corollary: the establisher/pump handler now receive the
**per-call** opener identity (validated via an identity witness —
the establisher saw `hub`, and the override identity under (a)).
On hub-forwarded opens the establisher sees the end client, not
the hub.
Status: resolved — the POC's `auth_token` workaround is dead code;
the primary path is transport identity.
- **W2 post-hoc openable registration — works.** The worker registers - **W2 post-hoc openable registration — works.** The worker registers
its openable AFTER `from_connection_with_serving` returns; the its openable AFTER `from_connection_with_serving` returns; the
dispatcher reads through the shared `Arc<OperationRegistry>` per dispatcher reads through the shared `Arc<OperationRegistry>` per
@@ -111,10 +130,10 @@ halves are `Sync`, so dial-shaped payloads are unaffected).
Implications for Phase 1: tunnel plan payloads (target handles) must Implications for Phase 1: tunnel plan payloads (target handles) must
be `Sync`, which is fine for socket-backed substrates but would be `Sync`, which is fine for socket-backed substrates but would
exclude non-Sync handles (e.g. process pipes as boxed trait objects) exclude non-Sync handles (e.g. process pipes as boxed trait objects)
without a wrapper. The spec should pin "plan payloads are without a wrapper. **Documented upstream 2026-09-07 (alkcall 0.7.0):
`Send + Sync`" as a documented constraint of the establisher API. the `ChannelPlan` type doc now carries the `Send + Sync` payload
No upstream change needed — the bound is correct (the plan crosses constraint.** No further action needed — the bound is correct (the
the wrapper task boundary). plan crosses the wrapper task boundary).
### F-2 — empty UDP datagrams collide with the EOF sentinel in raw pass-through (spec-mandate) ### F-2 — empty UDP datagrams collide with the EOF sentinel in raw pass-through (spec-mandate)
@@ -171,22 +190,27 @@ alktunnels-reverse-poc/
src/ src/
lib.rs — module docs; wrinkle overview lib.rs — module docs; wrinkle overview
producer.rs — worker half: tunnel_open_spec, tunnel_establisher producer.rs — worker half: tunnel_open_spec, tunnel_establisher
(Establishment::new(plan) — R-01), make_tunnel_ (Establishment::new(plan) — R-01; per-call
identity witness — CF-006), make_tunnel_
pump_handler (pump_bidi inline — R-02/03), pump_handler (pump_bidi inline — R-02/03),
register_tunnel_openable (post-hoc, W2) register_tunnel_openable (post-hoc, W2)
producer/ producer/
params.rs — TunnelParams {resource, substrate} + the UdpHalf params.rs — TunnelParams {resource, substrate} + the UdpHalf
adapter (Send + Sync — F-1) adapter (Send + Sync — F-1)
consumer.rs — hub half: open_reverse_channel (call_with_payload consumer.rs — hub half: open_reverse_channel (call_with_payload
+ auth_token — W1), ReverseTunnel::open_and_pump with optional auth_token — now the fallback
(adopt + pump_bidi), join_and_reap/close (W3), path; primary is transport identity, 0.7.0),
ReverseTunnel::open_and_pump (adopt +
pump_bidi), join_and_reap/close (W3),
bi_stream_from_halves bi_stream_from_halves
harness.rs — wire(): worker = from_connection_with_serving harness.rs — wire()/wire_with(): worker =
(TokenIdProvider — W1) + ChannelOperations:: from_connection_with_serving (transport identity
+ ServingConfig identity/provider — the 0.7.0
precedence chain) + ChannelOperations::
register_on + post-hoc openable; hub = adapter + register_on + post-hoc openable; hub = adapter +
capturing install hook (manager + CallConnection) capturing install hook (manager + CallConnection)
tests/ tests/
tunnel_poc.rs — 14 tests (see Executive summary) tunnel_poc.rs — 16 tests (see Executive summary + §W1)
``` ```
## What the POC does NOT validate ## What the POC does NOT validate
@@ -200,9 +224,12 @@ alktunnels-reverse-poc/
shaped. shaped.
3. **Unix socket + stdio substrates** — OQ-TN-10 #3 (cheap; the pump 3. **Unix socket + stdio substrates** — OQ-TN-10 #3 (cheap; the pump
is substrate-agnostic and both POCs now confirm it). is substrate-agnostic and both POCs now confirm it).
4. **W1 remediation** — only the token path is exercised; whether 4. ~~**W1 remediation**~~**resolved 2026-09-07 (alkcall 0.7.0)**:
alkcall should grow a serving-side identity capture is an upstream the remediation IS now exercised from this POC's topology
question (W1), not resolved here. (transport identity, `ServingConfig.identity` override, precedence,
fail-closed, CF-006 witness). Remaining un-exercised: fingerprint-
based identity resolution (`resolve_from_fingerprint` — the POC's
duplex transport has no TLS layer to fingerprint).
5. **Multi-hop (hub relay traversal)** — single hop; relay forwarding 5. **Multi-hop (hub relay traversal)** — single hop; relay forwarding
(alkcall ADR-042) is transparent per leg. (alkcall ADR-042) is transparent per leg.
6. **Wasm** — POC-local `tokio/net`; the real crate's protocol-only 6. **Wasm** — POC-local `tokio/net`; the real crate's protocol-only
@@ -211,8 +238,10 @@ alktunnels-reverse-poc/
## Verification ## Verification
``` ```
14 tests pass; clippy --all-targets -D warnings clean; fmt clean. 0.6.0 pass: 14 tests; clippy -D warnings clean; fmt clean.
Repeat-run stable (3× clean). 0.7.0 pass: 16 tests (W1 remediation probes added, foreign-token
probe obsoleted by the precedence chain); clippy -D
warnings clean; fmt clean; repeat-run stable (3×).
``` ```
## References ## References