refactor(gateway): migrate to alkcall 0.2 promoted gateway module
Bump the alkcall dependency to 0.2 (with the gateway feature) and converge on the promoted shared pieces: - The local dispatch spine (gateway/dispatch.rs, 721 lines) is deleted; GatewayDispatch, schema_disclosure_denial, and DEFAULT_DEADLINE are re-exported from alkcall::gateway (alkcall ADR-048). The 30 s default deadline preserves the previous behavior exactly. - gateway/schema_cache.rs (PublishSchemaCache) is deleted: alkcall CF-003 compiles publish_schema at registration time and exposes OperationRegistry::publish_validator; the /publish chunk stream resolves against it. Un-compilable schemas are now rejected at registration, so the two end-to-end fail-closed tests were reworked into a registration-rejection test (a stronger guarantee). - schema_disclosure_denial consumers (to_mcp, routes) use alkcall's promoted implementation; the alkhttp-local copy is gone (ADR-071 updated: the guard stays as defense-in-depth, the implementation no longer forks). - CF-001: from_wss drop monitor and the WS overlay tests use CallError::connection_closed; the review-001-ws-eof-signal race tests now assert retryable CONNECTION_CLOSED on both resolution paths (the tolerated non-retryable INTERNAL write-failure outcome is gone). - Added CHANGELOG.md (Keep a Changelog), Unreleased section records the bump and convergence. Verification: cargo test default 453 ok, wss 470 ok, mcp 526 ok, all-features 575 ok; clippy -D warnings clean (default + all-features, all-targets); fmt clean; cargo doc warning-free. Net: -1093 lines.
This commit is contained in:
@@ -68,7 +68,7 @@ types — the former `alknet-core` and `alknet-call` merged).
|
||||
| [068](decisions/068-gateway-publish-endpoint.md) | Gateway `/publish` Endpoint | 6th gateway endpoint for `OperationType::Pub` (producer→consumer streaming); NDJSON request body → `call.published` chunks |
|
||||
| [069](decisions/069-webtransport-out-of-scope.md) | WebTransport Out of Scope | h3/WebTransport removed from alkhttp scope entirely (an alknet concern); supersedes the deferral framing of ADR-044 |
|
||||
| [070](decisions/070-from-wss-consumer-adapter.md) | `from_wss` Consumer Adapter | Import a remote node's operations over WSS — same-protocol importer, channels-over-WS as transport; `wss` feature gate |
|
||||
| [071](decisions/071-dispatch-schema-guard.md) | Dispatch-Spine `services/schema` Op-Path Guard | `GatewayDispatch` applies the GET `/schema` visibility+ACL checks to the meta-op's inner `name` (review-002 PRJ-16); alkcall CF-004 is the complete fix, this stays as defense-in-depth |
|
||||
| [071](decisions/071-dispatch-schema-guard.md) | Dispatch-Spine `services/schema` Op-Path Guard | `GatewayDispatch` applies the GET `/schema` visibility+ACL checks to the meta-op's inner `name` (review-002 PRJ-16); alkcall CF-004 is the complete fix, this stays as defense-in-depth (now via the promoted `alkcall::gateway` shared check — spine + guard themselves live in alkcall per ADR-048) |
|
||||
|
||||
## Relevant Open Questions
|
||||
|
||||
|
||||
@@ -53,23 +53,53 @@ registry rejects non-`Pub` operations before the handler runs and the
|
||||
sink ignores the input, so nothing is projected there.
|
||||
|
||||
The visibility + ACL check itself is one shared function
|
||||
(`gateway::dispatch::schema_disclosure_denial`) used by the HTTP GET
|
||||
`/schema` route, the dispatch-spine guard, and the MCP `schema` tool,
|
||||
so the transports cannot drift.
|
||||
(`schema_disclosure_denial`) used by the HTTP GET `/schema` route, the
|
||||
dispatch-spine guard, and the MCP `schema` tool, so the transports
|
||||
cannot drift.
|
||||
|
||||
## Consequences
|
||||
|
||||
- **Transport-level invariant (PRJ-16's wording):** no alkhttp
|
||||
transport can fetch, through any path, a spec the GET `/schema`
|
||||
route would deny for the same identity.
|
||||
- **When CF-004 lands, the guard stays.** The alkcall-side handler
|
||||
check is the complete fix for every transport (wire, overlays, peer
|
||||
composition); this per-transport check remains as defense-in-depth.
|
||||
Do not remove it.
|
||||
- Wire-observable behavior changes only for the previously-leaking
|
||||
requests: they now get the same 404/403 the GET route returns.
|
||||
Legitimate `services/schema` calls (allowed inner names) are
|
||||
unaffected.
|
||||
- **When CF-004 landed, the guard stayed — and was promoted.** The
|
||||
alkcall-side handler check is the complete fix for every transport
|
||||
(wire, overlays, peer composition; alkcall commit `8cb2a6e`). The
|
||||
alkhttp spine, the GET `/schema` route, the MCP `schema` tool, and
|
||||
the spine's `services/schema` op-path guard all now converge on the
|
||||
**shared promoted implementation**: `alkcall::gateway::
|
||||
schema_disclosure_denial` (alkcall ADR-048). The local copy was
|
||||
deleted on the alkcall-0.2 bump — one implementation, so the
|
||||
transports still cannot drift, and no alkhttp-local fork remains.
|
||||
Do not re-introduce a local copy.
|
||||
- **The dispatch spine itself is promoted too.** `GatewayDispatch`
|
||||
(the `invoke`/`invoke_streaming`/`invoke_sink` spine with the
|
||||
root-`OperationContext` invariants and the inner-`name` guard) is
|
||||
`alkcall::gateway::GatewayDispatch` (feature `gateway`, enabled
|
||||
unconditionally by the alkcall dependency — the gateway endpoints
|
||||
are this crate's sole invoke path, ADR-047). The alkhttp-local copy
|
||||
was deleted; only the HTTP-specific layers remain here (the
|
||||
CallError → HTTP mapping in `gateway::error`, NDJSON/SSE framing,
|
||||
body caps, batch envelopes, and this ADR's original
|
||||
FORBIDDEN-vs-spec-404 split on the GET route).
|
||||
- **`/publish` chunk validation is registry-backed.** The local
|
||||
compile-once `PublishSchemaCache` was deleted: alkcall CF-003
|
||||
compiles `publish_schema` at registration time and exposes the
|
||||
cached validator as `OperationRegistry::publish_validator`. The
|
||||
`/publish` chunk stream resolves against that cache; the
|
||||
fail-closed guarantee moved upstream with it (an un-compilable
|
||||
schema is a registration error, so an unvalidated-ingest path
|
||||
cannot be constructed).
|
||||
- **CF-001 resolution:** alkcall's `CallError::connection_closed`
|
||||
(retryable `CONNECTION_CLOSED`) covers the write-failure race; the
|
||||
from_wss drop-monitor race tests assert retryable-only (the
|
||||
previously-tolerated non-retryable `INTERNAL: failed to write
|
||||
request frame` outcome is gone from the wire vocabulary on the
|
||||
undelivered-request path).
|
||||
- Wire-observable behavior is unchanged from the pre-promotion guard:
|
||||
previously-leaking requests still get the same 404/403 the GET
|
||||
route returns; legitimate `services/schema` calls (allowed inner
|
||||
names) are unaffected.
|
||||
- The guard matches the outer registration's `spec.name` against the
|
||||
`services/schema` constant rather than the raw request string, so
|
||||
leading-slash variants (`/services/schema`) hit the same check.
|
||||
Reference in New Issue
Block a user