Skip to content

feat(seal-policy): add DbusFilterRule typed D-Bus filter rules + dbus_filter field on BundleSpec/GrantToolEntry/KernelParams (SEA-780 slice 1)#511

Closed
mattwilkinsonn wants to merge 4 commits into
mainfrom
sea-780-dbus-proxy-slice-1--athena
Closed

feat(seal-policy): add DbusFilterRule typed D-Bus filter rules + dbus_filter field on BundleSpec/GrantToolEntry/KernelParams (SEA-780 slice 1)#511
mattwilkinsonn wants to merge 4 commits into
mainfrom
sea-780-dbus-proxy-slice-1--athena

Conversation

@mattwilkinsonn

@mattwilkinsonn mattwilkinsonn commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Pull request

Summary

Introduces typed D-Bus session-bus filter rules (DbusFilterRule, BusName, InterfaceMatch, PathMatch) for the curated bundle catalog, wires them through BundleSpecGrantToolEntryKernelParams as rendered xdg-dbus-proxy CLI flag strings, and adds the compile-time resolver that aggregates, dedupes, and sorts the rules across all bundles applicable to a spawn. This is SEA-780 slice 1 — the typed shape and audit-chain plumbing that later slices build the dispatcher integration and per-bundle defaults on top of.

Related issues

Refs SEA-780, SEA-571, SEA-769

Changes

  • Adds crates/seal-policy/src/manifest/dbus_filter.rs with DbusFilterRule (Talk, See, Call variants), BusName, InterfaceMatch, and PathMatch newtypes. Each has new_unchecked for const-constructible catalog entries and TryFrom<String> / TryFrom<&str> for future user-bundle deserialization. to_flag() renders each rule into its exact xdg-dbus-proxy CLI flag form.
  • Adds dbus_filter: &'static [DbusFilterRule] to BundleSpec (all existing bundles default to &[]).
  • Propagates rendered flag strings into GrantToolEntry::dbus_filter (elided from canonical JSON when empty, so existing grants don't re-sign).
  • Adds dbus_filter_rules: Vec<String> to KernelParams (elided from canonical JSON when empty). Changing the rule set flips the audit hash, identical to the domains / psl_exemptions closure.
  • Adds resolve_dbus_filter_rules in seal-sandbox/src/compile.rs that mirrors apply_bundles's applicability predicate — including the SEA-571/SEA-769 direnv-wrap and gh credential-helper widenings — then dedupes and sorts the collected flag strings.
  • Adds every_bundle_dbus_filter_rule_validates catalog test that walks every BundleSpec::dbus_filter entry and calls rule.validate(), catching typos that new_unchecked skips at construction time.

Test plan

  • New unit tests in dbus_filter.rs cover BusName, InterfaceMatch, and PathMatch validation (well-formed, empty, invalid chars, length cap, leading-hyphen, trailing-slash, empty-segment, round-trip TryFrom), and DbusFilterRule::to_flag rendering for all three variants including wildcard members.
  • New compile-module tests cover: empty rules when no bundle requests D-Bus access; aggregation when a bundle applies; deduplication across two bundles sharing a rule; non-aggregation when the bundle doesn't apply on the spawn; and hash-flip when dbus_filter_rules changes.
  • every_bundle_dbus_filter_rule_validates catalog test guards against malformed rule strings in the static BUNDLES table.
  • All existing test fixtures updated with dbus_filter_rules: Vec::new() to keep the struct exhaustive.

Notes for reviewers

All bundles carry dbus_filter: &[] in this slice — no behavioral change to any existing spawn. The gh_dbus_disabled bypass (SEA-571/SEA-769) is untouched here; slice 4 retires it once the proxy is the only path. The rendered-string-rather-than-typed-enum choice in KernelParams and GrantToolEntry is intentional: it decouples audit-chain stability from future DbusFilterRule variant additions and lets the dispatcher (slice 2) push strings directly onto the proxy argv without re-parsing.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

@linear-code

linear-code Bot commented Jun 11, 2026

Copy link
Copy Markdown

SEA-780

SEA-571

SEA-769

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9fed5005-cba5-485a-babf-9b10106c493e

📥 Commits

Reviewing files that changed from the base of the PR and between 0ec85d9 and 585862e.

📒 Files selected for processing (1)
  • crates/seal-sandbox/src/compile.rs

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Per-bundle D‑Bus session-bus filter rules can be attached, aggregated for applicable sandboxes, deduplicated, sorted, and rendered as xdg-dbus-proxy flags; empty lists are omitted from canonical hashes and runtime params.
    • Manifest API now exposes typed D‑Bus filter rule types; kernel/launch parameters include an explicit D‑Bus filter rule list.
  • Tests

    • Added validation, flag-rendering, aggregation, deduplication, applicability, and hash-regression tests.

Walkthrough

Adds typed D-Bus session-bus filter rules to the manifest, validates them, renders rules to xdg-dbus-proxy flag strings into grants, aggregates sorted/deduped rules into KernelParams during compile, and updates tests/fixtures.

Changes

D-Bus Session-Bus Filtering for Sandbox Bundles

Layer / File(s) Summary
D-Bus filter rule type model and validation
crates/seal-policy/src/manifest/dbus_filter.rs, crates/seal-policy/src/manifest.rs
Adds BusName, InterfaceMatch, PathMatch, DbusFilterRule, validation and error types, to_flag() rendering, unit tests, and re-exports.
Bundle specification with D-Bus filter rules
crates/seal-policy/src/manifest/sandbox.rs
Extends BundleSpec with dbus_filter: &'static [DbusFilterRule], documents aggregation semantics, initializes curated bundles with &[], and adds a validation test iterating bundles' rules.
Grant payload synthesis with D-Bus filters
crates/seal-policy/src/grant.rs
Adds dbus_filter: Vec<String> to GrantToolEntry (serde elided when empty); synthesizes flags from manifest rules via rule.to_flag(), sorts and dedupes, and includes field in grant canonical JSON/hash.
Kernel parameters aggregation and compilation
crates/seal-sandbox/src/kernel_params.rs, crates/seal-sandbox/src/compile.rs
Adds dbus_filter_rules: Vec<String> to KernelParams (serde elision); adds resolve_dbus_filter_rules() to aggregate/dedupe/sort applicable bundles' rendered flags (including indirect direnv/gh cases); wires resolver into compile() and adds tests for empty/aggregated/deduped/skipped/hash-change cases.
Test fixture updates
crates/seal-runtime/src/scope/sandbox_spawn/*.rs, crates/seal-runtime/tests/bwrap_dispatcher_integration.rs, crates/seal-sandbox/src/*.rs, crates/seal-sandbox/tests/*.rs
Updates test helpers/fixtures to initialize KernelParams.dbus_filter_rules: Vec::new() so tests compile and snapshots remain deterministic.
sequenceDiagram
  participant Manifest as manifest::BundleSpec
  participant Validator as DbusFilterRule::validate
  participant GrantSynth as GrantToolEntry::from_manifest_entry
  participant Compile as seal_sandbox::compile
  participant Kernel as KernelParams
  Manifest->>Validator: validate each rule (rule.validate())
  Manifest->>GrantSynth: provide DbusFilterRule items
  GrantSynth->>GrantSynth: rule.to_flag(), sort, dedupe
  GrantSynth-->>Compile: include dbus_filter strings
  Compile->>Compile: resolve_dbus_filter_rules()
  Compile-->>Kernel: set dbus_filter_rules
Loading

🎯 4 (Complex) | ⏱️ ~45 minutes

🐰 The bundles now speak with care,
D-Bus rules float through the air,
Aggregated, sorted, clean,
A tiny proxy rule machine,
Hop, render, guard with flair!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: introducing typed D-Bus filter rules and adding dbus_filter fields across BundleSpec, GrantToolEntry, and KernelParams, with specific SEA-780 slice reference.
Description check ✅ Passed The description is detailed and directly related to the changeset, explaining the motivation, architecture, implementation details, test coverage, and design decisions for the D-Bus filter rules feature.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sea-780-dbus-proxy-slice-1--athena

Comment @coderabbitai help to get the list of available commands and usage tips.

mattwilkinsonn commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • Merge Queue - adds this PR to the back of the merge queue
  • Merge Queue Fast Track - for urgent changes, fast-track this PR to the front of the merge queue

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has required the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/seal-policy/src/grant.rs`:
- Around line 713-725: The dbus_filter Vec built from bundle.dbus_filter
currently preserves catalog order and duplicates, causing different grant hashes
for semantically identical policies; after mapping with rule.to_flag() but
before assigning into the grant payload (the local dbus_filter variable used by
GrantToolEntry), sort_unstable the Vec and then dedup it so the rendered flags
are canonicalized (stable order, no duplicates) to match the downstream
KernelParams normalization.

In `@crates/seal-policy/src/manifest/dbus_filter.rs`:
- Around line 53-80: Update the validation logic to match the xdg-dbus-proxy
NAME/RULE grammar: in validate_bus_name (affecting BusName) allow
segment-leading '-' per the file's documented regex (i.e., accept [A-Za-z_-] as
first char), in validate_interface_match (affecting InterfaceMatch) permit '.'
in names and support the interface wildcard form '.*' while still rejecting
member names that start with a digit (so enforce member-leading char ≠ digit),
and in validate_path_match (affecting PathMatch) prohibit '*' in arbitrary path
segments and only accept the documented subtree wildcard as a trailing '/*'
suffix; keep error returns using DbusFilterRuleError variants already used so
callers (e.g., try_from) continue to get DbusFilterRuleError::Invalid... on
malformed input.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c0b77c7f-dbbd-4d7a-b582-c5dd072826e4

📥 Commits

Reviewing files that changed from the base of the PR and between 57c3358 and 0581535.

📒 Files selected for processing (14)
  • crates/seal-policy/src/grant.rs
  • crates/seal-policy/src/manifest.rs
  • crates/seal-policy/src/manifest/dbus_filter.rs
  • crates/seal-policy/src/manifest/sandbox.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/linux.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/macos.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/mod.rs
  • crates/seal-runtime/tests/bwrap_dispatcher_integration.rs
  • crates/seal-sandbox/src/compile.rs
  • crates/seal-sandbox/src/kernel_params.rs
  • crates/seal-sandbox/src/linux.rs
  • crates/seal-sandbox/src/macos.rs
  • crates/seal-sandbox/tests/bwrap_integration.rs
  • crates/seal-sandbox/tests/sandbox_exec_integration.rs

Comment thread crates/seal-policy/src/grant.rs
Comment thread crates/seal-policy/src/manifest/dbus_filter.rs
@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces typed D-Bus session-bus filter rules (DbusFilterRule, BusName, InterfaceMatch, PathMatch) and wires them through BundleSpecGrantToolEntryKernelParams as rendered xdg-dbus-proxy CLI flag strings. It is SEA-780 slice 1 — the typed shape and audit-chain plumbing that later slices will build the actual proxy dispatch and per-bundle defaults on top of.

  • Adds crates/seal-policy/src/manifest/dbus_filter.rs with newtype validators, to_flag() rendering, and a comprehensive unit test suite for BusName, InterfaceMatch, and PathMatch.
  • Propagates an empty dbus_filter: &[] field to every existing BundleSpec, adds dbus_filter: Vec<String> to GrantToolEntry (elided from canonical JSON when empty), and dbus_filter_rules: Vec<String> to KernelParams (same elision), so no existing grant re-signs.
  • Adds resolve_dbus_filter_rules in seal-sandbox/src/compile.rs that mirrors apply_bundles's direnv-wrap and gh credential-helper widening predicates, deduplicates via HashSet, and sorts for a deterministic canonical-form hash.

Confidence Score: 5/5

All existing bundles default to empty dbus_filter, so no behavioral change reaches any current spawn; the new audit-chain fields elide from canonical JSON when empty, so no existing grant re-signs.

The typed newtype validation logic is correct, the applicability predicate in resolve_dbus_filter_rules exactly mirrors apply_bundles (direnv-wrap and gh credential-helper widenings included), the HashSet dedup is O(n) and correct, and the serde elision guards are in place on all three new fields. The catalog test every_bundle_dbus_filter_rule_validates closes the new_unchecked safety gap. No logic errors, data-loss paths, or audit-hash stability risks were found.

No files require special attention; the core logic lives in dbus_filter.rs and compile.rs, both of which are well-tested and correct.

Important Files Changed

Filename Overview
crates/seal-policy/src/manifest/dbus_filter.rs New file: typed D-Bus filter rule newtypes with validation, to_flag rendering, and thorough unit tests; logic is correct.
crates/seal-sandbox/src/compile.rs Adds resolve_dbus_filter_rules with correct HashSet dedup + sort; predicate mirrors apply_bundles with direnv/gh widenings; seven new tests cover the key scenarios.
crates/seal-policy/src/grant.rs Adds dbus_filter Vec to GrantToolEntry with serde elision; populated via sort_unstable + dedup from bundle's dbus_filter rules.
crates/seal-sandbox/src/kernel_params.rs Adds dbus_filter_rules Vec to KernelParams with serde elision; well-documented design rationale for storing rendered strings.
crates/seal-policy/src/manifest/sandbox.rs Adds dbus_filter: &[] to all existing BundleSpec entries and the every_bundle_dbus_filter_rule_validates catalog test.
crates/seal-sandbox/tests/bwrap_integration.rs Trivial fixture update adding dbus_filter_rules: Vec::new() to KernelParams struct literal.
crates/seal-runtime/src/scope/sandbox_spawn/linux.rs Trivial fixture update adding dbus_filter_rules: Vec::new() to test KernelParams.
crates/seal-runtime/src/scope/sandbox_spawn/macos.rs Trivial fixture update adding dbus_filter_rules: Vec::new() to test KernelParams.
crates/seal-runtime/src/scope/sandbox_spawn/mod.rs Trivial fixture update adding dbus_filter_rules: Vec::new() to test KernelParams.
crates/seal-runtime/tests/bwrap_dispatcher_integration.rs Trivial fixture update adding dbus_filter_rules: Vec::new() to test KernelParams.
crates/seal-sandbox/src/linux.rs Trivial fixture update adding dbus_filter_rules: Vec::new() to test KernelParams.
crates/seal-sandbox/src/macos.rs Trivial fixture update adding dbus_filter_rules: Vec::new() to test KernelParams.
crates/seal-sandbox/tests/sandbox_exec_integration.rs Trivial fixture update adding dbus_filter_rules: Vec::new() to test KernelParams.

Reviews (7): Last reviewed commit: "test(seal-sandbox): address PR #511 roun..." | Re-trigger Greptile

Comment thread crates/seal-policy/src/manifest/dbus_filter.rs
Comment thread crates/seal-sandbox/src/compile.rs
Comment thread crates/seal-policy/src/manifest/dbus_filter.rs Outdated
mattwilkinsonn added a commit that referenced this pull request Jun 11, 2026
…ilter validators with xdg-dbus-proxy grammar, canonicalize grant dbus_filter, HashSet dedup (SEA-780)
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 11, 2026
mattwilkinsonn added a commit that referenced this pull request Jun 11, 2026
…ilter validators with xdg-dbus-proxy grammar, canonicalize grant dbus_filter, HashSet dedup (SEA-780)
@mattwilkinsonn mattwilkinsonn force-pushed the sea-780-dbus-proxy-slice-1--athena branch from 288fa51 to 9c3e96c Compare June 11, 2026 15:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/seal-policy/src/manifest/sandbox.rs (1)

3333-3352: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove duplicated doc comment block.

Lines 3333-3352 contain the same doc comment twice. The second copy (starting at line 3343) duplicates the first. Only one copy is needed.

🧹 Suggested fix
-    /// Every entry in a bundle's `psl_exemptions` list must
-    /// match at least one entry in the same bundle's `domains`
-    /// list. An exemption for a pattern the bundle doesn't
-    /// actually use is dead config — and worse, it could mask
-    /// a typo: a future engineer adding `*.foo.bar.com` to
-    /// `domains` (which is a PSL-rejected pattern if
-    /// `bar.com` is a public suffix) might leave the unrelated
-    /// `*.baz.qux.com` in `psl_exemptions` and assume that
-    /// covers the new entry. The 1:1 check forces exemptions
-    /// to be explicitly tied to the domains they unblock.
     /// Every entry in a bundle's `psl_exemptions` list must
     /// match at least one entry in the same bundle's `domains`
     /// list. An exemption for a pattern the bundle doesn't
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/seal-policy/src/manifest/sandbox.rs` around lines 3333 - 3352, Remove
the duplicated doc comment block describing the psl_exemptions/domains 1:1 check
so only a single copy remains immediately above the item it documents; locate
the repeated paragraph that starts "Every entry in a bundle's `psl_exemptions`
list must match at least one entry in the same bundle's `domains` list" and
delete the second occurrence, preserving the first intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@crates/seal-policy/src/manifest/sandbox.rs`:
- Around line 3333-3352: Remove the duplicated doc comment block describing the
psl_exemptions/domains 1:1 check so only a single copy remains immediately above
the item it documents; locate the repeated paragraph that starts "Every entry in
a bundle's `psl_exemptions` list must match at least one entry in the same
bundle's `domains` list" and delete the second occurrence, preserving the first
intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 10f7052a-e0ad-4d2d-a959-2a88b6637600

📥 Commits

Reviewing files that changed from the base of the PR and between 288fa51 and 9c3e96c.

📒 Files selected for processing (14)
  • crates/seal-policy/src/grant.rs
  • crates/seal-policy/src/manifest.rs
  • crates/seal-policy/src/manifest/dbus_filter.rs
  • crates/seal-policy/src/manifest/sandbox.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/linux.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/macos.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/mod.rs
  • crates/seal-runtime/tests/bwrap_dispatcher_integration.rs
  • crates/seal-sandbox/src/compile.rs
  • crates/seal-sandbox/src/kernel_params.rs
  • crates/seal-sandbox/src/linux.rs
  • crates/seal-sandbox/src/macos.rs
  • crates/seal-sandbox/tests/bwrap_integration.rs
  • crates/seal-sandbox/tests/sandbox_exec_integration.rs

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 11, 2026
mattwilkinsonn added a commit that referenced this pull request Jun 11, 2026
…ption doc block (SEA-780)

Co-Authored-By: seal <noreply@sealedsecurity.com>
@graphite-app

graphite-app Bot commented Jun 11, 2026

Copy link
Copy Markdown

Merge activity

  • Jun 11, 9:19 PM UTC: mattwilkinsonn added this pull request to the Graphite merge queue.
  • Jun 11, 9:24 PM UTC: The Graphite merge queue couldn't merge this PR because it had merge conflicts.
  • Jun 13, 3:08 PM UTC: mattwilkinsonn added this pull request to the Graphite merge queue.
  • Jun 13, 3:13 PM UTC: CI is running for this pull request on a draft pull request (#550) due to your merge queue CI optimization settings.
  • Jun 13, 3:15 PM UTC: Merged by the Graphite merge queue via draft PR: #550.

mattwilkinsonn added a commit that referenced this pull request Jun 12, 2026
…ilter validators with xdg-dbus-proxy grammar, canonicalize grant dbus_filter, HashSet dedup (SEA-780)
mattwilkinsonn added a commit that referenced this pull request Jun 12, 2026
…ption doc block (SEA-780)

Co-Authored-By: seal <noreply@sealedsecurity.com>
@mattwilkinsonn mattwilkinsonn force-pushed the sea-780-dbus-proxy-slice-1--athena branch from b5957be to 7aa0145 Compare June 12, 2026 00:40

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/seal-policy/src/grant.rs`:
- Around line 706-726: Extract the sort+dedup normalization of dbus_filter into
a small helper (e.g., fn normalize_dbus_filter(rules: impl
IntoIterator<Item=&Rule>) -> Vec<String>) and update the existing code that
builds dbus_filter to call that helper (use bundle.dbus_filter.iter().map(|r|
r.to_flag()) as input); add a focused unit test for normalize_dbus_filter that
verifies canonicalization (sorted and deduplicated) for a variety of input
orders/duplicates and exercises Rule::to_flag behavior so the canonicalization
contract is pinned before non-empty bundles are used.

In `@crates/seal-sandbox/src/compile.rs`:
- Around line 526-543: resolve_dbus_filter_rules duplicates the "widened
bundle-activation" logic that's implemented in apply_bundles, causing the D-Bus
rule set to drift when that predicate changes; extract the predicate into a
shared helper (e.g., bundle_applies_widened or bundle_matches_with_wrappers) and
update resolve_dbus_filter_rules and apply_bundles to call it instead of
re-implementing logic. The helper should accept the same inputs used here (a
&GrantToolEntry or entry.name, section_wrappers, matched_pattern) plus the
direnv_wrap_active and gh_credential_helper flags and return the boolean;
replace the inline checks (is_direnv_wrap_target /
is_gh_credential_helper_target and bundle_applies call) with a single call to
the new helper so both code paths stay consistent and add the two specific cases
(direnv_wrap_active and gh_credential_helper) inside that helper.
- Around line 1029-1043: The Linux branch currently hardcodes tail =
"~/.cache/sccache" which can miss sccache's actual cache location when
SCCACHE_DIR or XDG_CACHE_HOME is used; update the resolution before calling
bundle_path_to_bind so that for Platform::Linux you first check
std::env::var("SCCACHE_DIR") and use that if present, otherwise use
XDG_CACHE_HOME (or fall back to ~/.cache) and append "sccache" (matching
sccache's ProjectDirs logic), then pass the resulting path to
bundle_path_to_bind and push_unique into fs_write.paths (same call-site where
tail was used), ensuring the resolved path mirrors sccache cache-dir resolution
instead of the hardcoded "~/.cache/sccache".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: efa49fab-a2ba-4b4c-9ca4-a9c7c4801473

📥 Commits

Reviewing files that changed from the base of the PR and between b5957be and 7aa0145.

📒 Files selected for processing (14)
  • crates/seal-policy/src/grant.rs
  • crates/seal-policy/src/manifest.rs
  • crates/seal-policy/src/manifest/dbus_filter.rs
  • crates/seal-policy/src/manifest/sandbox.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/linux.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/macos.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/mod.rs
  • crates/seal-runtime/tests/bwrap_dispatcher_integration.rs
  • crates/seal-sandbox/src/compile.rs
  • crates/seal-sandbox/src/kernel_params.rs
  • crates/seal-sandbox/src/linux.rs
  • crates/seal-sandbox/src/macos.rs
  • crates/seal-sandbox/tests/bwrap_integration.rs
  • crates/seal-sandbox/tests/sandbox_exec_integration.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/seal-policy/src/grant.rs`:
- Around line 706-726: Extract the sort+dedup normalization of dbus_filter into
a small helper (e.g., fn normalize_dbus_filter(rules: impl
IntoIterator<Item=&Rule>) -> Vec<String>) and update the existing code that
builds dbus_filter to call that helper (use bundle.dbus_filter.iter().map(|r|
r.to_flag()) as input); add a focused unit test for normalize_dbus_filter that
verifies canonicalization (sorted and deduplicated) for a variety of input
orders/duplicates and exercises Rule::to_flag behavior so the canonicalization
contract is pinned before non-empty bundles are used.

In `@crates/seal-sandbox/src/compile.rs`:
- Around line 526-543: resolve_dbus_filter_rules duplicates the "widened
bundle-activation" logic that's implemented in apply_bundles, causing the D-Bus
rule set to drift when that predicate changes; extract the predicate into a
shared helper (e.g., bundle_applies_widened or bundle_matches_with_wrappers) and
update resolve_dbus_filter_rules and apply_bundles to call it instead of
re-implementing logic. The helper should accept the same inputs used here (a
&GrantToolEntry or entry.name, section_wrappers, matched_pattern) plus the
direnv_wrap_active and gh_credential_helper flags and return the boolean;
replace the inline checks (is_direnv_wrap_target /
is_gh_credential_helper_target and bundle_applies call) with a single call to
the new helper so both code paths stay consistent and add the two specific cases
(direnv_wrap_active and gh_credential_helper) inside that helper.
- Around line 1029-1043: The Linux branch currently hardcodes tail =
"~/.cache/sccache" which can miss sccache's actual cache location when
SCCACHE_DIR or XDG_CACHE_HOME is used; update the resolution before calling
bundle_path_to_bind so that for Platform::Linux you first check
std::env::var("SCCACHE_DIR") and use that if present, otherwise use
XDG_CACHE_HOME (or fall back to ~/.cache) and append "sccache" (matching
sccache's ProjectDirs logic), then pass the resulting path to
bundle_path_to_bind and push_unique into fs_write.paths (same call-site where
tail was used), ensuring the resolved path mirrors sccache cache-dir resolution
instead of the hardcoded "~/.cache/sccache".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: efa49fab-a2ba-4b4c-9ca4-a9c7c4801473

📥 Commits

Reviewing files that changed from the base of the PR and between b5957be and 7aa0145.

📒 Files selected for processing (14)
  • crates/seal-policy/src/grant.rs
  • crates/seal-policy/src/manifest.rs
  • crates/seal-policy/src/manifest/dbus_filter.rs
  • crates/seal-policy/src/manifest/sandbox.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/linux.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/macos.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/mod.rs
  • crates/seal-runtime/tests/bwrap_dispatcher_integration.rs
  • crates/seal-sandbox/src/compile.rs
  • crates/seal-sandbox/src/kernel_params.rs
  • crates/seal-sandbox/src/linux.rs
  • crates/seal-sandbox/src/macos.rs
  • crates/seal-sandbox/tests/bwrap_integration.rs
  • crates/seal-sandbox/tests/sandbox_exec_integration.rs
🛑 Comments failed to post (3)
crates/seal-policy/src/grant.rs (1)

706-726: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Extract and pin dbus_filter normalization with a focused unit test.

This path now feeds the signed grant payload, but in this slice it is only exercised through the all-empty catalog. Pulling the sort+dedup into a tiny helper and adding a direct test would lock in the canonicalization contract before slice 3 starts shipping non-empty rules.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/seal-policy/src/grant.rs` around lines 706 - 726, Extract the
sort+dedup normalization of dbus_filter into a small helper (e.g., fn
normalize_dbus_filter(rules: impl IntoIterator<Item=&Rule>) -> Vec<String>) and
update the existing code that builds dbus_filter to call that helper (use
bundle.dbus_filter.iter().map(|r| r.to_flag()) as input); add a focused unit
test for normalize_dbus_filter that verifies canonicalization (sorted and
deduplicated) for a variety of input orders/duplicates and exercises
Rule::to_flag behavior so the canonicalization contract is pinned before
non-empty bundles are used.
crates/seal-sandbox/src/compile.rs (2)

526-543: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Extract the widened bundle-activation predicate.

resolve_dbus_filter_rules() now re-implements the same direnv-wrap / gh-helper widening that apply_bundles() owns, but the new tests only pin direct-prefix applicability. Pulling this into one shared helper and adding one direnv_wrap_active case plus one gh_credential_helper case would keep the D-Bus surface from drifting away from bind/env/network behavior on the next widening tweak.

Suggested shape
+fn bundle_applies_with_widenings(
+    entry: &GrantToolEntry,
+    matched_pattern: &str,
+    section_wrappers: &[String],
+    direnv_wrap_active: bool,
+    gh_credential_helper: bool,
+) -> bool {
+    let is_direnv_wrap_target = direnv_wrap_active && entry.name == "direnv";
+    let is_gh_credential_helper_target = gh_credential_helper && entry.name == "gh";
+    is_direnv_wrap_target
+        || is_gh_credential_helper_target
+        || bundle_applies(entry, section_wrappers, matched_pattern)
+}
+
 fn resolve_dbus_filter_rules(
     entries: &[GrantToolEntry],
     matched_pattern: &str,
     section_wrappers: &[String],
     direnv_wrap_active: bool,
     gh_credential_helper: bool,
 ) -> Vec<String> {
@@
     let mut rules: Vec<String> = Vec::new();
     for entry in entries {
-        let is_direnv_wrap_target = direnv_wrap_active && entry.name == "direnv";
-        let is_gh_credential_helper_target = gh_credential_helper && entry.name == "gh";
-        if !is_direnv_wrap_target
-            && !is_gh_credential_helper_target
-            && !bundle_applies(entry, section_wrappers, matched_pattern)
-        {
+        if !bundle_applies_with_widenings(
+            entry,
+            matched_pattern,
+            section_wrappers,
+            direnv_wrap_active,
+            gh_credential_helper,
+        ) {
             continue;
         }

Also applies to: 6470-6668

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/seal-sandbox/src/compile.rs` around lines 526 - 543,
resolve_dbus_filter_rules duplicates the "widened bundle-activation" logic
that's implemented in apply_bundles, causing the D-Bus rule set to drift when
that predicate changes; extract the predicate into a shared helper (e.g.,
bundle_applies_widened or bundle_matches_with_wrappers) and update
resolve_dbus_filter_rules and apply_bundles to call it instead of
re-implementing logic. The helper should accept the same inputs used here (a
&GrantToolEntry or entry.name, section_wrappers, matched_pattern) plus the
direnv_wrap_active and gh_credential_helper flags and return the boolean;
replace the inline checks (is_direnv_wrap_target /
is_gh_credential_helper_target and bundle_applies call) with a single call to
the new helper so both code paths stay consistent and add the two specific cases
(direnv_wrap_active and gh_credential_helper) inside that helper.

1029-1043: ⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

For current sccache releases, what cache directory does sccache use on Linux by default, and does it honor XDG_CACHE_HOME?

💡 Result:

On Linux, sccache uses ~/.cache/sccache as its default directory for local disk storage [1][2][3]. Regarding XDG_CACHE_HOME, sccache's default implementation for determining the cache directory utilizes the directories crate (ProjectDirs) [4]. While sccache explicitly defaults to ~/.cache/sccache on Linux [1][2], it generally relies on the standard behaviors provided by the underlying Rust libraries to resolve platform-specific cache directories [4]. You can override this location entirely by setting the SCCACHE_DIR environment variable to a path of your choosing [1][2][5].

Citations:


Fix Linux sccache bind to follow sccache’s actual cache-dir resolution (XDG_CACHE_HOME / SCCACHE_DIR)

In crates/seal-sandbox/src/compile.rs:1029-1043, the Linux branch hardcodes ~/.cache/sccache. However, sccache determines its Linux disk cache directory via standard platform cache-dir logic (ProjectDirs) and may vary with XDG_CACHE_HOME; it can also be overridden entirely via SCCACHE_DIR. If the sandbox sets either, binding ~/.cache/sccache may miss the real sccache cache dir and make the write bind ineffective.
Also applies to: 4091-4158

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/seal-sandbox/src/compile.rs` around lines 1029 - 1043, The Linux
branch currently hardcodes tail = "~/.cache/sccache" which can miss sccache's
actual cache location when SCCACHE_DIR or XDG_CACHE_HOME is used; update the
resolution before calling bundle_path_to_bind so that for Platform::Linux you
first check std::env::var("SCCACHE_DIR") and use that if present, otherwise use
XDG_CACHE_HOME (or fall back to ~/.cache) and append "sccache" (matching
sccache's ProjectDirs logic), then pass the resulting path to
bundle_path_to_bind and push_unique into fs_write.paths (same call-site where
tail was used), ensuring the resolved path mirrors sccache cache-dir resolution
instead of the hardcoded "~/.cache/sccache".

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/seal-runtime/src/scope/sandbox_spawn/macos.rs`:
- Around line 58-71: The current loop emitting "(allow file-read* (literal
...))" for each runtime.extra_ro_binds source only whitelists the leaf inode;
modify the loop over runtime.extra_ro_binds to first synthesize and emit "(allow
file-read-metadata (literal ...))" entries for each strict ancestor of the
source path (from the immediate parent up to the filesystem root or sandbox
baseline) using seal_sandbox::sbpl_string_literal(&ancestor.to_string_lossy()),
then emit the existing "(allow file-read* ...)" for the leaf; ensure ancestor
rules are pushed into profile before the leaf rule (you can mirror the
ancestor-synthesis logic from the compile layer if available) so sandbox-exec
can traverse to the whitelisted file.

In `@crates/seal-runtime/src/scope/sandbox_spawn/mod.rs`:
- Around line 454-459: The cleanup currently sets removed_socket = true whenever
self.sock_path was Some, even if std::fs::remove_file failed; change the logic
so you call std::fs::remove_file(p) and set removed_socket based on its Result
(true on Ok, false on Err), and log the actual error (including the error
message) when remove_file returns Err; reference the self.sock_path.take()
usage, the removed_socket binding, and the std::fs::remove_file call so you
locate and replace the current unconditional-true behavior with a Result match
that logs failures and only marks removal as true on success.

In `@crates/seal-sandbox/src/compile.rs`:
- Around line 526-554: The dbus filter selection in resolve_dbus_filter_rules
duplicates the direnv/gh/pattern checks already used elsewhere (notably in
apply_bundles); extract that predicate into a shared helper function (e.g.,
bundle_applies_with_wrappers or is_bundle_applicable) that accepts a
&GrantToolEntry, &str matched_pattern, &[String] section_wrappers,
direnv_wrap_active: bool, gh_credential_helper: bool and returns bool, then
replace the inline condition in resolve_dbus_filter_rules with a call to this
new helper and update apply_bundles() to call the same helper so all
bundle-applicability logic is centralized and stays synchronized.

In `@crates/seal-sandbox/src/macos.rs`:
- Around line 423-438: When expanding FIRMLINKS into sources, handle the case
where strip_prefix yields an empty remainder so the firmlink twin itself is
emitted: inside the loop over FIRMLINKS where you do if let Ok(rest) =
p.strip_prefix(short) { ... }, detect if rest is empty and push
Path::new(long).to_path_buf() (or Path::new(long).join(rest) only when rest is
non-empty) so the `/private/...` twin itself is included in sources; this
ensures the later ancestor-walk in ancestors includes metadata for exact roots
like `/tmp`, `/etc`, `/var`. Also add a unit test exercising an exact `/tmp`
grant (FsBaseline::None) to assert the `/private/tmp` metadata path is present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8628a4ac-5c7b-479f-b2ab-7096197603ba

📥 Commits

Reviewing files that changed from the base of the PR and between b5957be and 7aa0145.

📒 Files selected for processing (14)
  • crates/seal-policy/src/grant.rs
  • crates/seal-policy/src/manifest.rs
  • crates/seal-policy/src/manifest/dbus_filter.rs
  • crates/seal-policy/src/manifest/sandbox.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/linux.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/macos.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/mod.rs
  • crates/seal-runtime/tests/bwrap_dispatcher_integration.rs
  • crates/seal-sandbox/src/compile.rs
  • crates/seal-sandbox/src/kernel_params.rs
  • crates/seal-sandbox/src/linux.rs
  • crates/seal-sandbox/src/macos.rs
  • crates/seal-sandbox/tests/bwrap_integration.rs
  • crates/seal-sandbox/tests/sandbox_exec_integration.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/seal-runtime/src/scope/sandbox_spawn/macos.rs`:
- Around line 58-71: The current loop emitting "(allow file-read* (literal
...))" for each runtime.extra_ro_binds source only whitelists the leaf inode;
modify the loop over runtime.extra_ro_binds to first synthesize and emit "(allow
file-read-metadata (literal ...))" entries for each strict ancestor of the
source path (from the immediate parent up to the filesystem root or sandbox
baseline) using seal_sandbox::sbpl_string_literal(&ancestor.to_string_lossy()),
then emit the existing "(allow file-read* ...)" for the leaf; ensure ancestor
rules are pushed into profile before the leaf rule (you can mirror the
ancestor-synthesis logic from the compile layer if available) so sandbox-exec
can traverse to the whitelisted file.

In `@crates/seal-runtime/src/scope/sandbox_spawn/mod.rs`:
- Around line 454-459: The cleanup currently sets removed_socket = true whenever
self.sock_path was Some, even if std::fs::remove_file failed; change the logic
so you call std::fs::remove_file(p) and set removed_socket based on its Result
(true on Ok, false on Err), and log the actual error (including the error
message) when remove_file returns Err; reference the self.sock_path.take()
usage, the removed_socket binding, and the std::fs::remove_file call so you
locate and replace the current unconditional-true behavior with a Result match
that logs failures and only marks removal as true on success.

In `@crates/seal-sandbox/src/compile.rs`:
- Around line 526-554: The dbus filter selection in resolve_dbus_filter_rules
duplicates the direnv/gh/pattern checks already used elsewhere (notably in
apply_bundles); extract that predicate into a shared helper function (e.g.,
bundle_applies_with_wrappers or is_bundle_applicable) that accepts a
&GrantToolEntry, &str matched_pattern, &[String] section_wrappers,
direnv_wrap_active: bool, gh_credential_helper: bool and returns bool, then
replace the inline condition in resolve_dbus_filter_rules with a call to this
new helper and update apply_bundles() to call the same helper so all
bundle-applicability logic is centralized and stays synchronized.

In `@crates/seal-sandbox/src/macos.rs`:
- Around line 423-438: When expanding FIRMLINKS into sources, handle the case
where strip_prefix yields an empty remainder so the firmlink twin itself is
emitted: inside the loop over FIRMLINKS where you do if let Ok(rest) =
p.strip_prefix(short) { ... }, detect if rest is empty and push
Path::new(long).to_path_buf() (or Path::new(long).join(rest) only when rest is
non-empty) so the `/private/...` twin itself is included in sources; this
ensures the later ancestor-walk in ancestors includes metadata for exact roots
like `/tmp`, `/etc`, `/var`. Also add a unit test exercising an exact `/tmp`
grant (FsBaseline::None) to assert the `/private/tmp` metadata path is present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8628a4ac-5c7b-479f-b2ab-7096197603ba

📥 Commits

Reviewing files that changed from the base of the PR and between b5957be and 7aa0145.

📒 Files selected for processing (14)
  • crates/seal-policy/src/grant.rs
  • crates/seal-policy/src/manifest.rs
  • crates/seal-policy/src/manifest/dbus_filter.rs
  • crates/seal-policy/src/manifest/sandbox.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/linux.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/macos.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/mod.rs
  • crates/seal-runtime/tests/bwrap_dispatcher_integration.rs
  • crates/seal-sandbox/src/compile.rs
  • crates/seal-sandbox/src/kernel_params.rs
  • crates/seal-sandbox/src/linux.rs
  • crates/seal-sandbox/src/macos.rs
  • crates/seal-sandbox/tests/bwrap_integration.rs
  • crates/seal-sandbox/tests/sandbox_exec_integration.rs
🛑 Comments failed to post (4)
crates/seal-runtime/src/scope/sandbox_spawn/macos.rs (1)

58-71: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Grant ancestor metadata for dispatcher artifact paths, not just the leaf file.

The new (allow file-read* (literal ...)) rule only opens the final artifact inode. For artifacts outside the baseline tree (the current CA cert case under the per-session security dir), sandbox-exec still needs file-read-metadata on each strict ancestor to traverse to that leaf. Without those ancestor rules, TLS clients can still fail to open the injected cert even though the exact file is whitelisted.

Please emit file-read-metadata (literal ...) for the strict ancestors of each runtime.extra_ro_binds source path before the leaf file-read* rule, or reuse the same ancestor-synthesis logic the compile layer already uses for granted paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/seal-runtime/src/scope/sandbox_spawn/macos.rs` around lines 58 - 71,
The current loop emitting "(allow file-read* (literal ...))" for each
runtime.extra_ro_binds source only whitelists the leaf inode; modify the loop
over runtime.extra_ro_binds to first synthesize and emit "(allow
file-read-metadata (literal ...))" entries for each strict ancestor of the
source path (from the immediate parent up to the filesystem root or sandbox
baseline) using seal_sandbox::sbpl_string_literal(&ancestor.to_string_lossy()),
then emit the existing "(allow file-read* ...)" for the leaf; ensure ancestor
rules are pushed into profile before the leaf rule (you can mirror the
ancestor-synthesis logic from the compile layer if available) so sandbox-exec
can traverse to the whitelisted file.
crates/seal-runtime/src/scope/sandbox_spawn/mod.rs (1)

454-459: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Log the actual unlink result.

removed_socket is set to true whenever sock_path is present, even if remove_file fails or the file is already gone. That makes the cleanup log claim success when the socket artifact may still be on disk.

Suggested fix
-        let removed_socket = if let Some(p) = self.sock_path.take() {
-            let _ = std::fs::remove_file(p);
-            true
+        let removed_socket = if let Some(p) = self.sock_path.take() {
+            std::fs::remove_file(&p).is_ok()
         } else {
             false
         };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        let removed_socket = if let Some(p) = self.sock_path.take() {
            std::fs::remove_file(&p).is_ok()
        } else {
            false
        };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/seal-runtime/src/scope/sandbox_spawn/mod.rs` around lines 454 - 459,
The cleanup currently sets removed_socket = true whenever self.sock_path was
Some, even if std::fs::remove_file failed; change the logic so you call
std::fs::remove_file(p) and set removed_socket based on its Result (true on Ok,
false on Err), and log the actual error (including the error message) when
remove_file returns Err; reference the self.sock_path.take() usage, the
removed_socket binding, and the std::fs::remove_file call so you locate and
replace the current unconditional-true behavior with a Result match that logs
failures and only marks removal as true on success.
crates/seal-sandbox/src/compile.rs (1)

526-554: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Extract the shared bundle-applicability predicate.

Lines 536-540 duplicate the same direnv/gh/pattern logic already used on Lines 1001-1005. That makes dbus_filter_rules easy to desynchronize from the fs/env/network bundle surfaces the next time the widening rules change.

♻️ Extraction sketch
+fn bundle_entry_applies(
+    entry: &GrantToolEntry,
+    matched_pattern: &str,
+    section_wrappers: &[String],
+    direnv_wrap_active: bool,
+    gh_credential_helper: bool,
+) -> bool {
+    let is_direnv_wrap_target = direnv_wrap_active && entry.name == "direnv";
+    let is_gh_credential_helper_target = gh_credential_helper && entry.name == "gh";
+    is_direnv_wrap_target
+        || is_gh_credential_helper_target
+        || bundle_applies(entry, section_wrappers, matched_pattern)
+}
+
 fn resolve_dbus_filter_rules(
     entries: &[GrantToolEntry],
     matched_pattern: &str,
     section_wrappers: &[String],
     direnv_wrap_active: bool,
     gh_credential_helper: bool,
 ) -> Vec<String> {
     let mut seen: std::collections::HashSet<&str> = std::collections::HashSet::new();
     let mut rules: Vec<String> = Vec::new();
     for entry in entries {
-        let is_direnv_wrap_target = direnv_wrap_active && entry.name == "direnv";
-        let is_gh_credential_helper_target = gh_credential_helper && entry.name == "gh";
-        if !is_direnv_wrap_target
-            && !is_gh_credential_helper_target
-            && !bundle_applies(entry, section_wrappers, matched_pattern)
-        {
+        if !bundle_entry_applies(
+            entry,
+            matched_pattern,
+            section_wrappers,
+            direnv_wrap_active,
+            gh_credential_helper,
+        ) {
             continue;
         }
         for rule in &entry.dbus_filter {
             if seen.insert(rule.as_str()) {
                 rules.push(rule.clone());

Apply the same helper in apply_bundles() so all bundle surfaces stay locked together.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/seal-sandbox/src/compile.rs` around lines 526 - 554, The dbus filter
selection in resolve_dbus_filter_rules duplicates the direnv/gh/pattern checks
already used elsewhere (notably in apply_bundles); extract that predicate into a
shared helper function (e.g., bundle_applies_with_wrappers or
is_bundle_applicable) that accepts a &GrantToolEntry, &str matched_pattern,
&[String] section_wrappers, direnv_wrap_active: bool, gh_credential_helper: bool
and returns bool, then replace the inline condition in resolve_dbus_filter_rules
with a call to this new helper and update apply_bundles() to call the same
helper so all bundle-applicability logic is centralized and stays synchronized.
crates/seal-sandbox/src/macos.rs (1)

423-438: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Exact /tmp//etc//var grants still miss the /private/... metadata hop.

The firmlink expansion only adds the /private/... twin as a source, and the later walk emits ancestors of that twin, not the twin itself. That means a grant rooted exactly at /tmp, /etc, or /var still won't get a metadata rule for /private/tmp, /private/etc, or /private/var, so canonicalization of the exact firmlink root can still fail under FsBaseline::None.

Please special-case the empty rest case so the /private/... twin itself is emitted as a metadata path, and add a test for an exact /tmp grant.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/seal-sandbox/src/macos.rs` around lines 423 - 438, When expanding
FIRMLINKS into sources, handle the case where strip_prefix yields an empty
remainder so the firmlink twin itself is emitted: inside the loop over FIRMLINKS
where you do if let Ok(rest) = p.strip_prefix(short) { ... }, detect if rest is
empty and push Path::new(long).to_path_buf() (or Path::new(long).join(rest) only
when rest is non-empty) so the `/private/...` twin itself is included in
sources; this ensures the later ancestor-walk in ancestors includes metadata for
exact roots like `/tmp`, `/etc`, `/var`. Also add a unit test exercising an
exact `/tmp` grant (FsBaseline::None) to assert the `/private/tmp` metadata path
is present.

mattwilkinsonn and others added 3 commits June 12, 2026 22:32
…KernelParams::dbus_filter_rules — slice 1 of SEA-780 D-Bus / Secret Service proxy support
…ilter validators with xdg-dbus-proxy grammar, canonicalize grant dbus_filter, HashSet dedup (SEA-780)
…ption doc block (SEA-780)

Co-Authored-By: seal <noreply@sealedsecurity.com>
@mattwilkinsonn mattwilkinsonn force-pushed the sea-780-dbus-proxy-slice-1--athena branch from 7aa0145 to 0ec85d9 Compare June 13, 2026 03:13

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/seal-sandbox/src/compile.rs`:
- Around line 6530-6729: Add two unit tests that assert dbus_filter_rules follow
the resolver's indirect widenings: create synthetic bundle entries carrying
non-empty dbus_filter and use the same helper builders (e.g.,
cargo_entry_with_install / bun_entry_with_install and
sandbox_grant_with_resolved_tools_for_test) but craft the matched_pattern and/or
bundle setup so the resolver's gh_credential_helper and direnv_wrap_active
widenings are exercised; for each widening, compile(...) with the appropriate
matched_pattern that only becomes applicable via that widening and assert the
dbus_filter_rules either aggregate (when the widening makes the bundle apply) or
remain empty (when it doesn't), mirroring the existing tests
dbus_filter_rules_aggregated_when_bundle_applies and
dbus_filter_rules_skipped_when_bundle_does_not_apply. Ensure tests reference
gh_credential_helper and direnv_wrap_active in their names/comments so future
readers know which widening each test covers.
- Around line 535-541: The applicability predicate used in the entries loop (the
is_direnv_wrap_target / is_gh_credential_helper_target checks combined with
bundle_applies(entry, section_wrappers, matched_pattern)) should be extracted
into a single helper function (e.g., fn bundle_applicable(entry: &Entry,
section_wrappers: &..., matched_pattern: &..., direnv_wrap_active: bool,
gh_credential_helper: bool) -> bool) and both callsites (the current loop using
is_direnv_wrap_target/is_gh_credential_helper_target and the other duplicate at
the later block) should be updated to use this helper to avoid drift; update the
loop to call the new helper and remove the duplicated inline logic, preserving
existing parameters (entry, section_wrappers, matched_pattern,
direnv_wrap_active, gh_credential_helper).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 33c36ec3-69c2-4e13-80a9-295db6530aa1

📥 Commits

Reviewing files that changed from the base of the PR and between 7aa0145 and 0ec85d9.

📒 Files selected for processing (14)
  • crates/seal-policy/src/grant.rs
  • crates/seal-policy/src/manifest.rs
  • crates/seal-policy/src/manifest/dbus_filter.rs
  • crates/seal-policy/src/manifest/sandbox.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/linux.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/macos.rs
  • crates/seal-runtime/src/scope/sandbox_spawn/mod.rs
  • crates/seal-runtime/tests/bwrap_dispatcher_integration.rs
  • crates/seal-sandbox/src/compile.rs
  • crates/seal-sandbox/src/kernel_params.rs
  • crates/seal-sandbox/src/linux.rs
  • crates/seal-sandbox/src/macos.rs
  • crates/seal-sandbox/tests/bwrap_integration.rs
  • crates/seal-sandbox/tests/sandbox_exec_integration.rs

Comment thread crates/seal-sandbox/src/compile.rs
Comment thread crates/seal-sandbox/src/compile.rs
…ggregation through gh-credential-helper and direnv-wrap widenings (SEA-780)

Co-Authored-By: seal <noreply@sealedsecurity.com>
@graphite-app graphite-app Bot closed this Jun 13, 2026
@graphite-app graphite-app Bot deleted the sea-780-dbus-proxy-slice-1--athena branch June 13, 2026 15:15
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant