feat: alkcall 0.7.0 adoption (CF-006 identity alignment) — bump to 0.4.0

- BREAKING (ecosystem-coordination): alkcall bumped to 0.7.0. No type
  alktty touches changed shape (OpenEstablisher/OpenHandler/
  Establishment/ChannelPlan identical to 0.6.0); the minor bump is for
  downstream lockstep, since alktty's public signatures reference
  alkcall types.
- CF-006 alignment: the channels establisher and pump handler now take
  their identity from the per-call auth (alkcall 0.7 derives the
  dispatch-resolved opener — the same identity view the registry's ACL
  gate checked) instead of the captured install-time override.
  Behavior-identical in the per-connection-registry deployment; the
  ownership check and the ACL gate see the same subject in every
  deployment. make_tty_establisher / make_tty_open_handler drop their
  captured-identity parameter (both private).

Verification:
- cargo test: 113 passed (default), 156 passed (--all-features)
- cargo clippy --all-targets -- -D warnings: clean
- cargo fmt --check: clean
- cargo doc --no-deps: clean
- cargo check/clippy --target wasm32-unknown-unknown -D warnings: clean
- cargo publish --dry-run --allow-dirty: clean
This commit is contained in:
glm-5.3-flash committed 2026-09-07 17:57:36 +00:00
1 parent bc4a9b6024
commit 67cf253621
4 files changed
+53 -25

No files matched your search

+29
View File
@@ -4,6 +4,35 @@ All notable changes to this crate are documented here. The format is
based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
this crate adheres to [Semantic Versioning](https://semver.org/).
## [0.4.0] - 2026-09-07
The alkcall 0.7.0 adoption (the connect-side caller-identity seam,
CF-005/006/007): a dependency bump plus one behavior-alignment change
on the channels path. The wire format, the direct-ALPN path, the
`TtyBackend` trait, and the public API surface are unchanged.
### Changed
- **BREAKING (ecosystem-coordination) — `alkcall` bumped to 0.7.0.**
alkcall 0.7.0 changed no type that alktty touches
(`OpenEstablisher`/`OpenHandler`/`Establishment`/`ChannelPlan` are
identical to 0.6.0; alktty never constructs `ServingConfig`), but
alktty's public signatures reference alkcall types, so downstream
crates must now unify on alkcall 0.7.0. Minor bump per the 0.x
ecosystem-coordination rule.
- **The channels establisher and pump handler take their identity
from the per-call `auth` (CF-006 alignment).** `register_openable`
no longer captures the install-time identity and overrides the
establisher/handler `auth.identity` with it — post-alkcall-0.7 the
per-call context already carries the dispatch-resolved opener (the
same identity view the registry's ACL gate checked; the end client,
not the hub, on hub-forwarded opens). Behavior-identical in the
per-connection-registry deployment (install-time identity was the
caller's); the ownership check and the ACL gate now see the same
subject in every deployment. Two factory parameters dropped
(`make_tty_establisher`/`make_tty_open_handler` are private; no
public-surface change).
## [0.3.0] - 2026-09-07
The alkcall 0.6.0 adoption (review 007 R-01 — the `Establishment`
Generated
+3 -3
View File
@@ -27,9 +27,9 @@ dependencies = [
[[package]]
name = "alkcall"
version = "0.6.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44500900b82904d2a870e444051fc041a042e42ff7190803bbc5b3973f4feeb"
checksum = "5162a10144df65b03b887e30f77eb30d956ca1ca460a3f81b409128cbcae3199"
dependencies = [
"async-trait",
"bytes",
@@ -48,7 +48,7 @@ dependencies = [
[[package]]
name = "alktty"
version = "0.3.0"
version = "0.4.0"
dependencies = [
"alkcall",
"async-trait",
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "alktty"
version = "0.3.0"
version = "0.4.0"
edition = "2021"
rust-version = "1.85"
license = "MIT OR Apache-2.0"
@@ -25,7 +25,7 @@ default = []
local = ["dep:portable-pty", "dep:tokio-util", "tokio/process", "tokio/rt-multi-thread"]
[dependencies]
alkcall = "0.6.0"
alkcall = "0.7.0"
# Minimal, wasm-clean tokio features. `local` adds `process` +
# `rt-multi-thread` (non-wasm). Do NOT use `features = ["full"]` — it
# pulls in `signal`/`fs`/`net` which break `wasm32-unknown-unknown`.
+19 -20
View File
@@ -98,10 +98,12 @@ pub const TTY_ALPN: &str = "alk/tty";
/// the entry point (here by the registry's `AccessControl`), the
/// ownership check is enforced once at the backend-selection point.
///
/// `auth` is the peer's `AuthContext`, captured at
/// `install_channel_zero` time and closed over by the wrapper so the
/// `TtyOpenHandler` receives it without the wrapper having to reach
/// into `OperationContext` for it (per the ADR-047 §4 amendment).
/// `auth` is the peer's `AuthContext`, the install-time context passed
/// through to `register_openable_with_establisher`. The establisher
/// and pump handler read their identity from the per-call context
/// alkcall derives (alkcall 0.7, CF-006 corollary) — the
/// dispatch-resolved opener, the same view the registry's ACL gate
/// checked.
///
/// # Errors
///
@@ -117,8 +119,8 @@ pub fn register_openable(
auth: AuthContext,
) -> Result<(), String> {
let spec = tty_open_spec();
let establisher = make_tty_establisher(Arc::clone(&backends), ownership, auth.identity.clone());
let open_handler = make_tty_open_handler(backends, auth.identity.clone());
let establisher = make_tty_establisher(Arc::clone(&backends), ownership);
let open_handler = make_tty_open_handler(backends);
core.register_openable_with_establisher(
spec,
Some(establisher),
@@ -239,11 +241,12 @@ pub fn tty_open_spec() -> OperationSpec {
/// returned.
///
/// The `tty:open` scope gate is NOT checked here — the registry's
/// `AccessControl` enforced it before the establisher ran (the
/// identity view the registry checked, resolved from the connection,
/// is the authoritative one; the establisher-side identity is only
/// the ownership-check subject — the same split as the old
/// handler-side check).
/// `AccessControl` enforced it before the establisher ran. The
/// establisher's `auth` is the per-call context (alkcall 0.7, CF-006
/// corollary): its identity is the dispatch-resolved opener — the same
/// identity view the registry's ACL gate checked — and is the
/// ownership-check subject (the same split as the old handler-side
/// check).
///
/// Mapping into the ADR-049 reason vocabulary (no new codes — the
/// vocabulary is alkcall's one-way wire surface):
@@ -275,12 +278,11 @@ pub fn tty_open_spec() -> OperationSpec {
fn make_tty_establisher(
backends: Arc<HashMap<String, Arc<dyn TtyBackend>>>,
ownership: Option<Arc<dyn OwnershipProvider>>,
identity: Option<alkcall::core::auth::Identity>,
) -> OpenEstablisher {
Arc::new(move |input: Value, auth: AuthContext| {
let backends = Arc::clone(&backends);
let ownership = ownership.clone();
let identity = identity.clone().or_else(|| auth.identity.clone());
let identity = auth.identity.clone();
Box::pin(async move {
let req: NegotiateRequest = match serde_json::from_value(input) {
Ok(r) => r,
@@ -388,17 +390,14 @@ impl AllocatedHandle {
///
/// The `tty:open` scope gate is enforced by the registry's `AccessControl`
/// before this handler runs — the handler does not re-check it.
fn make_tty_open_handler(
backends: Arc<HashMap<String, Arc<dyn TtyBackend>>>,
identity: Option<alkcall::core::auth::Identity>,
) -> OpenHandler {
fn make_tty_open_handler(backends: Arc<HashMap<String, Arc<dyn TtyBackend>>>) -> OpenHandler {
Arc::new(
move |input: Value,
plan: Option<ChannelPlan>,
channel_conn: Connection,
auth: AuthContext| {
let backends = Arc::clone(&backends);
let identity = identity.clone().or_else(|| auth.identity.clone());
let identity = auth.identity.clone();
tokio::spawn(async move {
let req: NegotiateRequest = match serde_json::from_value(input) {
@@ -523,7 +522,7 @@ mod tests {
let mut backends: HashMap<String, Arc<dyn TtyBackend>> = HashMap::new();
backends.insert("mock".to_string(), Arc::new(MockBackend::with_exit_code(0)));
let handler = make_tty_open_handler(Arc::new(backends), None);
let handler = make_tty_open_handler(Arc::new(backends));
let task = handler(
serde_json::json!({
@@ -577,7 +576,7 @@ mod tests {
ownership: Option<Arc<dyn OwnershipProvider>>,
input: Value,
) -> Result<Establishment, EstablishmentError> {
let establisher = make_tty_establisher(backends, ownership, None);
let establisher = make_tty_establisher(backends, ownership);
establisher(input, AuthContext::anonymous(b"test")).await
}