Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(approval): bind responses to authenticated request owners - #1939

Open
joshuajbouw wants to merge 10 commits into
mainfrom
fix/approval-request-ownership
Open

joshuajbouw wants to merge 10 commits into
mainfrom
fix/approval-request-ownership

Conversation

@joshuajbouw

@joshuajbouw joshuajbouw commented Sep 15, 2026

Copy link
Copy Markdown
Member

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

  • mint an opaque owner for each authenticated native-uplink connection
  • mint a signed random owner in each new HTTP bearer while preserving legacy bearer verification
  • carry ownership through host-stamped IPC metadata and capsule fan-out
  • expose local connection ownership and the host-authenticated principal through the additive request-context WIT host API
  • require exact principal and owner matches for approval, local-egress consent, and grant-on-use responses
  • derive HTTP approval ownership from the verified bearer rather than accepting an owner from the request body
  • reject wrong-owner approval traffic before route queue admission, so peer sessions cannot consume the intended owner's queue budget
  • handle capsule approval prompts in the owning CLI: non-interactive callers deny immediately, while TTY callers can approve once or deny without preventing daemon-exit and capsule-unload cancellation
  • handle owner-routed grant prompts in the CLI, register request/response correlation through one ordered bounded kernel observer, wait for an exact kernel-sourced GrantResult acknowledgement after durable grant persistence, then retry the dropped command exactly once
  • keep elicitation principal-scoped while making approval and grant control request-scoped
  • fail closed for forged, unattributed, ownerless, or internally inconsistent approval prompts and responses
  • make the runtime E2E shutdown helper wait for the daemon's real signal/finalization path instead of truncating volume packing with a generic five-second reaper
  • add cross-owner, same-principal peer, missing-owner, legacy-bearer, propagation, queue-budget, CLI, HTTP, native, cancellation, crash, restart, authenticated-principal, and durable-grant regressions

The 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 warnings
  • cargo check -p astrid -p astrid-kernel -p astrid-capsule -p astrid-uplink
  • TMPDIR=/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 -- --check
  • git diff --check

AI / 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

  • Linked to issues
  • Changelog fragment added under changes/1936.fixed.md
  • I understand every change in this PR and can explain its design, risks, and validation.
  • I reviewed and tested any meaningful tool-generated output included in this PR.
  • Every non-bot, non-merge commit has a matching Signed-off-by trailer.

Copilot AI balanced review requested due to automatic review settings September 15, 2026 00:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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 GrantRequired field is missing from the three constructors in crates/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.

Comment thread crates/astrid-types/src/ipc.rs
Comment thread crates/astrid-types/src/ipc.rs
@joshuajbouw
joshuajbouw force-pushed the fix/approval-request-ownership branch 4 times, most recently from 8d8e11d to f062c12 Compare September 15, 2026 01:19
@joshuajbouw
joshuajbouw requested a balanced review from Copilot September 15, 2026 01:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread crates/astrid-gateway/src/routes/agent.rs Outdated
Comment thread crates/astrid-uplink/src/native/egress.rs Outdated
Comment thread crates/astrid-capsule/src/engine/wasm/host/approval.rs Outdated
Comment thread crates/astrid-capsule/src/engine/wasm/host/consent_egress.rs Outdated
@joshuajbouw
joshuajbouw force-pushed the fix/approval-request-ownership branch 2 times, most recently from 66fc868 to 40dbb29 Compare September 15, 2026 02:17
@joshuajbouw
joshuajbouw requested a balanced review from Copilot September 15, 2026 02:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread crates/astrid-uplink/src/native/egress.rs Outdated
Comment thread scripts/e2e/runtime-adversarial-smoke.sh Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread crates/astrid-uplink/src/native/egress.rs Outdated
Comment thread crates/astrid-gateway/src/routes/agent.rs
Comment thread scripts/e2e/runtime-adversarial-smoke.sh
@joshuajbouw
joshuajbouw requested a balanced review from Copilot September 15, 2026 02:43
@joshuajbouw
joshuajbouw force-pushed the fix/approval-request-ownership branch from 48dd1bc to dff220f Compare September 15, 2026 02:46
@joshuajbouw
joshuajbouw requested a balanced review from Copilot and removed request for Copilot September 15, 2026 02:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread scripts/e2e/runtime-hostcall-cancel-smoke.sh
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]>
@joshuajbouw
joshuajbouw force-pushed the fix/approval-request-ownership branch from 249af6b to 12da154 Compare September 15, 2026 05:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread crates/astrid-cli/src/commands/capsule_verb.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread crates/astrid-cli/src/commands/capsule_verb.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread crates/astrid-kernel/src/grant_on_use.rs Outdated
Comment thread scripts/e2e/runtime-adversarial-smoke.sh

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread crates/astrid-kernel/src/grant_on_use.rs
Comment thread crates/astrid-kernel/src/grant_on_use.rs
Comment thread scripts/e2e/runtime-adversarial-smoke.sh Outdated
Comment thread crates/astrid-cli/src/commands/capsule_verb.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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 GrantResult can never satisfy this check. native::write_message serializes only topic, payload, source_id, and principal (crates/astrid-uplink/src/native/mod.rs:524-537), so raw.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. Serialize request_owner on 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: IpcPayload now has 20 represented/known non-Unknown variants, but this table omits the existing ToolCancelRequest variant. Because both representatives.len() and this constant remain 19, the guard passes while not being exhaustive. Add a ToolCancelRequest representative 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.

Comment thread crates/astrid-uplink/src/native/egress.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 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 calls connection_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 HashMap and 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.

@joshuajbouw

Copy link
Copy Markdown
Member Author

@copilot review

Copilot AI commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

@copilot review

Addressed in d092b1b: legacy bearer verification now rejects non-canonical numeric claim encodings, and the gateway auth regression covers the rewritten-token case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Carry authenticated request ownership through approval events Expose authenticated connection principal through request context

3 participants