feat(cli): grant installed distro capsules to the target principal#1196
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses an issue where installing a distro via 'astrid init' placed capsule files but failed to grant the necessary permissions for non-default principals to invoke them. By introducing an opt-in '--grant-capsules' flag, users can now ensure that installed capsules are immediately usable. The changes include robust error handling, idempotent grant application, and clear guidance for manual configuration when the flag is not used, ensuring a smoother onboarding experience for non-default principals. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. The capsules land upon the drive, But access rules were not alive. With one new flag, the path is clear, And tools now work for all to hear. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces the --grant-capsules flag to astrid init, allowing users to automatically grant installed distro capsules to a target principal. To support this, the agent modify logic was refactored into a shared, idempotent helper function apply_agent_modify. The feedback focuses on performance improvements in init.rs to eliminate unnecessary allocations and clones, specifically by consuming collections via into_iter() and using std::fmt::Write to build commands directly.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Pull request overview
This PR fixes a principal-provisioning gap in the CLI init flow by adding an opt-in way to grant capsule-access for the capsules installed by a distro, reusing the existing admin.agent.modify kernel path (shared with astrid agent modify).
Changes:
- Add
--grant-capsulestoastrid initand thread it through dispatch into the init implementation. - Factor out a shared
apply_agent_modifyhelper so bothagent modifyandinit --grant-capsulesprovision capsule grants through the same idempotent kernel API. - Add unit tests for the new grant decision/formatting helpers and document the feature in
CHANGELOG.md.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| crates/astrid-cli/src/dispatch.rs | Threads grant_capsules into InitOpts; explicitly disables grants for distro apply. |
| crates/astrid-cli/src/commands/init.rs | Implements post-install grant/hint behavior and grant execution via admin.agent.modify. |
| crates/astrid-cli/src/commands/init_tests.rs | Adds unit tests for grant validation/decision logic and command rendering. |
| crates/astrid-cli/src/commands/agent/mod.rs | Extracts apply_agent_modify and returns a structured outcome used by both commands. |
| crates/astrid-cli/src/cli.rs | Adds the --grant-capsules CLI flag. |
| CHANGELOG.md | Documents the new astrid init --grant-capsules behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
672bd08 to
5b40982
Compare
astrid init installed a distro's capsules per-principal but attached no capsule-access grants, so a non-default principal ended up with the capsule files yet no authority to invoke their tools — provisioning it required an out-of-band, hand-SYNC'd `agent modify --add-capsule` step. Add an opt-in --grant-capsules flag (only meaningful with --distro) that, after the distro's capsules install, grants access for exactly the installed set through the same admin.agent.modify kernel path as `agent modify --add-capsule`, now factored into a shared apply_agent_modify helper. Idempotent across re-runs (kernel apply_set_delta dedups; a failed first grant recovers on the fresh-lock re-run). No-op for the default principal, which holds admin *. Without the flag a non-default install prints the exact agent modify command; on grant failure the capsules are already installed and init exits non-zero with the recovery command. Closes #1195
5b40982 to
1a5a324
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 24 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
crates/astrid-cli/src/dispatch.rs:182
astrid initparsing allows--grant-capsuleswithout--distro(see the CLI test asserting this), but the dispatch layer still hard-errors whendistroisNone. This makes the “operator-enforced distro” scenario described in the PR impossible at runtime, and leaves the CLI surface internally inconsistent (parse succeeds, dispatch fails). Please align either by (a) enforcing--distroat the clap layer and removing the parse-only test/docs, or (b) actually resolving an operator-enforced distro before callingrun_initwhen the flag is omitted.
let distro = distro.ok_or_else(|| {
anyhow::anyhow!(
"astrid init requires --distro <name, @org/repo, path, or .shuttle>; Astrid Runtime does not choose a product distro"
)
})?;
## Linked Issue Closes #1256 ## Summary Closes the remaining first-release bootstrap authority fallbacks without activating the deferred RFC #36 persistence model or adding any product-specific privilege path. ## Changes - reject kernel and admin management requests whose IPC envelope has no valid principal instead of inheriting the `default` administrator - audit missing and malformed admin callers exactly once as reserved no-capability `anonymous` before returning the uniform denial - preserve the local CLI active-principal behavior before requests cross the kernel boundary - attribute principal-less connection lifecycle signals to `anonymous` and ignore malformed identities - abort kernel construction when default administrator profile/key seeding or legacy-profile migration fails - reject `AgentModify` results that remove `default` from the built-in `admin` group while preserving idempotent remove-plus-add - keep caller resolution in a focused private module so the management router remains below the source-file cap - retain the merged device-attenuation, pair-device input-validation, issuance-preflight, cache-refresh, and terminal-audit behavior - add live-router, lifecycle, bootstrap, persistence, administrative, and pair-authority regression coverage ## Verification - restacked onto `main` after #1196 and #1238 merged - signed head: `916238ae54db4e1ea7409a4a82432cc5fe8603a4` - `cargo fmt --all -- --check` - `git diff --check origin/main...HEAD` - `cargo test --locked -p astrid-kernel admin_router_denies_missing_and_invalid_principals_deterministically -- --nocapture` - `cargo clippy --locked -p astrid-kernel --all-features --tests -- -D warnings` - replacement GitHub CI is the complete integration and execution gate ## Checklist - [x] Linked to an issue - [x] CHANGELOG.md updated under `[Unreleased]` No release is created or published by this change.
## Linked Issue Closes #1239 Refs #1237 and astrid-runtime/rfcs#36. ## Summary Carries the authenticated device into capsule dispatch so execution and inventory use the same live authority already enforced at the kernel boundary. The change is generic to Astrid and introduces no product-specific role or trust path. ## Changes - resolve one principal/profile/group/device snapshot per stamped event - reject disabled, malformed, unknown, and revoked identities before matching or grant signalling - use device-effective `capsule:list` only for global describe visibility - activate exact device-effective `capsule:access:any` for unrestricted execution and candidate expansion - preserve exact per-principal capsule grants, no-device/`Full` behavior, and principal-less lifecycle dispatch - emit one `GrantRequired` only for a valid in-view denied match - preserve legacy dispatch when no access resolver is installed - preserve merged authority-cache refresh, pairing preflight, audit classification, and caller-boundary audit behavior - require base `self:auth:pair` authority for pair issuance while retaining the additional `self:auth:pair:admin` gate and elevated audit classification for Full, preset-Full, and explicit-universal scopes - add a dedicated device-scope dispatch regression suite ## Verification - restacked onto `main` after #1196, #1238, and #1257 merged - signed head: `57ec31340db1a1749d5f137a25f4352bb6cb401f` - `cargo fmt --all -- --check` - `git diff --check origin/main...HEAD` - `cargo test --locked -p astrid-capsule` — 563 passed - `cargo test --locked -p astrid-kernel admin_cap_without_base_pair_capability_cannot_issue_full_token -- --nocapture` - `cargo clippy --locked -p astrid-capsule -p astrid-kernel --all-features --tests -- -D warnings` - replacement GitHub CI is the complete integration and execution gate ## Checklist - [x] Linked to an issue - [x] CHANGELOG.md updated under `[Unreleased]` No release is created or published by this change.
Linked Issue
Closes #1195
Summary
astrid initcould install a distro into one principal's home without granting that principal access to invoke the installed capsules. The original implementation also used the process principal as both the authenticated operator and the provisioning target, which made non-default provisioning fail at the finalagent.modifystep.This change adds an explicit, opt-in provisioning contract:
--principalis the authenticated operator;--target-principalis the principal whose home, environment, lock, capsules, and grants are provisioned;--grant-capsulesgrants exactly the transactionally verified installed set through the existingadmin.agent.modifypath.Standalone runtime requires an explicitly selected distro. The optional CLI shape remains available for a later operator-enforced source supplied by an embedding layer. No principal name is treated as privileged.
Changes
init --target-principal <PRINCIPAL>while preserving the process principal as the operator. The target defaults to the process principal when omitted.AgentModifyrequest as a read-only authorization and target-existence preflight before target/workspace provisioning. This preserves the existing public enum, wire method, topic, capability, and audit shape.Capsule.toml, before target-directory creation, backup, or replacement..shuttleinstallation through the checked sink. Existing manual installer APIs andInstallOptionsremain unchanged.Distro.lock.blake3:<hex>, WASM/hash presence equivalence, blob existence, and the BLAKE3 hash of the realbin/<hash>.wasmbytes before issuing grants.apply_agent_modifyhelper for the final atomic grant. A no-flag run prints the exact operator-aware recovery command; a failed grant leaves the verified install and lock for an idempotent retry..shuttleinstalls are identity/version checked but still reject--grant-capsulesuntil their grant composition is explicitly implemented.Verification
cargo fmt --all -- --checkcargo metadata --locked --offline --no-deps --format-version 1bash -n scripts/e2e/runtime-cli-smoke.shgit diff --check34a3a02a7ad1ab266586c3dd548d6d2cac8f188e: all 22 GitHub checks passed, including Ubuntu and macOS tests, Clippy, MSRV, public API compatibility/diff, CodeQL, Gateway OpenAPI, and the real runtime CLI + HTTP sweep.Focused Rust compile/test attempts on the local macOS host stopped during cold Wasmtime dependency compilation without reaching workspace code or emitting a Rust diagnostic; no local Rust pass is claimed. The exact pushed head passed the complete GitHub matrix.
Checklist
CHANGELOG.mdupdated under[Unreleased]