Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .agents/skills/build-openshell-mxc-windows/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ mise run --skip-tools windows:build:x64
mise run --skip-tools windows:build:arm64
mise run --skip-tools windows:test:x64
mise run --skip-tools windows:test:unsupported:x64
mise run --skip-tools windows:test:mxc-real:x64
mise run --skip-tools windows:test:mxc-real:arm64
```

For full validation, detect the Windows host architecture first and choose the
Expand Down Expand Up @@ -235,6 +237,8 @@ crypto dependency builds.
| `windows:test:arm64` | Runs native ARM64 workspace tests with `--no-fail-fast` and the same package exclusions. Rejects non-ARM64 hosts. |
| `windows:test:unsupported:x64` | Re-runs focused `openshell-gateway` tests for unsupported Windows driver behavior. |
| `windows:test:unsupported:arm64` | Re-runs the same focused contracts natively on ARM64. Rejects non-ARM64 hosts. |
| `windows:test:mxc-real:x64` | Runs the serial, ignored real-`wxc-exec` integration suite natively on x64 through the MSVC wrapper. Rejects non-x64 hosts. |
| `windows:test:mxc-real:arm64` | Runs the same real-`wxc-exec` suite natively on ARM64. Rejects non-ARM64 hosts. |
| `windows:artifacts` | Reports size and SHA256 for release artifacts that exist. |
| `windows:ci` | Runs the full ordered x64-host Windows CI lane, plus ARM64 check/build when not skipped. |

Expand Down Expand Up @@ -292,6 +296,8 @@ Useful log files:
| `test-aarch64-pc-windows-msvc.log` | Full native ARM64 workspace test output. |
| `test-x86_64-pc-windows-msvc-unsupported-*.log` | Focused unsupported-driver contract output. |
| `test-aarch64-pc-windows-msvc-unsupported-*.log` | Focused native ARM64 contract output. |
| `test-x86_64-pc-windows-msvc-mxc-real.log` | Native x64 real-MXC integration output. |
| `test-aarch64-pc-windows-msvc-mxc-real.log` | Native ARM64 real-MXC integration output. |

The first bundled-Z3 check or test can spend several minutes in CMake/MSBuild
without much console output because Cargo output is redirected to the log. Look
Expand Down
13 changes: 11 additions & 2 deletions architecture/compute-runtimes.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ launches and monitors the policy-constrained workload itself.

`compute_driver.proto` is the supported gateway/driver extension boundary.
At initialization the gateway snapshots the driver's identity, version,
default image, gateway-lifecycle preference, and
`driver_reports_runtime_readiness` from `GetCapabilities`. The gateway includes
default image, gateway-lifecycle preference, runtime-readiness ownership, and
complete UI-policy enforcement support from `GetCapabilities`. The gateway includes
the canonical `SandboxPolicy` in `DriverSandboxSpec.policy` for validation and
creation. Drivers that enforce policy outside the standard supervisor fetch
later revisions through `GetSandboxConfig` and acknowledge them through
Expand Down Expand Up @@ -106,6 +106,15 @@ The capability RPC reports driver identity, version, and the default sandbox
image used by the gateway. GPU availability stays driver-local and is validated
when a sandbox create request asks for GPU resources.

UI policy is capability-negotiated at the configured driver-instance boundary.
`supports_ui_policy = true` means the driver completely enforces every field in
the current portable `SandboxPolicy.ui` contract; partial implementations must
report false. When `ui` is explicitly present, including as `{}`, the gateway
rejects create before the driver validation RPC or provisioning unless this
capability is true. An absent section bypasses this gate and preserves the
runtime's existing behavior. The startup snapshot is also exposed through
gateway info so clients can discover the selected runtime's support.

The gateway records driver identity and version from the startup capability
response. Elevated gateway info reports that initialized driver snapshot instead
of re-querying drivers on each request.
Expand Down
24 changes: 23 additions & 1 deletion architecture/security-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,41 @@ per-request egress decisions.
For the field-by-field YAML reference, use
[Policy Schema Reference](../docs/reference/policy-schema.mdx).

## Windows MXC Static Enforcement

On native Windows, the MXC driver cannot rely on Linux Landlock or setuid. It
maps portable static filesystem and UI controls from `SandboxPolicy` into MXC
configuration. UI controls are available only with the MXC
`process_container` backend; all omitted UI fields retain deny-by-default
values, and other compute runtimes reject an explicit UI policy.

## Policy Areas

| Area | Enforcement |
|---|---|
| Filesystem | Landlock restricts read-only and read-write paths. |
| Process | The supervisor launches the agent as an unprivileged user with reduced capabilities. |
| UI | Within an explicit UI section, omitted display, clipboard, and input-injection fields deny. The MXC driver's OpenShell `process_container` backend (MXC containment `processcontainer`) can selectively enable them. Other configured backends reject the entire explicit section before provisioning. |
| Network | The proxy evaluates destination, port, calling binary, and optional L7 rules. |
| Inference | `inference.local` is configured through gateway inference settings, not OPA network policy. |
| Runtime settings | Typed settings are delivered with policy and can be global or sandbox scoped. |

Filesystem and process policy are startup-time controls. Network policy is
Filesystem, process, and UI policy are startup-time controls. Network policy is
dynamic and can be hot-reloaded when the new policy validates successfully.

The UI schema names portable capabilities rather than Windows primitives:
graphical output, directional clipboard access, and synthetic input. The
configured compute driver advertises whether it completely enforces this
contract. Any explicit section, including `{}`, is rejected before driver
validation or provisioning when that capability is false. The MXC
`process_container` mapper translates the fields to MXC's top-level `ui` object
under its `processcontainer` containment value and treats omitted fields inside
the section as deny. That object is common to MXC's 0.8 stable and 0.9
development schemas. Both schema lines reject it for `isolation_session`, so
that backend advertises no support and the mapper also rejects it in depth.
Linux, macOS, and other non-MXC paths advertise no support: explicit UI policy
fails closed, while an absent section leaves their runtime behavior unchanged.

Before applying Landlock, the supervisor enriches baseline filesystem paths that
the runtime needs. Missing baseline paths are skipped so one absent runtime path
does not weaken the whole ruleset. When GPU devices are present, GPU baseline
Expand Down
17 changes: 17 additions & 0 deletions crates/openshell-cli/src/commands/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ struct ComputeDriverInfoView {
struct ComputeDriverCapabilitiesView {
driver_name: String,
driver_version: String,
supports_ui_policy: bool,
}

/// Show gateway status.
Expand Down Expand Up @@ -392,6 +393,7 @@ pub async fn gateway_info(
capabilities: ComputeDriverCapabilitiesView {
driver_name: capabilities.driver_name,
driver_version: capabilities.driver_version,
supports_ui_policy: capabilities.supports_ui_policy,
},
}
})
Expand Down Expand Up @@ -446,6 +448,15 @@ fn print_compute_driver_info(drivers: &[ComputeDriverInfoView]) {
"Driver version:".dimmed(),
driver.capabilities.driver_version
);
println!(
" {} {}",
"UI policy:".dimmed(),
if driver.capabilities.supports_ui_policy {
"supported"
} else {
"unsupported"
}
);
}
}

Expand All @@ -464,6 +475,7 @@ fn gateway_info_to_json(view: &GatewayInfoView) -> serde_json::Value {
"capabilities": {
"driver_name": &driver.capabilities.driver_name,
"driver_version": &driver.capabilities.driver_version,
"supports_ui_policy": driver.capabilities.supports_ui_policy,
},
}))
.collect::<Vec<_>>(),
Expand Down Expand Up @@ -1822,6 +1834,7 @@ mod tests {
capabilities: ComputeDriverCapabilitiesView {
driver_name: "podman".to_string(),
driver_version: "0.0.75".to_string(),
supports_ui_policy: false,
},
}],
};
Expand All @@ -1840,6 +1853,10 @@ mod tests {
json["compute_drivers"][0]["capabilities"]["driver_version"],
"0.0.75"
);
assert_eq!(
json["compute_drivers"][0]["capabilities"]["supports_ui_policy"],
false
);
}

#[test]
Expand Down
32 changes: 32 additions & 0 deletions crates/openshell-core/src/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ impl TryFrom<ProtoSandboxPolicy> for SandboxPolicy {
type Error = miette::Report;

fn try_from(proto: ProtoSandboxPolicy) -> Result<Self, Self::Error> {
// UI capabilities are intentionally absent from the portable supervisor
// runtime. Non-Windows compute paths do not expose them, so even a
// schema-level UI allowance cannot grant a UI surface there. The MXC
// driver consumes the typed proto directly on Windows.
// In cluster mode we always run with proxy networking so all egress
// can be evaluated by OPA and `inference.local` is always addressable.
let network = NetworkPolicy {
Expand Down Expand Up @@ -165,3 +169,31 @@ impl From<ProtoProcessPolicy> for ProcessPolicy {
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::proto::{UiClipboardAccess, UiPolicy};

#[test]
fn portable_runtime_does_not_activate_ui_allowances() {
let converted = SandboxPolicy::try_from(ProtoSandboxPolicy {
version: 1,
ui: Some(UiPolicy {
allow_graphical_ui: true,
clipboard: UiClipboardAccess::All as i32,
allow_input_injection: true,
}),
..Default::default()
})
.expect("portable policy conversion succeeds");

assert_eq!(converted.version, 1);
assert!(matches!(converted.network.mode, NetworkMode::Proxy));
assert!(converted.network.proxy.is_some());
assert!(converted.filesystem.read_only.is_empty());
assert!(converted.filesystem.read_write.is_empty());
assert!(converted.process.run_as_user.is_none());
assert!(converted.process.run_as_group.is_none());
}
}
1 change: 1 addition & 0 deletions crates/openshell-driver-docker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ impl DockerComputeDriver {
count_selection_supported: self.config.gpu.cdi_supported,
}),
}),
supports_ui_policy: false,
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/openshell-driver-kubernetes/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ impl KubernetesComputeDriver {
count_selection_supported: true,
}),
}),
supports_ui_policy: false,
})
}

Expand Down
8 changes: 5 additions & 3 deletions crates/openshell-driver-mxc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ readiness; there is no in-sandbox supervisor or `ConnectSupervisor` relay.
| Capability | MXC driver |
|---|---|
| Filesystem policy | Read-only/read-write grants come only from `SandboxPolicy`. `process_container` enforces default-deny; `isolation_session` is an explicit grant-only compatibility mode. |
| UI policy | `process_container` advertises complete support and maps portable graphical UI, clipboard-direction, and input-injection controls to MXC; omitted fields inside an explicit section deny. `isolation_session` advertises no support, so the gateway rejects any explicit section before provisioning. |
| Network policy | Rejected synchronously during sandbox creation until an enforcing egress path is bound. |
| Process policy | Unsupported; MXC supplies OS isolation only. |
| Interactive exec/connect/forward | Unsupported; the configured workload runs in-driver. |
Expand Down Expand Up @@ -75,11 +76,11 @@ invokes `wxc-exec`. Mapping failure therefore returns from `CreateSandbox`
without leaving a partial sandbox. There is no in-process policy side channel
or MXC-specific gateway composition variant.

`EmbeddedPolicyMapper` calls the embedded [`policy_map`](src/policy_map/) module directly and normalizes filesystem paths to Windows form. It does not add gateway-configured host paths. The policy supplied for the sandbox is the only source of filesystem grants.
`EmbeddedPolicyMapper` calls the embedded [`policy_map`](src/policy_map/) module directly and normalizes filesystem paths to Windows form. It does not add gateway-configured host paths. The policy supplied for the sandbox is the only source of filesystem grants. For `process_container`, the driver advertises `supports_ui_policy = true` and the mapper emits the top-level `ui` object shared by MXC's 0.8 stable and 0.9 development schemas, with restrictive defaults or the exact requested clipboard direction, graphical UI setting, and input-injection setting. `isolation_session` advertises false, so the gateway rejects explicit UI policy before the driver RPC; the mapper also rejects it before lifecycle side effects as defense in depth.

The mapper retains an internal policy-splitting seam for future development, but the runtime exposes no governed-egress switch. Any network rule fails closed until an enforcing proxy is implemented and bound to the sandbox lifecycle.

Parity and matrix tests under [`tests/`](tests/) cover the mapper on the Windows MSVC lane. The driver performs this mapping automatically; there is no separate policy-export command or example.
Parity and matrix tests under [`tests/`](tests/) cover the mapper on the Windows MSVC lane. The real-MXC lane also dry-runs every clipboard direction against the installed schema. The driver performs this mapping automatically; there is no separate policy-export command or example.

## Packaging the demo for the demo box

Expand All @@ -98,7 +99,8 @@ exits 0 rather than failing.

| Task | What it runs | When to use |
|---|---|---|
| `windows:test:mxc-real:x64` | `tests/wxc_exec_real.rs` — Tier-2 invoker tests with `--ignored --test-threads=1` | Pre-merge on any Windows host that has `wxc-exec`; dry-run tests always pass; enforcement tests probe-gate themselves |
| `windows:test:mxc-real:x64` | Native x64 `tests/wxc_exec_real.rs` — Tier-2 invoker tests with `--ignored --test-threads=1` | Pre-merge on an x64 Windows host with `wxc-exec`; dry-run tests always pass; enforcement tests probe-gate themselves |
| `windows:test:mxc-real:arm64` | Native ARM64 `tests/wxc_exec_real.rs` with the same contract | Pre-merge on an ARM64 Windows host with `wxc-exec` |
| `windows:e2e:mxc` | `examples/run-mxc-e2e.ps1` — Tier-3 scenario runner, real binary, probe-gated | Demo box / nightly; needs the gateway + CLI binaries in the script directory |
| `windows:e2e:mxc:mock` | Same runner with `-Mock` — wiring-only, no real `wxc-exec` needed | Any Windows host (CI, dev machine); validates wiring and the network-reject scenario |

Expand Down
Loading
Loading