Skip to content

fix(capsule): make component→root capability merge exhaustive (#1232) - #1381

Open
jvsteiner wants to merge 2 commits into
astrid-runtime:mainfrom
jvsteiner:fix/1232-exhaustive-capability-merge
Open

fix(capsule): make component→root capability merge exhaustive (#1232)#1381
jvsteiner wants to merge 2 commits into
astrid-runtime:mainfrom
jvsteiner:fix/1232-exhaustive-capability-merge

Conversation

@jvsteiner

@jvsteiner jvsteiner commented Jul 26, 2026

Copy link
Copy Markdown

Linked Issue

Closes #1232.

Summary

discovery.rs folded each [[component]].capabilities into the root manifest field-by-field by hand-enumeration, so any field not explicitly listed was silently dropped — the security gate reads only the root, so a component-only declaration granted nothing, with no error. Dropped fields: net_connect, uplink, kv, identity, allow_persistent, allow_prompt_injection. Concretely, a capsule declaring net_connect at component level couldn't open the connections it asked for.

Changes

  • Add exhaustive CapabilitiesDef::merge_from(&mut self, other) (allowlists concatenated, flags OR-ed). It destructures the source struct with no .. rest pattern, so adding a field to CapabilitiesDef fails to compile there until it's handled — this class of silent-drop can't recur.
  • discovery.rs now calls manifest.capabilities.merge_from(caps) instead of the enumerated merge.

Verification

  • cargo test -p astrid-capsule-types -p astrid-capsule green.
  • merge_from_unions_every_field (fully-populated structs; every field unions) and component_level_capabilities_merge_into_root (the discovery-seam regression: a component-only net_connect surfaces in the root).
  • clippy clean, rustfmt applied.

Checklist

  • Linked to an issue
  • CHANGELOG.md updated

…d-runtime#1232)

discovery.rs folded each [[component]].capabilities into the root
manifest.capabilities field-by-field by hand-enumeration, silently dropping any
field not listed: net_connect, uplink, kv, identity, allow_persistent,
allow_prompt_injection (and bind_workers once the run-loop concurrency work
lands). The security gate reads only the root, so a component-only declaration
granted nothing -- no error, even though `astrid capsule show` displayed it.

Replace the enumerated merge with an exhaustive CapabilitiesDef::merge_from
(allowlists concatenated, flags OR-ed). It destructures the source struct with no
`..` rest pattern, so adding a field fails to compile until it is handled -- this
class of silent-drop bug can't recur.

Adds merge_from_unions_every_field (exhaustiveness guard) and
component_level_capabilities_merge_into_root (discovery-seam regression).

Closes astrid-runtime#1232.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jvsteiner
jvsteiner marked this pull request as ready for review July 26, 2026 12:27
@jvsteiner
jvsteiner requested a review from joshuajbouw as a code owner July 26, 2026 12:27
@jvsteiner

Copy link
Copy Markdown
Author

@joshuajbouw ready for review — exhaustive CapabilitiesDef::merge_from so component-level caps (net_connect etc.) stop getting silently dropped (#1232).

@joshuajbouw

Copy link
Copy Markdown
Member

Review outcome: technically worth advancing. The exhaustive capability merge and regression coverage look correct, and the substantive CI jobs are green. Please fix the required PR-template sections and add the changelog entry so the repository checks can pass.

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.

bug: discovery.rs component→root capability merge silently drops fields not in its enumerated list

2 participants