⚠️ Independent project
Cageforge is not affiliated with, sponsored by, or endorsed by OpenAI. This crate adapts sandbox design ideas from open-source OpenAI Codex into an independent library API and contains no copied Codex source.
This crate is a supporting component of the cageforge crate, a cross-platform Rust sandbox for AI agents and untrusted code.
cageforge-policy-compose
cageforge-policy-compose narrows a requested Cageforge sandbox policy with a
portable PolicyCeiling. It is the reusable policy-limiting layer for projects
that need to apply an outer safety boundary before execution.
The result keeps the requested and ceiling policies as separate internal constraints. Public effective APIs expose combined decisions, aggregate backend requirements, and immutable lowering views containing every required constraint layer, so a consumer cannot select the requested side and accidentally bypass the ceiling. Filesystem and network decisions are allowed only when both sides allow them; external enforcement is accepted only when both sides delegate that boundary to an external owner. Environment rules are applied in sequence and cannot add a variable that was absent from the requested result. Workspace roots must remain inside the configured ceiling roots.
The composition crate works with the public types from cageforge-policy and
cageforge-command, so an integrating project declares those crates directly
alongside cageforge-policy-compose.
When to use it
Use this crate when the requested permissions must be narrowed by another independent limit: for example, an application-wide default, a workspace boundary, a tenant restriction, or a caller-provided safety policy.
Do not use it merely to construct a policy. If there is no outer limit,
cageforge-policy is enough. Do not treat it as a backend abstraction: it
does not know how Linux, macOS, or Windows will enforce the result.
Workspace role
cageforge-policy-compose is the optional policy-narrowing layer.
| Crate | Role in the relationship |
|---|---|
cageforge-policy |
Supplies filesystem and network constraints to compose. |
cageforge-command |
Supplies the environment specification used during composition. |
cageforge-config |
Optionally provides requested values from TOML; it is not a dependency of this crate. |
cageforge |
Re-exports composition types for the application-facing sandbox flow. |
| Backend integrations | Inspect effective constraints and lower them to native execution APIs. |
The dependency direction keeps composition independent of configuration formats and backends. An application can use TOML, JSON, Rust builders, or its own configuration system and pass the same validated values here.
Example
use EnvironmentSpec;
use ;
use ;
let requested = workspace;
let ceiling = new;
let effective = compose?;
let workspace = temp_dir.join;
let context = effective.path_context?;
assert_eq!;
# Ok::
After composition, a backend API can inspect the effective constraints, check native capabilities, and lower them for Linux, macOS, or Windows execution.
The backend handoff must use EffectiveSandbox, not the original requested
policy. Its filesystem context, network authorization methods, environment
base, and workspace-root limit are the narrowed contract. A backend may reject
an unsupported capability, but it must not silently replace the effective
constraints with a broader request.
External is accepted only when both policy sides use the same opaque
ExternalOwner identity. This token comes from the caller; it does not prove
that an external sandbox exists or enforces anything. It only prevents two
unrelated declarations from being treated as one boundary:
use ExternalOwner;
let owner = new;
assert_eq!;
assert_ne!;
Create owners explicitly with ExternalOwner::new(). The type has no
Default implementation because every new owner represents a different
identity. Cloning an owner preserves that identity.
API guide
PolicyCeilingstores the outer portable maximum policy, environment rules, and optional workspace-root limit.CompositionRequestsupplies a requested policy without taking ownership of the caller's values. Runtime-resolved workspace roots can be added withwith_workspace_roots.composereturnsEffectiveSandbox.EffectiveSandbox::path_contextcreates the only context accepted by effective filesystem path evaluation, so a workspace-root ceiling cannot be silently replaced by a broader runtime context.EffectiveFilesystemPolicyandEffectiveNetworkPolicyexpose decisions constrained by both policies plus aggregate requirements for capability negotiation. Theirlowering()views expose every immutable filesystem or network constraint layer needed by a native backend, including rules, protected paths, glob depth, domain defaults, local-address settings, and Unix socket rules. A backend must process every returned layer as a conjunction; the layers are not alternative policies and neither input is exposed as an independent backend choice. Filesystem selector queries require theEffectivePathContextcreated byEffectiveSandbox::path_context; its rawPathResolutionContextis not exposed. The context is bound to that composed result and cannot be reused with another one. Use its safe accessors orresolvemethod when a backend needs the narrowed runtime paths. These accessors retain the runtime roots, minimal paths, temporary paths, and current directory while workspace roots remain constrained by composition. A selector with no effective runtime paths is denied.glob_scan_max_depthreturns the widest depth required by all effective deny-glob rules.EffectiveNetworkPolicy::authorize_connectionapplies both policies to oneResolvedNetworkTargetand the exact socket address supplied by a backend, then returns that address as a typed value. It performs no DNS lookup itself.CoreEnvironmentwraps the validated map selected by a platform backend's core environment allowlist.EnvironmentInput::coreaccepts this type instead of an arbitrary map, making the selection boundary explicit.EffectiveEnvironmentexposes the least-permissive base and applies both environment transformations only to anEnvironmentInputwhose selected base is no broader than the effective base.EnvironmentSpec::apply_toreturns a validated snapshot, so the base tag remains attached until the process adapter deliberately extracts its variables.
The complete API is documented on docs.rs.
Using it in another project
The crate can be used with any configuration source. Construct a
SandboxPolicy and EnvironmentSpec directly in Rust, or obtain them from
cageforge-config, then create a PolicyCeiling and call compose before
passing the result to the project's execution layer.