fix(approval): bind responses to authenticated request owners - #1939
joshuajbouw wants to merge 10 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The canonical native uplink lacks owner propagation and filtering, workspace consumers no longer compile, and WIT regeneration can remove the new package.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds authenticated connection ownership to approval, consent, and grant-on-use routing.
Changes:
- Introduces and propagates opaque request-owner IDs.
- Requires principal and owner matches for responses.
- Adds a WIT API and security regression tests.
File summaries
| File | Description |
|---|---|
crates/astrid-types/src/ipc.rs |
Defines ownership metadata. |
crates/astrid-types/src/ipc_tests.rs |
Updates payload tests. |
crates/astrid-kernel/src/grant_on_use.rs |
Validates grant response owners. |
crates/astrid-kernel/src/grant_on_use_tests.rs |
Tests owner-scoped grants. |
crates/astrid-capsule/wit-staging/deps/[email protected]/[email protected] |
Defines the owner lookup API. |
crates/astrid-capsule/src/engine/wasm/test_fixtures.rs |
Initializes ownership state. |
crates/astrid-capsule/src/engine/wasm/pool.rs |
Clears pooled ownership state. |
crates/astrid-capsule/src/engine/wasm/mod.rs |
Initializes host ownership state. |
crates/astrid-capsule/src/engine/wasm/host/request_context.rs |
Implements owner lookup. |
crates/astrid-capsule/src/engine/wasm/host/net/tcp_stream.rs |
Captures ingress owners. |
crates/astrid-capsule/src/engine/wasm/host/net/tcp_stream_tests.rs |
Tests capture and clearing. |
crates/astrid-capsule/src/engine/wasm/host/mod.rs |
Registers the host module. |
crates/astrid-capsule/src/engine/wasm/host/ipc.rs |
Propagates owners through IPC. |
crates/astrid-capsule/src/engine/wasm/host/ipc_tests.rs |
Tests IPC propagation. |
crates/astrid-capsule/src/engine/wasm/host/consent_egress.rs |
Owner-scopes egress consent. |
crates/astrid-capsule/src/engine/wasm/host/consent_egress_tests.rs |
Tests consent isolation. |
crates/astrid-capsule/src/engine/wasm/host/approval.rs |
Owner-scopes approvals. |
crates/astrid-capsule/src/engine/wasm/host/approval_tests.rs |
Tests approval isolation. |
crates/astrid-capsule/src/engine/wasm/host_state.rs |
Stores connection ownership. |
crates/astrid-capsule/src/engine/wasm/host_state_tests.rs |
Tests owner minting. |
crates/astrid-capsule/src/engine/wasm/host_state_hook.rs |
Initializes hook state. |
crates/astrid-capsule/src/engine/wasm/host_state_connection.rs |
Mints connection owners. |
crates/astrid-capsule/src/engine/wasm/bindings.rs |
Imports the WIT API. |
crates/astrid-capsule/src/dispatcher.rs |
Carries owners into grant requests. |
crates/astrid-capsule/src/dispatcher_tests.rs |
Tests owned dispatch. |
crates/astrid-capsule/src/dispatcher_device_scope_tests.rs |
Updates dispatcher fixtures. |
crates/astrid-capsule/src/access.rs |
Rejects unowned grant prompts. |
changes/1936.fixed.md |
Records the security fix. |
Review details
Suppressed comments (1)
crates/astrid-types/src/ipc.rs:323
- The new required
GrantRequiredfield is missing from the three constructors incrates/astrid-gateway/src/routes/agent/tests.rs:365-395, so the gateway test target no longer compiles. Update those fixtures with an owner (and matching message metadata where appropriate).
/// Host-minted connection owner that may answer this request.
request_owner: String,
- Files reviewed: 29/29 changed files
- Comments generated: 3
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
8d8e11d to
f062c12
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Ownerless native prompts and same-principal HTTP control streams still bypass the intended request-owner isolation.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 39/39 changed files
- Comments generated: 4
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
66fc868 to
40dbb29
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Native egress still permits owner-matching approval prompts from untrusted capsule sources.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 40/40 changed files
- Comments generated: 2
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
40dbb29 to
48dd1bc
Compare
There was a problem hiding this comment.
🟡 Changes recommended
HTTP filtering still occurs after queue admission, and native capsule-command approvals lack an owning response path.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 42/42 changed files
- Comments generated: 3
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
48dd1bc to
dff220f
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The cancellation smoke helper ignores its passed refreshed bearer and instead uses an older dynamically scoped token.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 42/42 changed files
- Comments generated: 1
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
dff220f to
249af6b
Compare
Carry authenticated request ownership through native and HTTP transports so concurrent same-principal sessions cannot observe or answer each other’s approval prompts. API-CONTRACT-CHANGE: scope approval control streams and responses to signed bearer ownership Signed-off-by: Joshua J. Bouw <[email protected]>
249af6b to
12da154
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The owning capsule CLI ignores owner-routed GrantRequired frames, causing ungranted commands to time out instead of completing consent and retrying.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 50/50 changed files
- Comments generated: 1
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
Signed-off-by: Joshua J. Bouw <[email protected]>
There was a problem hiding this comment.
🟡 Changes recommended
The CLI can retry a granted command before the asynchronous kernel grant has been persisted.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 50/50 changed files
- Comments generated: 1
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
Signed-off-by: Joshua J. Bouw <[email protected]>
Signed-off-by: Joshua J. Bouw <[email protected]>
There was a problem hiding this comment.
🟡 Changes recommended
Grant responses can race waiter registration and be permanently lost.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 52/52 changed files
- Comments generated: 2
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
Signed-off-by: Joshua J. Bouw <[email protected]>
There was a problem hiding this comment.
🟡 Changes recommended
Late approvals can bypass the timeout, grant tasks can grow without bound, and two CLI/E2E error-handling issues remain.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 52/52 changed files
- Comments generated: 4
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
Signed-off-by: Joshua J. Bouw <[email protected]>
There was a problem hiding this comment.
🟡 Changes recommended
Native grant acknowledgements omit required wire metadata, and malformed approval payloads can bypass the typed egress validation.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
crates/astrid-cli/src/commands/capsule_verb.rs:559
- A genuine native
GrantResultcan never satisfy this check.native::write_messageserializes onlytopic,payload,source_id, andprincipal(crates/astrid-uplink/src/native/mod.rs:524-537), soraw.get("request_owner")is always absent even though the internal message was owner-stamped. The CLI therefore ignores the durable acknowledgement, times out, and never performs its one retry. Serializerequest_owneron the native frame (with a wire-level regression), or remove this impossible top-level check while retaining the payload/source correlation.
crates/astrid-types/src/ipc_tests.rs:257 - The updated “exhaustive” count is still one short:
IpcPayloadnow has 20 represented/known non-Unknownvariants, but this table omits the existingToolCancelRequestvariant. Because bothrepresentatives.len()and this constant remain 19, the guard passes while not being exhaustive. Add aToolCancelRequestrepresentative and set the count to 20.
- Files reviewed: 52/52 changed files
- Comments generated: 1
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
Signed-off-by: Joshua J. Bouw <[email protected]>
There was a problem hiding this comment.
🔵 Needs a closer look
The cross-layer security change requires human validation, and the review found incomplete API coverage and stale security-model documentation.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
crates/astrid-capsule/src/engine/wasm/host/request_context.rs:13
- The only test in this new module exercises
connection_principal; it never callsconnection_owner. The primary new WIT API could therefore return the wrong owner (or mishandle unbound/invalid resources) without failing this suite. Add owner assertions for the unbound, bound, and invalid-handle cases alongside the principal assertions.
crates/astrid-kernel/src/grant_on_use.rs:85 - The module-level security model still says each correlation uses a per-request awaiter task and that there is no shared correlation table, but this new design stores correlations in this
HashMapand only spawns the durable-completion task after approval. That description is now materially misleading for security/resource reviews; update it to describe the ordered observer and semaphore-bounded map.
- Files reviewed: 52/52 changed files
- Comments generated: 0 new
- Review effort level: Balanced (auto)
Note
Copilot is running an experiment and ran this review at Balanced.
Signed-off-by: Joshua J. Bouw <[email protected]>
|
@copilot review |
Co-authored-by: joshuajbouw <[email protected]>
Co-authored-by: joshuajbouw <[email protected]>
Linked Issues
Closes #1936
Closes #1940
Summary
Bind every interactive approval to the authenticated request that caused it, expose the authenticated local connection principal to host capsules, and retry grant-gated CLI commands only after the kernel confirms the grant is durably installed.
Changes
GrantResultacknowledgement after durable grant persistence, then retry the dropped command exactly onceThe WIT contract landed in astrid-runtime/wit#25 and astrid-runtime/wit#26. SDK ownership support landed in astrid-runtime/sdk-rust#68; authenticated-principal support is in astrid-runtime/sdk-rust#70. AOS consumption is tracked by unicity-aos/aos-ce#175 and unicity-aos/aos-ce#176.
Verification
cargo test -p astrid-events -p astrid-gateway -p astrid-uplink -p astrid --lib --bins(767 CLI, 82 event-bus, 175 gateway, and 47 uplink tests passed before the final focused successor)cargo test -p astrid-types --features clock grant_result(2 passed)cargo test -p astrid-kernel grant_on_use::tests(15 passed, including an immediate response with no settling delay)cargo test -p astrid-capsule request_context(1 passed)cargo test -p astrid-uplink native::(34 passed, including owner metadata on the native wire and malformed approval rejection)cargo test -p astrid --bin astrid commands::capsule_verb(14 passed)cargo clippy -p astrid-types -p astrid-kernel -p astrid-capsule -p astrid-uplink -p astrid --all-targets --all-features -- -D warningscargo check -p astrid -p astrid-kernel -p astrid-capsule -p astrid-uplinkTMPDIR=/tmp ASTRID_E2E_SKIP_BUILD=1 ASTRID_E2E_CAPSULES_DIR=/tmp/astrid-aos-stage.Dbn3hy/capsules scripts/e2e/runtime-harness.sh(full runtime E2E passed through approvals, isolation, restart, crash recovery, capsule cancellation/lifecycle, and audit collection before the final focused successor)cargo fmt --all -- --checkgit diff --checkAI / Tool Assistance
Assisted-by: Codex:gpt-6-astra
Codex helped trace the ownership path across native sockets, signed HTTP bearers, the event bus, approval waiters, durable grant installation, control streams, and regression tests. I reviewed the exact diff and validated it with the compile, focused tests, strict clippy, formatting, and runtime journey listed above.
Checklist
changes/1936.fixed.mdSigned-off-bytrailer.