diff --git a/src/core/mxc-sdk/README.md b/src/core/mxc-sdk/README.md index 8fe12df8..4ffe2b3c 100644 --- a/src/core/mxc-sdk/README.md +++ b/src/core/mxc-sdk/README.md @@ -49,7 +49,9 @@ available to feed a policy: [`available_tools_policy`] (PATH + tool/SDK env dirs), [`user_profile_policy`], and [`temporary_files_policy`]. [`platform_support`] is the Rust port of `getPlatformSupport` — reports host -support and the available containment backends. +support and the available containment backends. On Windows, +`PlatformSupport::isolation_tier` reports the process-container tier selected +for the default policy. ## Live stdio + kill (streaming) diff --git a/src/core/mxc-sdk/src/lib.rs b/src/core/mxc-sdk/src/lib.rs index 6a1bc158..7055a1eb 100644 --- a/src/core/mxc-sdk/src/lib.rs +++ b/src/core/mxc-sdk/src/lib.rs @@ -70,8 +70,8 @@ mod sandbox; pub use mxc_engine::policy; pub use mxc_engine::{ available_tools_policy, build_request, platform_support, temporary_files_policy, - user_profile_policy, Error, ErrorCode, FilesystemPolicyResult, PlatformSupport, SandboxPolicy, - SandboxRequest, + user_profile_policy, Error, ErrorCode, FilesystemPolicyResult, IsolationTier, PlatformSupport, + SandboxPolicy, SandboxRequest, }; pub use sandbox::{Output, Sandbox, StreamCloser, WaitOutcome}; diff --git a/src/core/mxc-sdk/tests/sdk_helpers.rs b/src/core/mxc-sdk/tests/sdk_helpers.rs index 69e11539..3aaebd0b 100644 --- a/src/core/mxc-sdk/tests/sdk_helpers.rs +++ b/src/core/mxc-sdk/tests/sdk_helpers.rs @@ -12,6 +12,9 @@ use mxc_sdk::{ #[cfg(target_os = "macos")] use mxc_sdk::{spawn_sandbox, WaitOutcome}; +#[cfg(target_os = "windows")] +use mxc_sdk::IsolationTier; + fn env_pairs(pairs: &[(&str, &str)]) -> Vec<(String, String)> { pairs .iter() @@ -25,6 +28,8 @@ fn platform_support_reports_host() { // Every platform this test runs on (macOS/Linux/Windows in CI) is supported. assert!(support.is_supported, "reason: {:?}", support.reason); assert!(!support.available_methods.is_empty()); + #[cfg(not(target_os = "windows"))] + assert_eq!(support.isolation_tier, None); } #[cfg(target_os = "macos")] @@ -215,6 +220,9 @@ fn platform_support_windows_is_processcontainer() { support.available_methods, vec!["processcontainer".to_string()] ); + let _: IsolationTier = support + .isolation_tier + .expect("Windows probe should select an isolation tier"); } #[test] diff --git a/src/core/mxc_engine/src/lib.rs b/src/core/mxc_engine/src/lib.rs index 9e5f368c..7802f156 100644 --- a/src/core/mxc_engine/src/lib.rs +++ b/src/core/mxc_engine/src/lib.rs @@ -22,7 +22,8 @@ //! - [`run`] / [`resolve_runner`] (Windows) — run-to-completion backend //! selection and execution. //! - [`run_state_aware`] — state-aware lifecycle backend resolution + dispatch. -//! - [`platform_support`] / [`PlatformSupport`] — host support detection. +//! - [`platform_support`] / [`PlatformSupport`] / [`IsolationTier`] — host +//! support detection. //! - [`Error`] / [`ErrorCode`] — the crate-owned error facade over //! `wxc_common`'s internal error type. @@ -35,7 +36,7 @@ mod run; mod state_aware; pub use error::{Error, ErrorCode}; -pub use platform::{platform_support, PlatformSupport}; +pub use platform::{platform_support, IsolationTier, PlatformSupport}; pub use policy::{ available_tools_policy, build_request, temporary_files_policy, user_profile_policy, FilesystemPolicyResult, SandboxPolicy, SandboxRequest, diff --git a/src/core/mxc_engine/src/platform.rs b/src/core/mxc_engine/src/platform.rs index 8cbe38b2..f15c5e28 100644 --- a/src/core/mxc_engine/src/platform.rs +++ b/src/core/mxc_engine/src/platform.rs @@ -12,6 +12,11 @@ //! `dispatch.rs`, so both the public SDK and the executor binaries can share a //! single implementation. +#[cfg(target_os = "windows")] +use appcontainer_common::fallback_detector::{self, IsolationTier as BackendIsolationTier}; +#[cfg(target_os = "windows")] +use wxc_common::models::ContainerPolicy; + /// Platform support information — the Rust analogue of the SDK /// `PlatformSupport` type. #[derive(Debug, Clone, Default)] @@ -23,14 +28,28 @@ pub struct PlatformSupport { /// Containment backends available on this host, by wire name /// (e.g. `"seatbelt"`, `"bubblewrap"`, `"processcontainer"`). pub available_methods: Vec, + /// Isolation tier selected for the default Windows process-container policy. + /// + /// `None` on non-Windows hosts or when the Windows capability probe fails. + pub isolation_tier: Option, +} + +/// Windows process-container isolation tier selected by the runtime probe. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum IsolationTier { + /// BaseContainer via `Experimental_CreateProcessInSandbox`. + BaseContainer, + /// AppContainer with BFS filesystem isolation. + AppContainerBfs, + /// AppContainer with host DACL augmentation. + AppContainerDacl, } /// Detect MXC support on the current host. /// -/// Mirrors the SDK's `getPlatformSupport`, restricted to the backends the -/// `mxc-sdk` library can actually run. On Windows the isolation tier and UI -/// capabilities come from the in-process fallback probe rather than a -/// `wxc-exec --probe` subprocess. +/// Mirrors the SDK's `getPlatformSupport`. Available methods are restricted to +/// the backends this crate can run. On Windows the isolation tier comes from the +/// in-process fallback probe rather than a `wxc-exec --probe` subprocess. pub fn platform_support() -> PlatformSupport { #[cfg(target_os = "macos")] { @@ -68,9 +87,18 @@ pub fn platform_support() -> PlatformSupport { #[cfg(target_os = "windows")] { + let isolation_tier = fallback_detector::detect(&ContainerPolicy::default(), true) + .ok() + .map(|decision| match decision.tier { + BackendIsolationTier::BaseContainer => IsolationTier::BaseContainer, + BackendIsolationTier::AppContainerBfs => IsolationTier::AppContainerBfs, + BackendIsolationTier::AppContainerDacl => IsolationTier::AppContainerDacl, + }); + PlatformSupport { is_supported: true, available_methods: vec!["processcontainer".to_string()], + isolation_tier, ..Default::default() } } @@ -98,3 +126,19 @@ fn command_succeeds(program: &str, args: &[&str]) -> bool { .map(|s| s.success()) .unwrap_or(false) } + +#[cfg(all(test, target_os = "windows"))] +mod tests { + use super::*; + + #[test] + fn base_container_tier_matches_probe() { + let isolation_tier = platform_support() + .isolation_tier + .expect("Windows probe should select an isolation tier"); + assert_eq!( + isolation_tier == IsolationTier::BaseContainer, + appcontainer_common::fallback_detector::is_base_container_usable() + ); + } +}