diff --git a/crates/openshell-core/README.md b/crates/openshell-core/README.md index 1c61a72ef..b4cdb05f5 100644 --- a/crates/openshell-core/README.md +++ b/crates/openshell-core/README.md @@ -58,19 +58,6 @@ configuration validation live in `openshell_core::middleware`. Policy admission and the supervisor runtime consume the same contract without introducing a dependency from the policy crate to the supervisor implementation. -## Extension Capabilities - -Extensions advertise namespaced string capabilities through `PeerMetadata`. -Use shared constants in `extension_protocol` and pass optional capabilities to -`extension_metadata`; do not add per-driver booleans for policy features. -Negotiation validates and retains the extension's supported capability list. - -`POLICY_UI_V1` (`openshell.policy.ui.v1`) declares complete startup UI-policy -support. The gateway checks the effective policy before driver validation or -creation and rejects any explicit UI section when the capability is absent. -Supporting drivers validate and enforce the concrete settings. Omitted UI -preserves existing driver behavior; changing UI requires sandbox recreation. - ## Protobuf Struct Conversion Use `openshell_core::proto_struct` when crossing between `serde_json` values and diff --git a/crates/openshell-core/src/extension_protocol.rs b/crates/openshell-core/src/extension_protocol.rs index 4894d6c13..9c25c6cb8 100644 --- a/crates/openshell-core/src/extension_protocol.rs +++ b/crates/openshell-core/src/extension_protocol.rs @@ -19,10 +19,6 @@ pub const PROTOCOL_MINOR: u32 = 0; /// configured signer before accepting sandbox creation. pub const COMPUTE_LAUNCH_AUTHENTICATION: &str = "openshell.compute.launch-authentication"; -/// Compute drivers advertising this capability enforce the complete startup UI -/// policy contract. Absence means explicit UI policy must be rejected. -pub const POLICY_UI_V1: &str = "openshell.policy.ui.v1"; - const MAX_IMPLEMENTATION_NAME_BYTES: usize = 128; const MAX_IMPLEMENTATION_VERSION_BYTES: usize = 128; const MAX_CAPABILITY_BYTES: usize = 128; @@ -402,36 +398,6 @@ mod tests { ); } - #[test] - fn ui_policy_capability_uses_existing_optional_negotiation() { - let gateway = gateway_metadata(ExtensionFamily::Compute); - let extension = extension_metadata( - ExtensionFamily::Compute, - "openshell/test-ui-driver", - "test", - [POLICY_UI_V1.to_string()], - ); - let result = negotiate( - ExtensionFamily::Compute, - "test-ui-driver", - &gateway, - Some(extension), - ) - .unwrap(); - assert!( - result - .supported_capabilities - .iter() - .any(|value| value == POLICY_UI_V1) - ); - assert!( - !result - .required_capabilities - .iter() - .any(|value| value == POLICY_UI_V1) - ); - } - #[test] fn missing_metadata_and_major_skew_are_actionable() { let (gateway, mut extension) = compatible(); diff --git a/crates/openshell-core/src/policy.rs b/crates/openshell-core/src/policy.rs index 66dde13ca..af474325c 100644 --- a/crates/openshell-core/src/policy.rs +++ b/crates/openshell-core/src/policy.rs @@ -113,10 +113,6 @@ impl TryFrom for SandboxPolicy { type Error = miette::Report; fn try_from(proto: ProtoSandboxPolicy) -> Result { - // 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. A capable - // compute driver consumes the typed proto directly. // In cluster mode we always run with proxy networking so all egress // can be evaluated by OPA. let network = NetworkPolicy { @@ -196,7 +192,6 @@ impl From for ProcessPolicy { #[cfg(test)] mod tests { use super::*; - use crate::proto::{UiClipboardAccess, UiPolicy}; #[test] fn try_from_maps_known_compatibility_values() { @@ -238,26 +233,4 @@ mod tests { assert!(!is_valid_landlock_compatibility("nope")); assert!(!is_valid_landlock_compatibility("BestEffort")); } - - #[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()); - } } diff --git a/crates/openshell-driver-mxc/tests/policy_mapper_matrix.rs b/crates/openshell-driver-mxc/tests/policy_mapper_matrix.rs index 9647d617e..6dda646bd 100644 --- a/crates/openshell-driver-mxc/tests/policy_mapper_matrix.rs +++ b/crates/openshell-driver-mxc/tests/policy_mapper_matrix.rs @@ -1109,7 +1109,6 @@ fn handled_fields_inventory() { // ── (1) Top-level keys: serialize a SandboxPolicy with every section // present-but-minimal, then collect YAML keys. ────────────────────────── let full_toplevel_policy = SandboxPolicy { - ui: None, version: 1, filesystem: Some(FilesystemPolicy { include_workdir: false, diff --git a/crates/openshell-policy-schema/src/lib.rs b/crates/openshell-policy-schema/src/lib.rs index ea0f2b0d0..656433b79 100644 --- a/crates/openshell-policy-schema/src/lib.rs +++ b/crates/openshell-policy-schema/src/lib.rs @@ -195,12 +195,6 @@ pub struct PolicyDocument { skip_serializing_if = "Option::is_none" )] pub process: Option, - #[serde( - default, - deserialize_with = "deserialize_non_null_optional_field", - skip_serializing_if = "Option::is_none" - )] - pub ui: Option, #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] pub network_policies: BTreeMap, #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] @@ -242,34 +236,6 @@ pub struct ProcessPolicy { pub run_as_group: String, } -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct UiPolicy { - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub allow_graphical_ui: bool, - #[serde(default, skip_serializing_if = "UiClipboardAccess::is_none")] - pub clipboard: UiClipboardAccess, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub allow_input_injection: bool, -} - -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum UiClipboardAccess { - #[default] - None, - Read, - Write, - All, -} - -impl UiClipboardAccess { - #[must_use] - pub const fn is_none(&self) -> bool { - matches!(self, Self::None) - } -} - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct NetworkPolicyRule { @@ -774,7 +740,6 @@ fn inspect_document(root: &serde_yml::Value) -> InspectionResult { "filesystem_policy", "landlock", "process", - "ui", "network_policies", "network_middlewares", ], @@ -794,11 +759,6 @@ fn inspect_document(root: &serde_yml::Value) -> InspectionResult { "process", &["run_as_user", "run_as_group"], )?; - inspect_named( - root.get("ui"), - "ui", - &["allow_graphical_ui", "clipboard", "allow_input_injection"], - )?; for (name, rule) in open_map(root.get("network_policies")) { let path = join("network_policies", name); @@ -1262,7 +1222,6 @@ mod tests { for source in [ "version: 1\nfilesystem_policy: null\n", "version: 1\nprocess: null\n", - "version: 1\nui: null\n", "version: 1\nmetadata: null\n", "version: 1\nnetwork_policies:\n x:\n endpoints:\n - host: x\n port: 443\n mcp: null\n", ] { @@ -1348,7 +1307,6 @@ mod tests { "landlock.future", ), ("version: 1\nprocess: { future: true }\n", "process.future"), - ("version: 1\nui: { future: true }\n", "ui.future"), ( "version: 1\nnetwork_policies: { api: { future: true } }\n", "network_policies.api.future", diff --git a/crates/openshell-policy/src/lib.rs b/crates/openshell-policy/src/lib.rs index a2ddd4c45..bad8532cd 100644 --- a/crates/openshell-policy/src/lib.rs +++ b/crates/openshell-policy/src/lib.rs @@ -31,27 +31,9 @@ use openshell_core::mcp::{ use openshell_core::proto::{ FilesystemPolicy, GraphqlOperation, L7Allow, L7DenyRule, L7QueryMatcher, L7Rule, LandlockPolicy, McpOptions, NetworkBinary, NetworkEndpoint, NetworkPolicyRule, ProcessPolicy, - SandboxPolicy, UiClipboardAccess, UiPolicy, + SandboxPolicy, }; -const fn ui_clipboard_to_proto(value: UiClipboardAccessDef) -> UiClipboardAccess { - match value { - UiClipboardAccessDef::None => UiClipboardAccess::None, - UiClipboardAccessDef::Read => UiClipboardAccess::Read, - UiClipboardAccessDef::Write => UiClipboardAccess::Write, - UiClipboardAccessDef::All => UiClipboardAccess::All, - } -} - -fn ui_clipboard_from_proto(value: i32) -> UiClipboardAccessDef { - match UiClipboardAccess::try_from(value).unwrap_or(UiClipboardAccess::Unspecified) { - UiClipboardAccess::Unspecified | UiClipboardAccess::None => UiClipboardAccessDef::None, - UiClipboardAccess::Read => UiClipboardAccessDef::Read, - UiClipboardAccess::Write => UiClipboardAccessDef::Write, - UiClipboardAccess::All => UiClipboardAccessDef::All, - } -} - pub use compose::{ PROVIDER_RULE_NAME_PREFIX, ProviderPolicyLayer, compose_effective_policy, is_provider_rule_name, provider_rule_name, strip_provider_rule_names, @@ -84,7 +66,6 @@ use openshell_policy_schema::{ NetworkCredentialBinding as NetworkCredentialBindingDef, NetworkEndpoint as NetworkEndpointDef, NetworkPolicyRule as NetworkPolicyRuleDef, ParameterMatcher as ParamMatcherDef, PolicyDocument as PolicyFile, ProcessPolicy as ProcessDef, QueryMatcher as QueryMatcherDef, - UiClipboardAccess as UiClipboardAccessDef, UiPolicy as UiDef, }; fn json_rpc_config_from_proto(max_body_bytes: u32) -> Option { @@ -628,11 +609,6 @@ fn to_proto(raw: PolicyFile) -> Result { run_as_user: p.run_as_user, run_as_group: p.run_as_group, }), - ui: raw.ui.map(|ui| UiPolicy { - allow_graphical_ui: ui.allow_graphical_ui, - clipboard: ui_clipboard_to_proto(ui.clipboard) as i32, - allow_input_injection: ui.allow_input_injection, - }), network_policies, network_middlewares, }) @@ -676,12 +652,6 @@ fn from_proto(policy: &SandboxPolicy) -> Result { } }); - let ui = policy.ui.as_ref().map(|ui| UiDef { - allow_graphical_ui: ui.allow_graphical_ui, - clipboard: ui_clipboard_from_proto(ui.clipboard), - allow_input_injection: ui.allow_input_injection, - }); - let network_policies = policy .network_policies .iter() @@ -826,7 +796,6 @@ fn from_proto(policy: &SandboxPolicy) -> Result { filesystem_policy, landlock, process, - ui, network_policies, network_middlewares, }) @@ -1020,7 +989,6 @@ pub fn restrictive_default_policy() -> SandboxPolicy { compatibility: "best_effort".into(), }), process: None, - ui: None, network_policies: HashMap::new(), network_middlewares: HashMap::default(), } @@ -1056,8 +1024,6 @@ const MAX_PATH_LENGTH: usize = 4096; pub enum PolicyViolation { /// An explicit `run_as_user` or `run_as_group` is unsafe. InvalidProcessIdentity { field: &'static str, value: String }, - /// The protobuf carries a clipboard enum value unknown to this version. - InvalidUiClipboardAccess { value: i32 }, /// A filesystem path contains `..` components. PathTraversal { path: String }, /// A filesystem path is not absolute (does not start with `/`). @@ -1159,12 +1125,6 @@ impl fmt::Display for PolicyViolation { "{field} must be 'sandbox' or a numeric UID/GID in range [{MIN_SANDBOX_UID}, {MAX_SANDBOX_UID}], got '{value}'" ) } - Self::InvalidUiClipboardAccess { value } => { - write!( - f, - "ui clipboard access has unknown enum value {value}; expected unspecified, none, read, write, or all" - ) - } Self::PathTraversal { path } => { write!(f, "path contains '..' traversal component: {path}") } @@ -1371,7 +1331,6 @@ impl fmt::Display for PolicyViolation { /// /// Checks performed: /// - Explicit `run_as_user` / `run_as_group` fields must be safe identities -/// - UI clipboard access must use a recognized enum value /// - Filesystem paths must be absolute (start with `/`) /// - Filesystem paths must not contain `..` components /// - Read-write paths must not be overly broad (just `/`) @@ -1486,14 +1445,6 @@ fn validate_sandbox_policy_with_mcp_presence( }); } - if let Some(ref ui) = policy.ui - && UiClipboardAccess::try_from(ui.clipboard).is_err() - { - violations.push(PolicyViolation::InvalidUiClipboardAccess { - value: ui.clipboard, - }); - } - if let Some(ref fs) = policy.filesystem && let Err(errors) = validate_filesystem_paths(&fs.read_only, &fs.read_write) { @@ -1905,7 +1856,6 @@ fn validate_and_canonicalize_mcp_policy_schema( .map_err(|violations| PolicyValidationError { violations })?; materialize_default_mcp_versions(&mut policy); canonicalize_mcp_version_allowlists(&mut policy); - canonicalize_ui_defaults(&mut policy); validate_mcp_policy_schema(&policy, McpVersionPresence::RequireMaterialized) .map_err(|violations| PolicyValidationError { violations })?; Ok(policy) @@ -1928,7 +1878,6 @@ pub fn validate_and_canonicalize_sandbox_policy( .map_err(|violations| PolicyValidationError { violations })?; materialize_default_mcp_versions(&mut policy); canonicalize_mcp_version_allowlists(&mut policy); - canonicalize_ui_defaults(&mut policy); debug_assert!( validate_sandbox_policy(&policy).is_ok(), "validated MCP canonicalization must preserve every policy invariant" @@ -1936,20 +1885,6 @@ pub fn validate_and_canonicalize_sandbox_policy( Ok(policy) } -/// Materialize protobuf UI defaults that have a distinct canonical enum value. -/// -/// Proto3 clients commonly leave `clipboard` at `Unspecified(0)`. `OpenShell` -/// defines that value as deny, so canonical policy state stores the equivalent -/// explicit `None(1)`. This keeps protobuf, YAML, hashes, and static-field -/// comparisons stable across a serialize/parse round trip. -fn canonicalize_ui_defaults(policy: &mut SandboxPolicy) { - if let Some(ui) = policy.ui.as_mut() - && ui.clipboard == UiClipboardAccess::Unspecified as i32 - { - ui.clipboard = UiClipboardAccess::None as i32; - } -} - /// Replace absent protobuf MCP options and empty revision lists with the /// single pinned policy default while preserving every explicit MCP option. pub(crate) fn materialize_default_mcp_versions(policy: &mut SandboxPolicy) { @@ -2069,99 +2004,6 @@ network_policies: assert!(json.get("network_policies").is_some()); } - #[test] - fn ui_absence_and_explicit_empty_remain_distinct() { - let absent = parse_sandbox_policy("version: 1\n").expect("absent UI parses"); - assert!(absent.ui.is_none()); - let absent_yaml = serialize_sandbox_policy(&absent).expect("absent UI serializes"); - assert!(!absent_yaml.contains("\nui:")); - - let explicit = parse_sandbox_policy("version: 1\nui: {}\n").expect("empty UI parses"); - let ui = explicit.ui.as_ref().expect("UI presence preserved"); - assert!(!ui.allow_graphical_ui); - assert_eq!(ui.clipboard, UiClipboardAccess::None as i32); - assert!(!ui.allow_input_injection); - - let explicit_yaml = serialize_sandbox_policy(&explicit).expect("empty UI serializes"); - assert!(explicit_yaml.contains("ui: {}"), "got:\n{explicit_yaml}"); - let reparsed = parse_sandbox_policy(&explicit_yaml).expect("empty UI reparses"); - assert!(reparsed.ui.is_some()); - } - - #[test] - fn ui_policy_round_trips_all_clipboard_directions() { - for (wire, expected) in [ - ("none", UiClipboardAccess::None), - ("read", UiClipboardAccess::Read), - ("write", UiClipboardAccess::Write), - ("all", UiClipboardAccess::All), - ] { - let yaml = format!( - "version: 1\nui:\n allow_graphical_ui: true\n clipboard: {wire}\n allow_input_injection: true\n" - ); - let policy = parse_sandbox_policy(&yaml).expect("UI policy parses"); - let ui = policy.ui.as_ref().expect("UI policy present"); - assert!(ui.allow_graphical_ui); - assert_eq!(ui.clipboard, expected as i32); - assert!(ui.allow_input_injection); - - let serialized = serialize_sandbox_policy(&policy).expect("UI policy serializes"); - let reparsed = parse_sandbox_policy(&serialized).expect("UI policy reparses"); - assert_eq!(reparsed, policy); - } - } - - #[test] - fn ui_unspecified_clipboard_canonicalizes_to_none_across_yaml_round_trip() { - let raw = SandboxPolicy { - version: 1, - ui: Some(UiPolicy { - allow_graphical_ui: true, - clipboard: UiClipboardAccess::Unspecified as i32, - ..Default::default() - }), - ..Default::default() - }; - - let canonical = validate_and_canonicalize_sandbox_policy(raw) - .expect("unspecified clipboard must be a valid deny default"); - assert_eq!( - canonical.ui.as_ref().expect("UI remains present").clipboard, - UiClipboardAccess::None as i32 - ); - - let yaml = serialize_sandbox_policy(&canonical).expect("canonical UI serializes"); - let reparsed = parse_sandbox_policy(&yaml).expect("canonical UI reparses"); - assert_eq!(reparsed, canonical); - } - - #[test] - fn ui_policy_rejects_unknown_yaml_clipboard_value() { - let error = parse_sandbox_policy("version: 1\nui:\n clipboard: execute\n") - .expect_err("unknown clipboard value must fail"); - assert!( - error - .to_string() - .contains("failed to decode sandbox policy fields") - ); - } - - #[test] - fn ui_policy_validation_rejects_unknown_proto_clipboard_value() { - let policy = SandboxPolicy { - ui: Some(UiPolicy { - clipboard: 99, - ..Default::default() - }), - ..Default::default() - }; - let violations = validate_sandbox_policy(&policy).expect_err("unknown enum must fail"); - assert_eq!( - violations, - vec![PolicyViolation::InvalidUiClipboardAccess { value: 99 }] - ); - } - /// Verify that `allowed_ips` survives the round-trip. #[test] fn round_trip_preserves_allowed_ips() { @@ -3861,7 +3703,6 @@ network_policies: process: None, filesystem: None, landlock: None, - ui: None, network_policies: HashMap::new(), network_middlewares: HashMap::default(), }; @@ -4320,7 +4161,6 @@ network_policies: }), filesystem: None, landlock: None, - ui: None, network_policies: HashMap::new(), network_middlewares: HashMap::default(), }; @@ -4337,7 +4177,6 @@ network_policies: }), filesystem: None, landlock: None, - ui: None, network_policies: HashMap::new(), network_middlewares: HashMap::default(), }; @@ -4410,7 +4249,6 @@ network_policies: }), filesystem: None, landlock: None, - ui: None, network_policies: HashMap::new(), network_middlewares: HashMap::default(), }; diff --git a/crates/openshell-prover/src/containment.rs b/crates/openshell-prover/src/containment.rs index 73d96b67a..f7a7a43c3 100644 --- a/crates/openshell-prover/src/containment.rs +++ b/crates/openshell-prover/src/containment.rs @@ -83,11 +83,6 @@ impl ContainmentEndpoint for Endpoint { pub fn parse_policy_str(source: &str) -> Result { let document = openshell_policy_schema::parse_policy(source) .map_err(|error| ParsePolicyError(format!("invalid policy: {error:#}")))?; - if document.ui.is_some() { - return Err(ParsePolicyError( - "UI policy containment is not supported".to_string(), - )); - } let mut filesystem_policy = document.effective_filesystem_policy(); normalize_filesystem_paths(&mut filesystem_policy)?; let PolicyDocument { @@ -97,7 +92,6 @@ pub fn parse_policy_str(source: &str) -> Result CheckOptions { diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index a818300d1..4f17a8530 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -1099,7 +1099,6 @@ impl ComputeRuntime { .as_ref() .and_then(|spec| spec.template.as_ref()), )?; - self.validate_policy_capabilities(sandbox, runtime_inputs.effective_policy.as_ref())?; let mut driver_sandbox = driver_sandbox_from_public(sandbox, &self.driver_info.name) .map_err(|status| *status)?; if let Some(effective_policy) = runtime_inputs.effective_policy.as_ref() @@ -1129,30 +1128,6 @@ impl ComputeRuntime { .map(|_| ()) } - fn validate_policy_capabilities( - &self, - sandbox: &Sandbox, - effective_policy: Option<&ProtoSandboxPolicy>, - ) -> Result<(), Status> { - let has_explicit_ui = effective_policy - .or_else(|| sandbox.spec.as_ref().and_then(|spec| spec.policy.as_ref())) - .and_then(|policy| policy.ui.as_ref()) - .is_some(); - let supports_ui = self - .driver_info - .negotiated_extension - .supported_capabilities - .iter() - .any(|capability| capability == openshell_core::extension_protocol::POLICY_UI_V1); - if has_explicit_ui && !supports_ui { - return Err(Status::failed_precondition(format!( - "compute driver '{}' does not support the complete UI policy contract; remove the explicit ui section or select a supporting driver/backend", - self.driver_info.name - ))); - } - Ok(()) - } - pub async fn create_sandbox( &self, sandbox: Sandbox, @@ -1286,7 +1261,6 @@ impl ComputeRuntime { .as_ref() .and_then(|spec| spec.template.as_ref()), )?; - self.validate_policy_capabilities(&sandbox, runtime_inputs.effective_policy.as_ref())?; let sandbox_id = sandbox.object_id().to_string(); let mut sandbox = sandbox; @@ -7571,12 +7545,12 @@ pub fn new_test_runtime_with_driver( mod tests { use super::*; use futures::stream; + use openshell_core::proto::SandboxPolicy as PublicSandboxPolicy; use openshell_core::proto::compute::v1::{ CreateSandboxResponse, DeleteSandboxResponse, GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse, StartSandboxResponse, StopSandboxRequest, StopSandboxResponse, ValidateSandboxCreateResponse, WatchSandboxesDeletedEvent, WatchSandboxesSandboxEvent, }; - use openshell_core::proto::{SandboxPolicy as PublicSandboxPolicy, UiPolicy}; use std::collections::HashMap; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::{Arc, Mutex as TestMutex}; @@ -8671,131 +8645,6 @@ mod tests { } } - fn sandbox_with_explicit_ui(id: &str) -> Sandbox { - let mut sandbox = sandbox_record(id, "ui-policy", SandboxPhase::Provisioning); - sandbox.spec = Some(SandboxSpec { - policy: Some(PublicSandboxPolicy { - ui: Some(UiPolicy::default()), - ..Default::default() - }), - ..Default::default() - }); - sandbox - } - - #[tokio::test] - async fn explicit_ui_policy_rejects_before_unsupported_driver_validation() { - let driver = Arc::new(TestDriver::default()); - let runtime = test_runtime(driver.clone()).await; - - let error = runtime - .validate_sandbox_create(&sandbox_with_explicit_ui("sb-ui-validate")) - .await - .expect_err("an unsupported driver must reject explicit UI policy"); - - assert_eq!(error.code(), Code::FailedPrecondition); - assert!(error.message().contains("complete UI policy contract")); - assert_eq!( - driver.validate_create_calls.load(Ordering::Relaxed), - 0, - "gateway capability validation must run before the driver RPC" - ); - } - - #[tokio::test] - async fn explicit_ui_policy_rejects_before_unsupported_driver_create() { - let driver = Arc::new(TestDriver::default()); - let runtime = test_runtime(driver.clone()).await; - - let error = runtime - .create_sandbox(sandbox_with_explicit_ui("sb-ui-create"), None, false) - .await - .expect_err("an internal caller must not bypass UI capability validation"); - - assert_eq!(error.code(), Code::FailedPrecondition); - assert_eq!( - driver.create_calls.load(Ordering::Relaxed), - 0, - "unsupported UI policy must fail before provisioning" - ); - } - - #[tokio::test] - async fn effective_ui_policy_rejects_before_unsupported_driver_validation() { - let driver = Arc::new(TestDriver::default()); - let runtime = test_runtime(driver.clone()).await; - let sandbox = sandbox_record( - "sb-effective-ui", - "effective-ui-policy", - SandboxPhase::Provisioning, - ); - let runtime_inputs = SandboxCreateRuntimeInputs::new(PublicSandboxPolicy { - ui: Some(UiPolicy::default()), - ..Default::default() - }); - - let error = runtime - .validate_sandbox_create_with_runtime_inputs(&sandbox, &runtime_inputs) - .await - .expect_err("an unsupported driver must reject the effective UI policy"); - - assert_eq!(error.code(), Code::FailedPrecondition); - assert_eq!(driver.validate_create_calls.load(Ordering::Relaxed), 0); - } - - #[tokio::test] - async fn explicit_ui_policy_reaches_driver_when_capability_is_complete() { - let driver = Arc::new(TestDriver::default()); - let mut runtime = test_runtime(driver.clone()).await; - runtime - .driver_info - .negotiated_extension - .supported_capabilities - .push(openshell_core::extension_protocol::POLICY_UI_V1.to_string()); - - runtime - .validate_sandbox_create(&sandbox_with_explicit_ui("sb-ui-supported")) - .await - .expect("a driver advertising complete UI support accepts validation"); - - assert_eq!(driver.validate_create_calls.load(Ordering::Relaxed), 1); - } - - #[tokio::test] - async fn effective_ui_policy_rejects_before_unsupported_driver_create() { - let driver = Arc::new(TestDriver::default()); - let runtime = test_runtime(driver.clone()).await; - let sandbox = sandbox_record( - "sb-effective-ui-create", - "ui-policy", - SandboxPhase::Provisioning, - ); - let runtime_inputs = SandboxCreateRuntimeInputs::new(PublicSandboxPolicy { - ui: Some(UiPolicy::default()), - ..Default::default() - }); - let error = runtime - .create_sandbox_with_runtime_inputs(sandbox, None, false, runtime_inputs) - .await - .expect_err("effective UI must be checked on internal creation"); - assert_eq!(error.code(), Code::FailedPrecondition); - assert_eq!(driver.create_calls.load(Ordering::Relaxed), 0); - } - - #[tokio::test] - async fn absent_ui_policy_preserves_unsupported_driver_behavior() { - let driver = Arc::new(TestDriver::default()); - let runtime = test_runtime(driver.clone()).await; - let sandbox = sandbox_record("sb-no-ui", "no-ui-policy", SandboxPhase::Provisioning); - - runtime - .validate_sandbox_create(&sandbox) - .await - .expect("an absent UI section must preserve existing behavior"); - - assert_eq!(driver.validate_create_calls.load(Ordering::Relaxed), 1); - } - #[tokio::test] async fn create_runtime_inputs_reach_driver_without_persisting_effective_policy_or_secrets() { let driver = Arc::new(TestDriver::default()); diff --git a/crates/openshell-server/src/grpc/policy.rs b/crates/openshell-server/src/grpc/policy.rs index ade26be05..1782516d3 100644 --- a/crates/openshell-server/src/grpc/policy.rs +++ b/crates/openshell-server/src/grpc/policy.rs @@ -1902,20 +1902,6 @@ async fn auto_approve_chunk( Ok(()) } -/// Preserve UI as the sandbox's startup contract when applying a global policy. -/// -/// UI controls are enforced by the compute runtime before the workload starts, -/// so a later global override cannot safely add, remove, or change them. Global -/// policy writes reject their own UI section; this overlay also prevents a -/// global dynamic policy from hiding the UI state that the runtime enforced. -fn preserve_sandbox_startup_ui(policy: &mut ProtoSandboxPolicy, sandbox: &Sandbox) { - policy.ui = sandbox - .spec - .as_ref() - .and_then(|spec| spec.policy.as_ref()) - .and_then(|policy| policy.ui); -} - // TODO: share effective-policy lookup with `load_sandbox_policy` / // `GetSandboxConfig`. They re-implement very similar global-settings and // profile-composition logic; consolidating them is out of scope for the @@ -1951,11 +1937,10 @@ async fn current_effective_policy_from_records( records: &[super::provider::ProviderEnvironmentRecord], ) -> Result<(ProtoSandboxPolicy, PolicySource), Status> { let global_settings = load_global_settings(state.store.as_ref()).await?; - if let Some(mut global_policy) = decode_policy_from_global_settings(&global_settings)? { + if let Some(global_policy) = decode_policy_from_global_settings(&global_settings)? { // A global policy is the complete effective policy. Dormant sandbox // history and specs may predate the current schema, but they must not // prevent the valid global policy from being served. - preserve_sandbox_startup_ui(&mut global_policy, sandbox); return apply_captured_policy_context( provider_policy_context_from_records(catalog, records), global_policy, @@ -2817,10 +2802,9 @@ pub(super) async fn load_sandbox_config( .await .map_err(|e| Status::internal(format!("fetch policy history failed: {e}")))?; - let (mut policy, version, mut policy_hash, policy_source) = if let Some(mut global_policy) = + let (mut policy, version, mut policy_hash, policy_source) = if let Some(global_policy) = global_policy { - preserve_sandbox_startup_ui(&mut global_policy, sandbox); let version = latest .as_ref() .map(|record| u32::try_from(record.version).unwrap_or(0)) @@ -3882,11 +3866,6 @@ async fn handle_update_config_inner( clear_provider_credentialed_markers(&mut new_policy); validate_no_reserved_provider_policy_keys(&new_policy)?; new_policy = validate_and_canonicalize_policy(new_policy)?; - if new_policy.ui.is_some() { - return Err(Status::invalid_argument( - "UI policy cannot be set globally because it is applied at sandbox startup; configure ui in each sandbox policy", - )); - } validate_policy_safety(&new_policy)?; crate::middleware::validate_policy(state.middleware_registry.as_ref(), &new_policy) .await?; @@ -8600,20 +8579,6 @@ mod tests { assert!(inputs.launch_authentication.is_none()); } - #[tokio::test] - async fn create_runtime_inputs_apply_global_policy_and_preserve_startup_ui() { - let state = test_server_state().await; - let mut global_policy = install_test_global_policy(&state).await; - let mut policy = openshell_policy::restrictive_default_policy(); - policy.ui = Some(openshell_core::proto::UiPolicy::default()); - global_policy.ui = policy.ui; - let sandbox = test_sandbox("create-global", "create-global", policy, Vec::new()); - let inputs = resolve_sandbox_create_runtime_inputs(state.as_ref(), &sandbox) - .await - .expect("global effective policy"); - assert_eq!(inputs.effective_policy, Some(global_policy)); - } - #[tokio::test] async fn list_sandbox_policies_traverses_multiple_pages_exactly_once() { let state = test_server_state().await; @@ -9209,67 +9174,6 @@ mod tests { ); } - #[tokio::test] - async fn global_policy_preserves_each_sandbox_startup_ui_contract() { - use openshell_core::proto::{UiClipboardAccess, UiPolicy}; - - let state = test_server_state().await; - let global_policy = install_test_global_policy(&state).await; - assert!(global_policy.ui.is_none()); - - let sandbox_id = "global-preserves-startup-ui"; - let startup_ui = UiPolicy { - allow_graphical_ui: true, - clipboard: UiClipboardAccess::Read as i32, - allow_input_injection: false, - }; - let mut sandbox_policy = openshell_policy::restrictive_default_policy(); - sandbox_policy.ui = Some(startup_ui); - let sandbox = test_sandbox(sandbox_id, sandbox_id, sandbox_policy, Vec::new()); - state - .store - .put_message(&sandbox) - .await - .expect("store sandbox"); - - let response = handle_get_sandbox_config( - &state, - with_sandbox( - Request::new(GetSandboxConfigRequest { - name: sandbox_id.to_string(), - workspace_scope: Some(openshell_core::proto::workspace_selector("default")), - }), - sandbox_id, - ), - ) - .await - .expect("global policy read must preserve startup UI") - .into_inner(); - assert_eq!( - response - .policy - .as_ref() - .and_then(|policy| policy.ui.as_ref()), - Some(&startup_ui) - ); - - let catalog = state - .provider_profile_sources - .snapshot_catalog(state.store.as_ref(), "default") - .await - .expect("provider profile catalog"); - let effective = current_effective_policy_for_sandbox( - state.as_ref(), - &catalog, - "default", - &sandbox, - sandbox_id, - ) - .await - .expect("effective policy lookup must preserve startup UI"); - assert_eq!(effective.ui.as_ref(), Some(&startup_ui)); - } - #[tokio::test] async fn canonical_mcp_version_order_produces_identical_policy_bytes_and_hashes() { let state = test_server_state().await; @@ -9367,93 +9271,6 @@ mod tests { } } - #[tokio::test] - async fn global_policy_ingress_rejects_startup_only_ui_before_persistence() { - use openshell_core::proto::UiPolicy; - - let state = test_server_state().await; - let mut policy = openshell_policy::restrictive_default_policy(); - policy.ui = Some(UiPolicy::default()); - - let error = handle_update_config( - &state, - with_user(Request::new(UpdateConfigRequest { - global: true, - policy: Some(policy), - ..Default::default() - })), - ) - .await - .expect_err("global UI must be rejected before persistence"); - - assert_eq!(error.code(), Code::InvalidArgument); - assert!(error.message().contains("sandbox startup")); - assert!( - state - .store - .get_latest_policy(GLOBAL_POLICY_SANDBOX_ID) - .await - .expect("global policy lookup") - .is_none() - ); - let settings = load_global_settings(state.store.as_ref()) - .await - .expect("global settings lookup"); - assert!(!settings.settings.contains_key(POLICY_SETTING_KEY)); - } - - #[tokio::test] - async fn sandbox_policy_update_accepts_semantically_unchanged_ui_default() { - use openshell_core::proto::{UiClipboardAccess, UiPolicy}; - - let state = test_server_state().await; - let sandbox_id = "ui-default-roundtrip"; - let mut canonical = openshell_policy::restrictive_default_policy(); - canonical.ui = Some(UiPolicy { - allow_graphical_ui: true, - clipboard: UiClipboardAccess::None as i32, - ..Default::default() - }); - state - .store - .put_message(&test_sandbox( - sandbox_id, - sandbox_id, - canonical.clone(), - Vec::new(), - )) - .await - .expect("store sandbox"); - - let mut protobuf_default = canonical; - protobuf_default.ui.as_mut().expect("UI policy").clipboard = - UiClipboardAccess::Unspecified as i32; - handle_update_config( - &state, - with_user(Request::new(UpdateConfigRequest { - sandbox: sandbox_id.to_string(), - workspace_scope: Some(openshell_core::proto::workspace_selector("default")), - policy: Some(protobuf_default), - ..Default::default() - })), - ) - .await - .expect("unspecified and none are the same static UI policy"); - - let stored = state - .store - .get_latest_policy(sandbox_id) - .await - .expect("policy history lookup") - .expect("policy revision"); - let persisted = ProtoSandboxPolicy::decode(stored.policy_payload.as_slice()) - .expect("decode persisted policy"); - assert_eq!( - persisted.ui.expect("persisted UI").clipboard, - UiClipboardAccess::None as i32 - ); - } - #[tokio::test] async fn policy_record_identity_global_deduplicates_defaulted_mcp_history() { for (case, legacy_policy) in defaulted_mcp_policy_cases() { @@ -21507,35 +21324,6 @@ mod tests { ); } - #[test] - fn policy_hash_distinguishes_ui_absence_presence_and_values() { - use openshell_core::proto::{UiClipboardAccess, UiPolicy}; - - let absent = ProtoSandboxPolicy::default(); - let explicit_deny = ProtoSandboxPolicy { - ui: Some(UiPolicy::default()), - ..Default::default() - }; - let clipboard_read = ProtoSandboxPolicy { - ui: Some(UiPolicy { - clipboard: UiClipboardAccess::Read as i32, - ..Default::default() - }), - ..Default::default() - }; - - assert_ne!( - deterministic_policy_hash(&absent), - deterministic_policy_hash(&explicit_deny), - "an explicitly present deny-only UI block remains hash-significant" - ); - assert_ne!( - deterministic_policy_hash(&explicit_deny), - deterministic_policy_hash(&clipboard_read), - "UI capability changes must produce a new policy hash" - ); - } - #[test] fn policy_hash_is_stable_across_middleware_config_field_insertion_order() { use prost_types::{Struct, Value, value::Kind}; diff --git a/crates/openshell-server/src/grpc/validation.rs b/crates/openshell-server/src/grpc/validation.rs index 4d47b9510..abdfccda1 100644 --- a/crates/openshell-server/src/grpc/validation.rs +++ b/crates/openshell-server/src/grpc/validation.rs @@ -10,7 +10,7 @@ use openshell_core::proto::{ CredentialHandle, ExecSandboxRequest, Provider, SandboxPolicy as ProtoSandboxPolicy, - SandboxRestartPolicy, SandboxSpec, SandboxTemplate, UiClipboardAccess, + SandboxRestartPolicy, SandboxSpec, SandboxTemplate, }; use openshell_core::rpc_error::invalid_argument; use prost::Message; @@ -1030,7 +1030,7 @@ pub(super) fn validate_no_reserved_provider_policy_keys( Ok(()) } -/// Validate that static policy fields (filesystem, landlock, process, UI) haven't changed +/// Validate that static policy fields (filesystem, landlock, process) haven't changed /// from the baseline (version 1) policy. pub(super) fn validate_static_fields_unchanged( baseline: &ProtoSandboxPolicy, @@ -1054,18 +1054,6 @@ pub(super) fn validate_static_fields_unchanged( "process policy cannot be changed on a live sandbox (applied at startup)", )); } - let mut baseline_ui = baseline.ui; - let mut new_ui = new.ui; - for ui in [&mut baseline_ui, &mut new_ui].into_iter().flatten() { - if ui.clipboard == UiClipboardAccess::Unspecified as i32 { - ui.clipboard = UiClipboardAccess::None as i32; - } - } - if baseline_ui != new_ui { - return Err(Status::invalid_argument( - "UI policy cannot be changed on a live sandbox (applied at startup)", - )); - } Ok(()) } @@ -2413,33 +2401,6 @@ mod tests { assert!(result.unwrap_err().message().contains("include_workdir")); } - #[test] - fn validate_static_fields_rejects_ui_presence_or_value_change() { - use openshell_core::proto::{UiClipboardAccess, UiPolicy}; - - let absent = ProtoSandboxPolicy::default(); - let deny = ProtoSandboxPolicy { - ui: Some(UiPolicy::default()), - ..Default::default() - }; - let allow_clipboard = ProtoSandboxPolicy { - ui: Some(UiPolicy { - clipboard: UiClipboardAccess::Read as i32, - ..Default::default() - }), - ..Default::default() - }; - - let presence_error = validate_static_fields_unchanged(&absent, &deny) - .expect_err("adding explicit UI policy must be static"); - assert!(presence_error.message().contains("UI policy")); - - let value_error = validate_static_fields_unchanged(&deny, &allow_clipboard) - .expect_err("changing UI policy must be static"); - assert!(value_error.message().contains("UI policy")); - assert!(validate_static_fields_unchanged(&deny, &deny).is_ok()); - } - // ---- Exec validation ---- #[test] diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index 503b956af..3ec9adbf0 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -143,11 +143,11 @@ mod tests { // Legacy payloads decode empty owners; the gateway rebuilds their authority // from effective policy rather than trusting persisted owner stamps. const PUBLIC_RPC_SCHEMA_SHA256: &str = - "3066eb8ed5a0b43381196e5c19716a0e5a284996c0dfe0122750a6e7366beb5d"; + "18206c52e68fdb0af60f8bb8dfaf47d9bc8021222cb49cacffab6352d3ad5549"; const DURABLE_SCHEMA_SHA256: &str = - "ebb9153e436a6c042a221ec3daa7bb0d21ad81e31ce841ee1b5144404156802e"; + "76487ab369fc3a4b03a179bb5e7ea6be8d20e380ad5563075dff8ee50e539406"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = - "5f5165548d2ec333689fc88ab652af1977760bb976007a634e3ed30f28782424"; + "761dea31a521b0650840fe2a823ad6e36a265ed323ba4506889781d630df0ee3"; // A persisted Sandbox without endpoint status retains its lifecycle fields; // the absent repeated field decodes empty and needs no database rewrite. const SANDBOX_WITHOUT_ENDPOINT_STATUS: &str = "0a1e0a0a73616e64626f782d6964120773616e64626f783a0764656661756c741a2b0a0773616e64626f782a0d0a05526561647912045472756530023807420d73757065727669736f722d6964"; @@ -612,9 +612,9 @@ mod tests { overlap_hash.as_str(), ), ( - (307, 28), - (94, 22), - (82, 22), + (306, 27), + (93, 21), + (81, 21), PUBLIC_RPC_SCHEMA_SHA256, DURABLE_SCHEMA_SHA256, PUBLIC_DURABLE_OVERLAP_SHA256 @@ -743,7 +743,6 @@ mod tests { PolicyRevisionPayload::decode(legacy_bytes(V0_0_116_POLICY_PAYLOAD).as_slice()) .expect("legacy policy payload must decode"); assert!(policy_payload.policy.is_some()); - assert!(policy_payload.policy.as_ref().unwrap().ui.is_none()); assert_eq!(policy_payload.hash, "sha256"); assert_eq!(policy_payload.load_error, "none"); assert_eq!(policy_payload.loaded_at_ms, 300); diff --git a/crates/openshell-supervisor-network/src/opa.rs b/crates/openshell-supervisor-network/src/opa.rs index 6c28c3e11..62cf0582e 100644 --- a/crates/openshell-supervisor-network/src/opa.rs +++ b/crates/openshell-supervisor-network/src/opa.rs @@ -1559,7 +1559,6 @@ fn validate_opa_static_settings(data: &mut serde_json::Value) -> Result<()> { fn redacted_policy_violation_category(violation: &PolicyViolation) -> &'static str { match violation { PolicyViolation::InvalidProcessIdentity { .. } => "invalid process identity", - PolicyViolation::InvalidUiClipboardAccess { .. } => "invalid UI clipboard access", PolicyViolation::InvalidLandlockCompatibility { .. } => "invalid Landlock compatibility", PolicyViolation::PathTraversal { .. } | PolicyViolation::RelativePath { .. } @@ -3371,7 +3370,6 @@ mod tests { run_as_user: "sandbox".to_string(), run_as_group: "sandbox".to_string(), }), - ui: None, network_policies, network_middlewares: std::collections::HashMap::default(), } @@ -5731,7 +5729,6 @@ process: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto_with_pid_and_binary_identity_required(&proto, 0, false) .expect("engine from relaxed proto"); @@ -6355,7 +6352,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).expect("engine from proto"); @@ -6427,7 +6423,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).expect("engine from proto"); @@ -6504,7 +6499,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).expect("engine from proto"); @@ -8248,7 +8242,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).expect("engine from proto"); @@ -8306,7 +8299,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).expect("engine from proto"); @@ -8365,7 +8357,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).expect("engine from proto"); @@ -8426,7 +8417,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).expect("engine from proto"); @@ -8486,7 +8476,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).expect("engine from proto"); @@ -9998,7 +9987,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).expect("engine from proto"); let input = NetworkInput { @@ -10069,7 +10057,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).expect("Failed to create engine from proto"); @@ -10300,7 +10287,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let engine = OpaEngine::from_proto(&proto).unwrap(); // Port 443 @@ -11266,7 +11252,6 @@ network_policies: process: None, network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; let pid = std::process::id(); // accessible root, leaf paths absent @@ -11950,7 +11935,6 @@ network_policies: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; // Build engine with our PID (symlink resolution will work via /proc/self/root/) @@ -12114,7 +12098,6 @@ process: }), network_policies, network_middlewares: std::collections::HashMap::default(), - ui: None, }; // Initial load at pid=0 — no symlink expansion diff --git a/docs/how-it-works/policies/overview.mdx b/docs/how-it-works/policies/overview.mdx index 4d5757af0..d5800bf0a 100644 --- a/docs/how-it-works/policies/overview.mdx +++ b/docs/how-it-works/policies/overview.mdx @@ -20,7 +20,7 @@ Policies](/how-it-works/policies/manage-policies). ## What a Policy Controls -A policy file sets `version: 1` and has up to six other top-level sections. +A policy file sets `version: 1` and has up to five other top-level sections. Each section controls a different part of the sandbox and takes effect at a specific time: @@ -29,11 +29,10 @@ specific time: | `filesystem_policy` | Paths that sandbox processes can read, or read and write. | Landlock LSM in the kernel. | At sandbox startup. | | `landlock` | Whether the sandbox still starts, without your filesystem rules, if OpenShell cannot apply them. | Sandbox runtime. | At sandbox startup. | | `process` | User and group that sandbox processes run as. | Docker and Podman, when they create the sandbox. | At sandbox creation. | -| `ui` | Graphical UI, clipboard, and synthetic input. | A compute driver advertising complete UI-policy support. | At sandbox creation. | | `network_policies` | Destinations each binary can reach, and the requests it can send. | Sandbox network proxy. | While the sandbox runs. | | `network_middlewares` | Additional inspection, transformation, or blocking of traffic that network rules allow. | Sandbox network proxy. | While the sandbox runs. | -Filesystem, Landlock, process, and UI settings are fixed once the sandbox starts. +Filesystem, Landlock, and process settings are fixed once the sandbox starts. Network rules and middleware can change while it runs, as described in [How Changes Take Effect](/how-it-works/policies/manage-policies#how-changes-take-effect). diff --git a/docs/how-it-works/policies/schema.mdx b/docs/how-it-works/policies/schema.mdx index 7a360e41f..db85e3a19 100644 --- a/docs/how-it-works/policies/schema.mdx +++ b/docs/how-it-works/policies/schema.mdx @@ -19,7 +19,6 @@ version: 1 filesystem_policy: { ... } landlock: { ... } process: { ... } -ui: { ... } network_policies: { ... } network_middlewares: { ... } ``` @@ -30,7 +29,6 @@ network_middlewares: { ... } | `filesystem_policy` | object | No | Startup | Paths the workload can read and write. | | `landlock` | object | No | Startup | Landlock enforcement behavior. | | `process` | object | No | Startup | User and group that the workload runs as. | -| `ui` | object | No | Startup | Graphical UI, clipboard, and input injection on a supporting runtime. | | `network_policies` | map | No | Live | Which binaries can reach which network endpoints. | | `network_middlewares` | map | No | Live | Middleware applied to allowed traffic. | @@ -101,32 +99,6 @@ process: run_as_group: "1500" ``` -## UI - -UI controls require the selected compute driver to advertise -`openshell.policy.ui.v1` in its extension capabilities. Unsupported drivers -reject any explicit UI section, including -`ui: {}`, before provisioning. Omit the section to preserve their existing -behavior. - -| Field | Type | Default | Description | -|---|---|---|---| -| `allow_graphical_ui` | bool | `false` | Allows a graphical UI surface. | -| `clipboard` | string | `none` | `none`, `read`, `write`, or `all`, from the sandbox's perspective. | -| `allow_input_injection` | bool | `false` | Allows synthetic input. | - -Clipboard access and input injection require `allow_graphical_ui: true`. -Unknown fields and values are rejected. UI settings are startup-only; recreate -the sandbox to change them. Global policies cannot set UI and preserve each -sandbox's startup UI settings. - -```yaml showLineNumbers={false} -ui: - allow_graphical_ui: true - clipboard: read - allow_input_injection: false -``` - ## Network Policies A map of named rules. The key is the rule's name. Each rule allows every listed diff --git a/proto/sandbox.proto b/proto/sandbox.proto index 3dd8dc065..7f7f407c3 100644 --- a/proto/sandbox.proto +++ b/proto/sandbox.proto @@ -33,10 +33,6 @@ message SandboxPolicy { // policy-local names. At most 10 configs are accepted, and at most 10 stages // can be selected per request. map network_middlewares = 6; - // Static, platform-neutral user-interface access policy. Within an explicit - // section, omitted capabilities deny. Omitting the section preserves the - // compute platform's existing behavior. - UiPolicy ui = 7; } // Filesystem access policy. @@ -63,32 +59,6 @@ message ProcessPolicy { string run_as_group = 2; } -// Directional clipboard access for a sandboxed workload. -enum UiClipboardAccess { - // Unspecified resolves to no clipboard access. - UI_CLIPBOARD_ACCESS_UNSPECIFIED = 0; - // No clipboard reads or writes. - UI_CLIPBOARD_ACCESS_NONE = 1; - // The sandbox may read host clipboard contents. - UI_CLIPBOARD_ACCESS_READ = 2; - // The sandbox may write host clipboard contents. - UI_CLIPBOARD_ACCESS_WRITE = 3; - // The sandbox may read and write host clipboard contents. - UI_CLIPBOARD_ACCESS_ALL = 4; -} - -// Platform-neutral user-interface capabilities. Every omitted field in an -// explicit policy defaults to deny. Compute platforms without complete support -// reject the entire explicit policy before provisioning. -message UiPolicy { - // Allow the sandbox to display graphical windows. - bool allow_graphical_ui = 1; - // Directional host clipboard access. - UiClipboardAccess clipboard = 2; - // Allow the sandbox to synthesize keyboard or pointer input. - bool allow_input_injection = 3; -} - // A named network access policy rule. message NetworkPolicyRule { // Human-readable name for this policy rule. diff --git a/sdk/go/openshell/v1/fake/sandbox.go b/sdk/go/openshell/v1/fake/sandbox.go index 965e11b0d..2932457c2 100644 --- a/sdk/go/openshell/v1/fake/sandbox.go +++ b/sdk/go/openshell/v1/fake/sandbox.go @@ -79,10 +79,6 @@ func copySandboxPolicy(p *types.SandboxPolicy) *types.SandboxPolicy { pr := *p.Process cp.Process = &pr } - if p.UI != nil { - ui := *p.UI - cp.UI = &ui - } if p.NetworkPolicies != nil { np := make(map[string]types.NetworkPolicyRule, len(p.NetworkPolicies)) for k, rule := range p.NetworkPolicies { diff --git a/sdk/go/openshell/v1/fake/sandbox_test.go b/sdk/go/openshell/v1/fake/sandbox_test.go index 526cf4319..4329652c1 100644 --- a/sdk/go/openshell/v1/fake/sandbox_test.go +++ b/sdk/go/openshell/v1/fake/sandbox_test.go @@ -843,11 +843,6 @@ func TestFakeSandboxCreateWithPolicy(t *testing.T) { RunAsUser: "sandbox", RunAsGroup: "sandbox-group", }, - UI: &types.UIPolicy{ - AllowGraphicalUI: true, - Clipboard: types.UIClipboardAccessRead, - AllowInputInjection: true, - }, NetworkPolicies: map[string]types.NetworkPolicyRule{ "web": { Name: "web", @@ -885,10 +880,6 @@ func TestFakeSandboxCreateWithPolicy(t *testing.T) { require.NotNil(t, p.Process) assert.Equal(t, "sandbox", p.Process.RunAsUser) assert.Equal(t, "sandbox-group", p.Process.RunAsGroup) - require.NotNil(t, p.UI) - assert.True(t, p.UI.AllowGraphicalUI) - assert.Equal(t, types.UIClipboardAccessRead, p.UI.Clipboard) - assert.True(t, p.UI.AllowInputInjection) require.Len(t, p.NetworkPolicies, 1) webRule, ok := p.NetworkPolicies["web"] @@ -901,23 +892,19 @@ func TestFakeSandboxCreateWithPolicy(t *testing.T) { // Deep-copy isolation: mutate input spec, verify stored copy unchanged spec.Policy.Version = 99 spec.Policy.Filesystem.ReadOnly[0] = "mutated" - spec.Policy.UI.Clipboard = types.UIClipboardAccessAll spec.Policy.NetworkPolicies["web"] = types.NetworkPolicyRule{Name: "mutated"} got2, err := sc.Get(ctx, "default", "policy-sb") require.NoError(t, err) assert.Equal(t, uint32(3), got2.Spec.Policy.Version) assert.Equal(t, "/etc", got2.Spec.Policy.Filesystem.ReadOnly[0]) - assert.Equal(t, types.UIClipboardAccessRead, got2.Spec.Policy.UI.Clipboard) assert.Equal(t, "web", got2.Spec.Policy.NetworkPolicies["web"].Name) // Deep-copy isolation: mutate returned object, verify store unchanged got.Spec.Policy.Filesystem.ReadWrite[0] = "mutated" - got.Spec.Policy.UI.AllowInputInjection = false got3, err := sc.Get(ctx, "default", "policy-sb") require.NoError(t, err) assert.Equal(t, "/tmp", got3.Spec.Policy.Filesystem.ReadWrite[0]) - assert.True(t, got3.Spec.Policy.UI.AllowInputInjection) } func TestFakeSandboxCreateWithNilPolicy(t *testing.T) { diff --git a/sdk/go/openshell/v1/internal/converter/coverage_test.go b/sdk/go/openshell/v1/internal/converter/coverage_test.go index a8d57e3b1..be563af9c 100644 --- a/sdk/go/openshell/v1/internal/converter/coverage_test.go +++ b/sdk/go/openshell/v1/internal/converter/coverage_test.go @@ -171,7 +171,6 @@ func TestConverterCoversAllProtoFields_SandboxPolicy(t *testing.T) { "network_policies": true, "process": true, "landlock": true, - "ui": true, "network_middlewares": true, } diff --git a/sdk/go/openshell/v1/internal/converter/policy.go b/sdk/go/openshell/v1/internal/converter/policy.go index 7be4ecbb8..1a473654e 100644 --- a/sdk/go/openshell/v1/internal/converter/policy.go +++ b/sdk/go/openshell/v1/internal/converter/policy.go @@ -117,7 +117,6 @@ func SandboxPolicyFromProto(p *sbv1.SandboxPolicy) *types.SandboxPolicy { Filesystem: filesystemPolicyFromProto(p.GetFilesystem()), Landlock: landlockPolicyFromProto(p.GetLandlock()), Process: processPolicyFromProto(p.GetProcess()), - UI: uiPolicyFromProto(p.GetUi()), } if np := p.GetNetworkPolicies(); np != nil { result.NetworkPolicies = make(map[string]types.NetworkPolicyRule, len(np)) @@ -149,7 +148,6 @@ func SandboxPolicyToProto(p *types.SandboxPolicy) *sbv1.SandboxPolicy { Filesystem: filesystemPolicyToProto(p.Filesystem), Landlock: landlockPolicyToProto(p.Landlock), Process: processPolicyToProto(p.Process), - Ui: uiPolicyToProto(p.UI), } if p.NetworkPolicies != nil { result.NetworkPolicies = make(map[string]*sbv1.NetworkPolicyRule, len(p.NetworkPolicies)) @@ -186,58 +184,6 @@ func SandboxPolicyToProtoChecked(p *types.SandboxPolicy) (*sbv1.SandboxPolicy, e return result, nil } -func uiPolicyFromProto(p *sbv1.UiPolicy) *types.UIPolicy { - if p == nil { - return nil - } - return &types.UIPolicy{ - AllowGraphicalUI: p.GetAllowGraphicalUi(), - Clipboard: uiClipboardAccessFromProto(p.GetClipboard()), - AllowInputInjection: p.GetAllowInputInjection(), - } -} - -func uiPolicyToProto(p *types.UIPolicy) *sbv1.UiPolicy { - if p == nil { - return nil - } - return &sbv1.UiPolicy{ - AllowGraphicalUi: p.AllowGraphicalUI, - Clipboard: uiClipboardAccessToProto(p.Clipboard), - AllowInputInjection: p.AllowInputInjection, - } -} - -func uiClipboardAccessFromProto(v sbv1.UiClipboardAccess) types.UIClipboardAccess { - switch v { - case sbv1.UiClipboardAccess_UI_CLIPBOARD_ACCESS_NONE: - return types.UIClipboardAccessNone - case sbv1.UiClipboardAccess_UI_CLIPBOARD_ACCESS_READ: - return types.UIClipboardAccessRead - case sbv1.UiClipboardAccess_UI_CLIPBOARD_ACCESS_WRITE: - return types.UIClipboardAccessWrite - case sbv1.UiClipboardAccess_UI_CLIPBOARD_ACCESS_ALL: - return types.UIClipboardAccessAll - default: - return types.UIClipboardAccessUnspecified - } -} - -func uiClipboardAccessToProto(v types.UIClipboardAccess) sbv1.UiClipboardAccess { - switch v { - case types.UIClipboardAccessNone: - return sbv1.UiClipboardAccess_UI_CLIPBOARD_ACCESS_NONE - case types.UIClipboardAccessRead: - return sbv1.UiClipboardAccess_UI_CLIPBOARD_ACCESS_READ - case types.UIClipboardAccessWrite: - return sbv1.UiClipboardAccess_UI_CLIPBOARD_ACCESS_WRITE - case types.UIClipboardAccessAll: - return sbv1.UiClipboardAccess_UI_CLIPBOARD_ACCESS_ALL - default: - return sbv1.UiClipboardAccess_UI_CLIPBOARD_ACCESS_UNSPECIFIED - } -} - func middlewareConfigFromProto(m *sbv1.NetworkMiddlewareConfig) types.NetworkMiddlewareConfig { result := types.NetworkMiddlewareConfig{ Name: m.GetName(), diff --git a/sdk/go/openshell/v1/internal/converter/policy_test.go b/sdk/go/openshell/v1/internal/converter/policy_test.go index c6cf740d7..dde220577 100644 --- a/sdk/go/openshell/v1/internal/converter/policy_test.go +++ b/sdk/go/openshell/v1/internal/converter/policy_test.go @@ -200,11 +200,6 @@ func TestSandboxPolicyRoundTrip(t *testing.T) { RunAsUser: "sandbox-user", RunAsGroup: "sandbox-group", }, - UI: &v1.UIPolicy{ - AllowGraphicalUI: true, - Clipboard: v1.UIClipboardAccessRead, - AllowInputInjection: true, - }, NetworkPolicies: map[string]v1.NetworkPolicyRule{ "web-api": { Name: "web-api", @@ -244,10 +239,6 @@ func TestSandboxPolicyRoundTrip(t *testing.T) { assert.Equal(t, original.Process.RunAsUser, roundTrip.Process.RunAsUser) assert.Equal(t, original.Process.RunAsGroup, roundTrip.Process.RunAsGroup) - // UI - require.NotNil(t, roundTrip.UI) - assert.Equal(t, original.UI, roundTrip.UI) - // NetworkPolicies require.Len(t, roundTrip.NetworkPolicies, 2) webAPI, ok := roundTrip.NetworkPolicies["web-api"] @@ -324,39 +315,6 @@ func TestSandboxPolicyPartialSubPolicies(t *testing.T) { assert.Nil(t, roundTrip.NetworkPolicies) }) - t.Run("only UI", func(t *testing.T) { - for _, clipboard := range []v1.UIClipboardAccess{ - v1.UIClipboardAccessUnspecified, - v1.UIClipboardAccessNone, - v1.UIClipboardAccessRead, - v1.UIClipboardAccessWrite, - v1.UIClipboardAccessAll, - } { - original := &v1.SandboxPolicy{ - UI: &v1.UIPolicy{ - AllowGraphicalUI: true, - Clipboard: clipboard, - AllowInputInjection: true, - }, - } - roundTrip := SandboxPolicyFromProto(SandboxPolicyToProto(original)) - require.NotNil(t, roundTrip) - assert.Equal(t, original.UI, roundTrip.UI) - } - }) - - t.Run("explicit empty UI remains present", func(t *testing.T) { - original := &v1.SandboxPolicy{UI: &v1.UIPolicy{}} - protoPolicy := SandboxPolicyToProto(original) - require.NotNil(t, protoPolicy) - require.NotNil(t, protoPolicy.Ui) - - roundTrip := SandboxPolicyFromProto(protoPolicy) - require.NotNil(t, roundTrip) - require.NotNil(t, roundTrip.UI) - assert.Equal(t, &v1.UIPolicy{}, roundTrip.UI) - }) - t.Run("only landlock", func(t *testing.T) { original := &v1.SandboxPolicy{ Version: 2, diff --git a/sdk/go/openshell/v1/types/policy.go b/sdk/go/openshell/v1/types/policy.go index ab0101452..8fb0712b6 100644 --- a/sdk/go/openshell/v1/types/policy.go +++ b/sdk/go/openshell/v1/types/policy.go @@ -112,7 +112,7 @@ type DraftPolicy struct { // SandboxPolicy is the top-level security policy configuration for a sandbox. // It contains filesystem access rules, Landlock LSM configuration, process -// identity rules, portable UI capabilities, and named network access policies. +// identity rules, and named network access policies. type SandboxPolicy struct { // Version is the policy version number. The server may override this on write. Version uint32 @@ -125,9 +125,6 @@ type SandboxPolicy struct { // Process controls the user and group identity for sandboxed processes. // Nil means no process policy is specified. Process *ProcessPolicy - // UI controls portable graphical UI, clipboard, and input-injection capabilities. - // Nil means no UI policy is specified. - UI *UIPolicy // NetworkPolicies contains named network access rules. // Nil means no network policies are specified; an empty map is distinct from nil. NetworkPolicies map[string]NetworkPolicyRule @@ -181,33 +178,6 @@ type ProcessPolicy struct { RunAsGroup string } -// UIClipboardAccess controls host clipboard direction from the sandbox's perspective. -type UIClipboardAccess int - -const ( - // UIClipboardAccessUnspecified resolves to no clipboard access. - UIClipboardAccessUnspecified UIClipboardAccess = iota - // UIClipboardAccessNone denies clipboard reads and writes. - UIClipboardAccessNone - // UIClipboardAccessRead permits reading host clipboard contents. - UIClipboardAccessRead - // UIClipboardAccessWrite permits writing host clipboard contents. - UIClipboardAccessWrite - // UIClipboardAccessAll permits reading and writing host clipboard contents. - UIClipboardAccessAll -) - -// UIPolicy declares platform-neutral user-interface capabilities. -// Every zero value denies access. -type UIPolicy struct { - // AllowGraphicalUI permits the workload to display graphical windows. - AllowGraphicalUI bool - // Clipboard controls host clipboard direction. - Clipboard UIClipboardAccess - // AllowInputInjection permits synthetic keyboard or pointer input. - AllowInputInjection bool -} - // SandboxPolicyRevision represents a versioned policy revision for a sandbox. type SandboxPolicyRevision struct { // Version is the policy version (monotonically increasing per sandbox). diff --git a/sdk/go/proto/sandboxv1/sandbox.pb.go b/sdk/go/proto/sandboxv1/sandbox.pb.go index 83d114387..237c2c94b 100644 --- a/sdk/go/proto/sandboxv1/sandbox.pb.go +++ b/sdk/go/proto/sandboxv1/sandbox.pb.go @@ -27,67 +27,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// Directional clipboard access for a sandboxed workload. -type UiClipboardAccess int32 - -const ( - // Unspecified resolves to no clipboard access. - UiClipboardAccess_UI_CLIPBOARD_ACCESS_UNSPECIFIED UiClipboardAccess = 0 - // No clipboard reads or writes. - UiClipboardAccess_UI_CLIPBOARD_ACCESS_NONE UiClipboardAccess = 1 - // The sandbox may read host clipboard contents. - UiClipboardAccess_UI_CLIPBOARD_ACCESS_READ UiClipboardAccess = 2 - // The sandbox may write host clipboard contents. - UiClipboardAccess_UI_CLIPBOARD_ACCESS_WRITE UiClipboardAccess = 3 - // The sandbox may read and write host clipboard contents. - UiClipboardAccess_UI_CLIPBOARD_ACCESS_ALL UiClipboardAccess = 4 -) - -// Enum value maps for UiClipboardAccess. -var ( - UiClipboardAccess_name = map[int32]string{ - 0: "UI_CLIPBOARD_ACCESS_UNSPECIFIED", - 1: "UI_CLIPBOARD_ACCESS_NONE", - 2: "UI_CLIPBOARD_ACCESS_READ", - 3: "UI_CLIPBOARD_ACCESS_WRITE", - 4: "UI_CLIPBOARD_ACCESS_ALL", - } - UiClipboardAccess_value = map[string]int32{ - "UI_CLIPBOARD_ACCESS_UNSPECIFIED": 0, - "UI_CLIPBOARD_ACCESS_NONE": 1, - "UI_CLIPBOARD_ACCESS_READ": 2, - "UI_CLIPBOARD_ACCESS_WRITE": 3, - "UI_CLIPBOARD_ACCESS_ALL": 4, - } -) - -func (x UiClipboardAccess) Enum() *UiClipboardAccess { - p := new(UiClipboardAccess) - *p = x - return p -} - -func (x UiClipboardAccess) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (UiClipboardAccess) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[0].Descriptor() -} - -func (UiClipboardAccess) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[0] -} - -func (x UiClipboardAccess) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use UiClipboardAccess.Descriptor instead. -func (UiClipboardAccess) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{0} -} - // TLS handling for a network endpoint. type NetworkTlsMode int32 @@ -133,11 +72,11 @@ func (x NetworkTlsMode) String() string { } func (NetworkTlsMode) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[1].Descriptor() + return file_sandbox_proto_enumTypes[0].Descriptor() } func (NetworkTlsMode) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[1] + return &file_sandbox_proto_enumTypes[0] } func (x NetworkTlsMode) Number() protoreflect.EnumNumber { @@ -146,7 +85,7 @@ func (x NetworkTlsMode) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkTlsMode.Descriptor instead. func (NetworkTlsMode) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{1} + return file_sandbox_proto_rawDescGZIP(), []int{0} } // Enforcement behavior for inspected network traffic. @@ -186,11 +125,11 @@ func (x NetworkEnforcementMode) String() string { } func (NetworkEnforcementMode) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[2].Descriptor() + return file_sandbox_proto_enumTypes[1].Descriptor() } func (NetworkEnforcementMode) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[2] + return &file_sandbox_proto_enumTypes[1] } func (x NetworkEnforcementMode) Number() protoreflect.EnumNumber { @@ -199,7 +138,7 @@ func (x NetworkEnforcementMode) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkEnforcementMode.Descriptor instead. func (NetworkEnforcementMode) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{2} + return file_sandbox_proto_rawDescGZIP(), []int{1} } // Shorthand access policy for an inspected network endpoint. @@ -243,11 +182,11 @@ func (x NetworkAccessPreset) String() string { } func (NetworkAccessPreset) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[3].Descriptor() + return file_sandbox_proto_enumTypes[2].Descriptor() } func (NetworkAccessPreset) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[3] + return &file_sandbox_proto_enumTypes[2] } func (x NetworkAccessPreset) Number() protoreflect.EnumNumber { @@ -256,7 +195,7 @@ func (x NetworkAccessPreset) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkAccessPreset.Descriptor instead. func (NetworkAccessPreset) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{3} + return file_sandbox_proto_rawDescGZIP(), []int{2} } // Scope that currently controls a setting. @@ -293,11 +232,11 @@ func (x SettingScope) String() string { } func (SettingScope) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[4].Descriptor() + return file_sandbox_proto_enumTypes[3].Descriptor() } func (SettingScope) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[4] + return &file_sandbox_proto_enumTypes[3] } func (x SettingScope) Number() protoreflect.EnumNumber { @@ -306,7 +245,7 @@ func (x SettingScope) Number() protoreflect.EnumNumber { // Deprecated: Use SettingScope.Descriptor instead. func (SettingScope) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{4} + return file_sandbox_proto_rawDescGZIP(), []int{3} } // Source used for the policy payload in GetSandboxConfigResponse. @@ -343,11 +282,11 @@ func (x PolicySource) String() string { } func (PolicySource) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[5].Descriptor() + return file_sandbox_proto_enumTypes[4].Descriptor() } func (PolicySource) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[5] + return &file_sandbox_proto_enumTypes[4] } func (x PolicySource) Number() protoreflect.EnumNumber { @@ -356,7 +295,7 @@ func (x PolicySource) Number() protoreflect.EnumNumber { // Deprecated: Use PolicySource.Descriptor instead. func (PolicySource) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{5} + return file_sandbox_proto_rawDescGZIP(), []int{4} } // Sandbox security policy configuration. @@ -376,12 +315,8 @@ type SandboxPolicy struct { // policy-local names. At most 10 configs are accepted, and at most 10 stages // can be selected per request. NetworkMiddlewares map[string]*NetworkMiddlewareConfig `protobuf:"bytes,6,rep,name=network_middlewares,json=networkMiddlewares,proto3" json:"network_middlewares,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - // Static, platform-neutral user-interface access policy. Within an explicit - // section, omitted capabilities deny. Omitting the section preserves the - // compute platform's existing behavior. - Ui *UiPolicy `protobuf:"bytes,7,opt,name=ui,proto3" json:"ui,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SandboxPolicy) Reset() { @@ -456,13 +391,6 @@ func (x *SandboxPolicy) GetNetworkMiddlewares() map[string]*NetworkMiddlewareCon return nil } -func (x *SandboxPolicy) GetUi() *UiPolicy { - if x != nil { - return x.Ui - } - return nil -} - // Filesystem access policy. type FilesystemPolicy struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -628,72 +556,6 @@ func (x *ProcessPolicy) GetRunAsGroup() string { return "" } -// Platform-neutral user-interface capabilities. Every omitted field in an -// explicit policy defaults to deny. Compute platforms without complete support -// reject the entire explicit policy before provisioning. -type UiPolicy struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Allow the sandbox to display graphical windows. - AllowGraphicalUi bool `protobuf:"varint,1,opt,name=allow_graphical_ui,json=allowGraphicalUi,proto3" json:"allow_graphical_ui,omitempty"` - // Directional host clipboard access. - Clipboard UiClipboardAccess `protobuf:"varint,2,opt,name=clipboard,proto3,enum=openshell.sandbox.v1.UiClipboardAccess" json:"clipboard,omitempty"` - // Allow the sandbox to synthesize keyboard or pointer input. - AllowInputInjection bool `protobuf:"varint,3,opt,name=allow_input_injection,json=allowInputInjection,proto3" json:"allow_input_injection,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UiPolicy) Reset() { - *x = UiPolicy{} - mi := &file_sandbox_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UiPolicy) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UiPolicy) ProtoMessage() {} - -func (x *UiPolicy) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[4] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UiPolicy.ProtoReflect.Descriptor instead. -func (*UiPolicy) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{4} -} - -func (x *UiPolicy) GetAllowGraphicalUi() bool { - if x != nil { - return x.AllowGraphicalUi - } - return false -} - -func (x *UiPolicy) GetClipboard() UiClipboardAccess { - if x != nil { - return x.Clipboard - } - return UiClipboardAccess_UI_CLIPBOARD_ACCESS_UNSPECIFIED -} - -func (x *UiPolicy) GetAllowInputInjection() bool { - if x != nil { - return x.AllowInputInjection - } - return false -} - // A named network access policy rule. type NetworkPolicyRule struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -709,7 +571,7 @@ type NetworkPolicyRule struct { func (x *NetworkPolicyRule) Reset() { *x = NetworkPolicyRule{} - mi := &file_sandbox_proto_msgTypes[5] + mi := &file_sandbox_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -721,7 +583,7 @@ func (x *NetworkPolicyRule) String() string { func (*NetworkPolicyRule) ProtoMessage() {} func (x *NetworkPolicyRule) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[5] + mi := &file_sandbox_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -734,7 +596,7 @@ func (x *NetworkPolicyRule) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkPolicyRule.ProtoReflect.Descriptor instead. func (*NetworkPolicyRule) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{5} + return file_sandbox_proto_rawDescGZIP(), []int{4} } func (x *NetworkPolicyRule) GetName() string { @@ -779,7 +641,7 @@ type NetworkMiddlewareConfig struct { func (x *NetworkMiddlewareConfig) Reset() { *x = NetworkMiddlewareConfig{} - mi := &file_sandbox_proto_msgTypes[6] + mi := &file_sandbox_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -791,7 +653,7 @@ func (x *NetworkMiddlewareConfig) String() string { func (*NetworkMiddlewareConfig) ProtoMessage() {} func (x *NetworkMiddlewareConfig) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[6] + mi := &file_sandbox_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -804,7 +666,7 @@ func (x *NetworkMiddlewareConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkMiddlewareConfig.ProtoReflect.Descriptor instead. func (*NetworkMiddlewareConfig) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{6} + return file_sandbox_proto_rawDescGZIP(), []int{5} } func (x *NetworkMiddlewareConfig) GetName() string { @@ -864,7 +726,7 @@ type MiddlewareEndpointSelector struct { func (x *MiddlewareEndpointSelector) Reset() { *x = MiddlewareEndpointSelector{} - mi := &file_sandbox_proto_msgTypes[7] + mi := &file_sandbox_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -876,7 +738,7 @@ func (x *MiddlewareEndpointSelector) String() string { func (*MiddlewareEndpointSelector) ProtoMessage() {} func (x *MiddlewareEndpointSelector) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[7] + mi := &file_sandbox_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -889,7 +751,7 @@ func (x *MiddlewareEndpointSelector) ProtoReflect() protoreflect.Message { // Deprecated: Use MiddlewareEndpointSelector.ProtoReflect.Descriptor instead. func (*MiddlewareEndpointSelector) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{7} + return file_sandbox_proto_rawDescGZIP(), []int{6} } func (x *MiddlewareEndpointSelector) GetInclude() []string { @@ -918,7 +780,7 @@ type NetworkCredentialBinding struct { func (x *NetworkCredentialBinding) Reset() { *x = NetworkCredentialBinding{} - mi := &file_sandbox_proto_msgTypes[8] + mi := &file_sandbox_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -930,7 +792,7 @@ func (x *NetworkCredentialBinding) String() string { func (*NetworkCredentialBinding) ProtoMessage() {} func (x *NetworkCredentialBinding) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[8] + mi := &file_sandbox_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -943,7 +805,7 @@ func (x *NetworkCredentialBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkCredentialBinding.ProtoReflect.Descriptor instead. func (*NetworkCredentialBinding) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{8} + return file_sandbox_proto_rawDescGZIP(), []int{7} } func (x *NetworkCredentialBinding) GetProvider() string { @@ -979,6 +841,7 @@ type NetworkEndpoint struct { // When non-empty, the SSRF internal-IP check is replaced by an allowlist check: // - If host is also set: domain must resolve to an IP in this list. // - If host is empty: any domain is allowed as long as it resolves to an IP in this list. + // // Supports exact IPs ("10.0.5.20") and CIDR notation ("10.0.5.0/24"). // Loopback (127.0.0.0/8) and link-local (169.254.0.0/16) are always blocked // regardless of this field. @@ -1058,7 +921,7 @@ type NetworkEndpoint struct { func (x *NetworkEndpoint) Reset() { *x = NetworkEndpoint{} - mi := &file_sandbox_proto_msgTypes[9] + mi := &file_sandbox_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1070,7 +933,7 @@ func (x *NetworkEndpoint) String() string { func (*NetworkEndpoint) ProtoMessage() {} func (x *NetworkEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[9] + mi := &file_sandbox_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1083,7 +946,7 @@ func (x *NetworkEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkEndpoint.ProtoReflect.Descriptor instead. func (*NetworkEndpoint) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{9} + return file_sandbox_proto_rawDescGZIP(), []int{8} } func (x *NetworkEndpoint) GetHost() string { @@ -1316,7 +1179,7 @@ type McpOptions struct { func (x *McpOptions) Reset() { *x = McpOptions{} - mi := &file_sandbox_proto_msgTypes[10] + mi := &file_sandbox_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1328,7 +1191,7 @@ func (x *McpOptions) String() string { func (*McpOptions) ProtoMessage() {} func (x *McpOptions) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[10] + mi := &file_sandbox_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1341,7 +1204,7 @@ func (x *McpOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use McpOptions.ProtoReflect.Descriptor instead. func (*McpOptions) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{10} + return file_sandbox_proto_rawDescGZIP(), []int{9} } func (x *McpOptions) GetStrictToolNames() bool { @@ -1380,7 +1243,7 @@ type GraphqlOperation struct { func (x *GraphqlOperation) Reset() { *x = GraphqlOperation{} - mi := &file_sandbox_proto_msgTypes[11] + mi := &file_sandbox_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1392,7 +1255,7 @@ func (x *GraphqlOperation) String() string { func (*GraphqlOperation) ProtoMessage() {} func (x *GraphqlOperation) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[11] + mi := &file_sandbox_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1405,7 +1268,7 @@ func (x *GraphqlOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use GraphqlOperation.ProtoReflect.Descriptor instead. func (*GraphqlOperation) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{11} + return file_sandbox_proto_rawDescGZIP(), []int{10} } func (x *GraphqlOperation) GetOperationType() string { @@ -1460,7 +1323,7 @@ type L7DenyRule struct { func (x *L7DenyRule) Reset() { *x = L7DenyRule{} - mi := &file_sandbox_proto_msgTypes[12] + mi := &file_sandbox_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1472,7 +1335,7 @@ func (x *L7DenyRule) String() string { func (*L7DenyRule) ProtoMessage() {} func (x *L7DenyRule) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[12] + mi := &file_sandbox_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1485,7 +1348,7 @@ func (x *L7DenyRule) ProtoReflect() protoreflect.Message { // Deprecated: Use L7DenyRule.ProtoReflect.Descriptor instead. func (*L7DenyRule) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{12} + return file_sandbox_proto_rawDescGZIP(), []int{11} } func (x *L7DenyRule) GetMethod() string { @@ -1554,7 +1417,7 @@ type L7Rule struct { func (x *L7Rule) Reset() { *x = L7Rule{} - mi := &file_sandbox_proto_msgTypes[13] + mi := &file_sandbox_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1566,7 +1429,7 @@ func (x *L7Rule) String() string { func (*L7Rule) ProtoMessage() {} func (x *L7Rule) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[13] + mi := &file_sandbox_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1579,7 +1442,7 @@ func (x *L7Rule) ProtoReflect() protoreflect.Message { // Deprecated: Use L7Rule.ProtoReflect.Descriptor instead. func (*L7Rule) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{13} + return file_sandbox_proto_rawDescGZIP(), []int{12} } func (x *L7Rule) GetAllow() *L7Allow { @@ -1619,7 +1482,7 @@ type L7Allow struct { func (x *L7Allow) Reset() { *x = L7Allow{} - mi := &file_sandbox_proto_msgTypes[14] + mi := &file_sandbox_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1631,7 +1494,7 @@ func (x *L7Allow) String() string { func (*L7Allow) ProtoMessage() {} func (x *L7Allow) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[14] + mi := &file_sandbox_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1644,7 +1507,7 @@ func (x *L7Allow) ProtoReflect() protoreflect.Message { // Deprecated: Use L7Allow.ProtoReflect.Descriptor instead. func (*L7Allow) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{14} + return file_sandbox_proto_rawDescGZIP(), []int{13} } func (x *L7Allow) GetMethod() string { @@ -1716,7 +1579,7 @@ type L7QueryMatcher struct { func (x *L7QueryMatcher) Reset() { *x = L7QueryMatcher{} - mi := &file_sandbox_proto_msgTypes[15] + mi := &file_sandbox_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1728,7 +1591,7 @@ func (x *L7QueryMatcher) String() string { func (*L7QueryMatcher) ProtoMessage() {} func (x *L7QueryMatcher) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[15] + mi := &file_sandbox_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1741,7 +1604,7 @@ func (x *L7QueryMatcher) ProtoReflect() protoreflect.Message { // Deprecated: Use L7QueryMatcher.ProtoReflect.Descriptor instead. func (*L7QueryMatcher) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{15} + return file_sandbox_proto_rawDescGZIP(), []int{14} } func (x *L7QueryMatcher) GetGlob() string { @@ -1768,7 +1631,7 @@ type NetworkBinary struct { func (x *NetworkBinary) Reset() { *x = NetworkBinary{} - mi := &file_sandbox_proto_msgTypes[16] + mi := &file_sandbox_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1780,7 +1643,7 @@ func (x *NetworkBinary) String() string { func (*NetworkBinary) ProtoMessage() {} func (x *NetworkBinary) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[16] + mi := &file_sandbox_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1793,7 +1656,7 @@ func (x *NetworkBinary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkBinary.ProtoReflect.Descriptor instead. func (*NetworkBinary) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{16} + return file_sandbox_proto_rawDescGZIP(), []int{15} } func (x *NetworkBinary) GetPath() string { @@ -1815,7 +1678,7 @@ type GetSandboxConfigRequest struct { func (x *GetSandboxConfigRequest) Reset() { *x = GetSandboxConfigRequest{} - mi := &file_sandbox_proto_msgTypes[17] + mi := &file_sandbox_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1827,7 +1690,7 @@ func (x *GetSandboxConfigRequest) String() string { func (*GetSandboxConfigRequest) ProtoMessage() {} func (x *GetSandboxConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[17] + mi := &file_sandbox_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1840,7 +1703,7 @@ func (x *GetSandboxConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxConfigRequest.ProtoReflect.Descriptor instead. func (*GetSandboxConfigRequest) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{17} + return file_sandbox_proto_rawDescGZIP(), []int{16} } func (x *GetSandboxConfigRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -1866,7 +1729,7 @@ type GetGatewayConfigRequest struct { func (x *GetGatewayConfigRequest) Reset() { *x = GetGatewayConfigRequest{} - mi := &file_sandbox_proto_msgTypes[18] + mi := &file_sandbox_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1878,7 +1741,7 @@ func (x *GetGatewayConfigRequest) String() string { func (*GetGatewayConfigRequest) ProtoMessage() {} func (x *GetGatewayConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[18] + mi := &file_sandbox_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1891,7 +1754,7 @@ func (x *GetGatewayConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGatewayConfigRequest.ProtoReflect.Descriptor instead. func (*GetGatewayConfigRequest) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{18} + return file_sandbox_proto_rawDescGZIP(), []int{17} } // Response containing gateway-global settings. @@ -1908,7 +1771,7 @@ type GetGatewayConfigResponse struct { func (x *GetGatewayConfigResponse) Reset() { *x = GetGatewayConfigResponse{} - mi := &file_sandbox_proto_msgTypes[19] + mi := &file_sandbox_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1920,7 +1783,7 @@ func (x *GetGatewayConfigResponse) String() string { func (*GetGatewayConfigResponse) ProtoMessage() {} func (x *GetGatewayConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[19] + mi := &file_sandbox_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1933,7 +1796,7 @@ func (x *GetGatewayConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGatewayConfigResponse.ProtoReflect.Descriptor instead. func (*GetGatewayConfigResponse) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{19} + return file_sandbox_proto_rawDescGZIP(), []int{18} } func (x *GetGatewayConfigResponse) GetSettings() map[string]*SettingValue { @@ -1966,7 +1829,7 @@ type SettingValue struct { func (x *SettingValue) Reset() { *x = SettingValue{} - mi := &file_sandbox_proto_msgTypes[20] + mi := &file_sandbox_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1978,7 +1841,7 @@ func (x *SettingValue) String() string { func (*SettingValue) ProtoMessage() {} func (x *SettingValue) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[20] + mi := &file_sandbox_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1991,7 +1854,7 @@ func (x *SettingValue) ProtoReflect() protoreflect.Message { // Deprecated: Use SettingValue.ProtoReflect.Descriptor instead. func (*SettingValue) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{20} + return file_sandbox_proto_rawDescGZIP(), []int{19} } func (x *SettingValue) GetValue() isSettingValue_Value { @@ -2076,7 +1939,7 @@ type EffectiveSetting struct { func (x *EffectiveSetting) Reset() { *x = EffectiveSetting{} - mi := &file_sandbox_proto_msgTypes[21] + mi := &file_sandbox_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2088,7 +1951,7 @@ func (x *EffectiveSetting) String() string { func (*EffectiveSetting) ProtoMessage() {} func (x *EffectiveSetting) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[21] + mi := &file_sandbox_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2101,7 +1964,7 @@ func (x *EffectiveSetting) ProtoReflect() protoreflect.Message { // Deprecated: Use EffectiveSetting.ProtoReflect.Descriptor instead. func (*EffectiveSetting) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{21} + return file_sandbox_proto_rawDescGZIP(), []int{20} } func (x *EffectiveSetting) GetValue() *SettingValue { @@ -2170,7 +2033,7 @@ type GetSandboxConfigResponse struct { func (x *GetSandboxConfigResponse) Reset() { *x = GetSandboxConfigResponse{} - mi := &file_sandbox_proto_msgTypes[22] + mi := &file_sandbox_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2182,7 +2045,7 @@ func (x *GetSandboxConfigResponse) String() string { func (*GetSandboxConfigResponse) ProtoMessage() {} func (x *GetSandboxConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[22] + mi := &file_sandbox_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2195,7 +2058,7 @@ func (x *GetSandboxConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxConfigResponse.ProtoReflect.Descriptor instead. func (*GetSandboxConfigResponse) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{22} + return file_sandbox_proto_rawDescGZIP(), []int{21} } func (x *GetSandboxConfigResponse) GetPolicy() *SandboxPolicy { @@ -2342,7 +2205,7 @@ type SupervisorMiddlewareService struct { func (x *SupervisorMiddlewareService) Reset() { *x = SupervisorMiddlewareService{} - mi := &file_sandbox_proto_msgTypes[23] + mi := &file_sandbox_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2354,7 +2217,7 @@ func (x *SupervisorMiddlewareService) String() string { func (*SupervisorMiddlewareService) ProtoMessage() {} func (x *SupervisorMiddlewareService) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[23] + mi := &file_sandbox_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2367,7 +2230,7 @@ func (x *SupervisorMiddlewareService) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMiddlewareService.ProtoReflect.Descriptor instead. func (*SupervisorMiddlewareService) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{23} + return file_sandbox_proto_rawDescGZIP(), []int{22} } func (x *SupervisorMiddlewareService) GetName() string { @@ -2423,7 +2286,7 @@ var File_sandbox_proto protoreflect.FileDescriptor const file_sandbox_proto_rawDesc = "" + "\n" + - "\rsandbox.proto\x12\x14openshell.sandbox.v1\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x0fdatamodel.proto\"\xd8\x05\n" + + "\rsandbox.proto\x12\x14openshell.sandbox.v1\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x0fdatamodel.proto\"\xa8\x05\n" + "\rSandboxPolicy\x12\x18\n" + "\aversion\x18\x01 \x01(\rR\aversion\x12F\n" + "\n" + @@ -2432,8 +2295,7 @@ const file_sandbox_proto_rawDesc = "" + "\blandlock\x18\x03 \x01(\v2$.openshell.sandbox.v1.LandlockPolicyR\blandlock\x12=\n" + "\aprocess\x18\x04 \x01(\v2#.openshell.sandbox.v1.ProcessPolicyR\aprocess\x12c\n" + "\x10network_policies\x18\x05 \x03(\v28.openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntryR\x0fnetworkPolicies\x12l\n" + - "\x13network_middlewares\x18\x06 \x03(\v2;.openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntryR\x12networkMiddlewares\x12.\n" + - "\x02ui\x18\a \x01(\v2\x1e.openshell.sandbox.v1.UiPolicyR\x02ui\x1ak\n" + + "\x13network_middlewares\x18\x06 \x03(\v2;.openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntryR\x12networkMiddlewares\x1ak\n" + "\x14NetworkPoliciesEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12=\n" + "\x05value\x18\x02 \x01(\v2'.openshell.sandbox.v1.NetworkPolicyRuleR\x05value:\x028\x01\x1at\n" + @@ -2450,11 +2312,7 @@ const file_sandbox_proto_rawDesc = "" + "\rProcessPolicy\x12\x1e\n" + "\vrun_as_user\x18\x01 \x01(\tR\trunAsUser\x12 \n" + "\frun_as_group\x18\x02 \x01(\tR\n" + - "runAsGroup\"\xb3\x01\n" + - "\bUiPolicy\x12,\n" + - "\x12allow_graphical_ui\x18\x01 \x01(\bR\x10allowGraphicalUi\x12E\n" + - "\tclipboard\x18\x02 \x01(\x0e2'.openshell.sandbox.v1.UiClipboardAccessR\tclipboard\x122\n" + - "\x15allow_input_injection\x18\x03 \x01(\bR\x13allowInputInjection\"\xad\x01\n" + + "runAsGroup\"\xad\x01\n" + "\x11NetworkPolicyRule\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12C\n" + "\tendpoints\x18\x02 \x03(\v2%.openshell.sandbox.v1.NetworkEndpointR\tendpoints\x12?\n" + @@ -2608,13 +2466,7 @@ const file_sandbox_proto_rawDesc = "" + "\x0frequest_timeout\x18h \x01(\v2\x19.google.protobuf.DurationR\x0erequestTimeout\x12%\n" + "\x0ftls_ca_cert_pem\x18\x05 \x01(\fR\ftlsCaCertPem\x12\x1a\n" + "\baudience\x18\x06 \x01(\tR\baudience\x128\n" + - "\x18allow_insecure_transport\x18\a \x01(\bR\x16allowInsecureTransportJ\x04\b\x04\x10\x05R\atimeout*\xb0\x01\n" + - "\x11UiClipboardAccess\x12#\n" + - "\x1fUI_CLIPBOARD_ACCESS_UNSPECIFIED\x10\x00\x12\x1c\n" + - "\x18UI_CLIPBOARD_ACCESS_NONE\x10\x01\x12\x1c\n" + - "\x18UI_CLIPBOARD_ACCESS_READ\x10\x02\x12\x1d\n" + - "\x19UI_CLIPBOARD_ACCESS_WRITE\x10\x03\x12\x1b\n" + - "\x17UI_CLIPBOARD_ACCESS_ALL\x10\x04*\x97\x01\n" + + "\x18allow_insecure_transport\x18\a \x01(\bR\x16allowInsecureTransportJ\x04\b\x04\x10\x05R\atimeout*\x97\x01\n" + "\x0eNetworkTlsMode\x12 \n" + "\x1cNETWORK_TLS_MODE_UNSPECIFIED\x10\x00\x12\x19\n" + "\x15NETWORK_TLS_MODE_SKIP\x10\x01\x12\"\n" + @@ -2650,100 +2502,96 @@ func file_sandbox_proto_rawDescGZIP() []byte { return file_sandbox_proto_rawDescData } -var file_sandbox_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 33) +var file_sandbox_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 32) var file_sandbox_proto_goTypes = []any{ - (UiClipboardAccess)(0), // 0: openshell.sandbox.v1.UiClipboardAccess - (NetworkTlsMode)(0), // 1: openshell.sandbox.v1.NetworkTlsMode - (NetworkEnforcementMode)(0), // 2: openshell.sandbox.v1.NetworkEnforcementMode - (NetworkAccessPreset)(0), // 3: openshell.sandbox.v1.NetworkAccessPreset - (SettingScope)(0), // 4: openshell.sandbox.v1.SettingScope - (PolicySource)(0), // 5: openshell.sandbox.v1.PolicySource - (*SandboxPolicy)(nil), // 6: openshell.sandbox.v1.SandboxPolicy - (*FilesystemPolicy)(nil), // 7: openshell.sandbox.v1.FilesystemPolicy - (*LandlockPolicy)(nil), // 8: openshell.sandbox.v1.LandlockPolicy - (*ProcessPolicy)(nil), // 9: openshell.sandbox.v1.ProcessPolicy - (*UiPolicy)(nil), // 10: openshell.sandbox.v1.UiPolicy - (*NetworkPolicyRule)(nil), // 11: openshell.sandbox.v1.NetworkPolicyRule - (*NetworkMiddlewareConfig)(nil), // 12: openshell.sandbox.v1.NetworkMiddlewareConfig - (*MiddlewareEndpointSelector)(nil), // 13: openshell.sandbox.v1.MiddlewareEndpointSelector - (*NetworkCredentialBinding)(nil), // 14: openshell.sandbox.v1.NetworkCredentialBinding - (*NetworkEndpoint)(nil), // 15: openshell.sandbox.v1.NetworkEndpoint - (*McpOptions)(nil), // 16: openshell.sandbox.v1.McpOptions - (*GraphqlOperation)(nil), // 17: openshell.sandbox.v1.GraphqlOperation - (*L7DenyRule)(nil), // 18: openshell.sandbox.v1.L7DenyRule - (*L7Rule)(nil), // 19: openshell.sandbox.v1.L7Rule - (*L7Allow)(nil), // 20: openshell.sandbox.v1.L7Allow - (*L7QueryMatcher)(nil), // 21: openshell.sandbox.v1.L7QueryMatcher - (*NetworkBinary)(nil), // 22: openshell.sandbox.v1.NetworkBinary - (*GetSandboxConfigRequest)(nil), // 23: openshell.sandbox.v1.GetSandboxConfigRequest - (*GetGatewayConfigRequest)(nil), // 24: openshell.sandbox.v1.GetGatewayConfigRequest - (*GetGatewayConfigResponse)(nil), // 25: openshell.sandbox.v1.GetGatewayConfigResponse - (*SettingValue)(nil), // 26: openshell.sandbox.v1.SettingValue - (*EffectiveSetting)(nil), // 27: openshell.sandbox.v1.EffectiveSetting - (*GetSandboxConfigResponse)(nil), // 28: openshell.sandbox.v1.GetSandboxConfigResponse - (*SupervisorMiddlewareService)(nil), // 29: openshell.sandbox.v1.SupervisorMiddlewareService - nil, // 30: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry - nil, // 31: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry - nil, // 32: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry - nil, // 33: openshell.sandbox.v1.L7DenyRule.QueryEntry - nil, // 34: openshell.sandbox.v1.L7DenyRule.ParamsEntry - nil, // 35: openshell.sandbox.v1.L7Allow.QueryEntry - nil, // 36: openshell.sandbox.v1.L7Allow.ParamsEntry - nil, // 37: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry - nil, // 38: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry - (*structpb.Struct)(nil), // 39: google.protobuf.Struct - (*datamodelv1.WorkspaceSelector)(nil), // 40: openshell.datamodel.v1.WorkspaceSelector - (*durationpb.Duration)(nil), // 41: google.protobuf.Duration + (NetworkTlsMode)(0), // 0: openshell.sandbox.v1.NetworkTlsMode + (NetworkEnforcementMode)(0), // 1: openshell.sandbox.v1.NetworkEnforcementMode + (NetworkAccessPreset)(0), // 2: openshell.sandbox.v1.NetworkAccessPreset + (SettingScope)(0), // 3: openshell.sandbox.v1.SettingScope + (PolicySource)(0), // 4: openshell.sandbox.v1.PolicySource + (*SandboxPolicy)(nil), // 5: openshell.sandbox.v1.SandboxPolicy + (*FilesystemPolicy)(nil), // 6: openshell.sandbox.v1.FilesystemPolicy + (*LandlockPolicy)(nil), // 7: openshell.sandbox.v1.LandlockPolicy + (*ProcessPolicy)(nil), // 8: openshell.sandbox.v1.ProcessPolicy + (*NetworkPolicyRule)(nil), // 9: openshell.sandbox.v1.NetworkPolicyRule + (*NetworkMiddlewareConfig)(nil), // 10: openshell.sandbox.v1.NetworkMiddlewareConfig + (*MiddlewareEndpointSelector)(nil), // 11: openshell.sandbox.v1.MiddlewareEndpointSelector + (*NetworkCredentialBinding)(nil), // 12: openshell.sandbox.v1.NetworkCredentialBinding + (*NetworkEndpoint)(nil), // 13: openshell.sandbox.v1.NetworkEndpoint + (*McpOptions)(nil), // 14: openshell.sandbox.v1.McpOptions + (*GraphqlOperation)(nil), // 15: openshell.sandbox.v1.GraphqlOperation + (*L7DenyRule)(nil), // 16: openshell.sandbox.v1.L7DenyRule + (*L7Rule)(nil), // 17: openshell.sandbox.v1.L7Rule + (*L7Allow)(nil), // 18: openshell.sandbox.v1.L7Allow + (*L7QueryMatcher)(nil), // 19: openshell.sandbox.v1.L7QueryMatcher + (*NetworkBinary)(nil), // 20: openshell.sandbox.v1.NetworkBinary + (*GetSandboxConfigRequest)(nil), // 21: openshell.sandbox.v1.GetSandboxConfigRequest + (*GetGatewayConfigRequest)(nil), // 22: openshell.sandbox.v1.GetGatewayConfigRequest + (*GetGatewayConfigResponse)(nil), // 23: openshell.sandbox.v1.GetGatewayConfigResponse + (*SettingValue)(nil), // 24: openshell.sandbox.v1.SettingValue + (*EffectiveSetting)(nil), // 25: openshell.sandbox.v1.EffectiveSetting + (*GetSandboxConfigResponse)(nil), // 26: openshell.sandbox.v1.GetSandboxConfigResponse + (*SupervisorMiddlewareService)(nil), // 27: openshell.sandbox.v1.SupervisorMiddlewareService + nil, // 28: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry + nil, // 29: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry + nil, // 30: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry + nil, // 31: openshell.sandbox.v1.L7DenyRule.QueryEntry + nil, // 32: openshell.sandbox.v1.L7DenyRule.ParamsEntry + nil, // 33: openshell.sandbox.v1.L7Allow.QueryEntry + nil, // 34: openshell.sandbox.v1.L7Allow.ParamsEntry + nil, // 35: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry + nil, // 36: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry + (*structpb.Struct)(nil), // 37: google.protobuf.Struct + (*datamodelv1.WorkspaceSelector)(nil), // 38: openshell.datamodel.v1.WorkspaceSelector + (*durationpb.Duration)(nil), // 39: google.protobuf.Duration } var file_sandbox_proto_depIdxs = []int32{ - 7, // 0: openshell.sandbox.v1.SandboxPolicy.filesystem:type_name -> openshell.sandbox.v1.FilesystemPolicy - 8, // 1: openshell.sandbox.v1.SandboxPolicy.landlock:type_name -> openshell.sandbox.v1.LandlockPolicy - 9, // 2: openshell.sandbox.v1.SandboxPolicy.process:type_name -> openshell.sandbox.v1.ProcessPolicy - 30, // 3: openshell.sandbox.v1.SandboxPolicy.network_policies:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry - 31, // 4: openshell.sandbox.v1.SandboxPolicy.network_middlewares:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry - 10, // 5: openshell.sandbox.v1.SandboxPolicy.ui:type_name -> openshell.sandbox.v1.UiPolicy - 0, // 6: openshell.sandbox.v1.UiPolicy.clipboard:type_name -> openshell.sandbox.v1.UiClipboardAccess - 15, // 7: openshell.sandbox.v1.NetworkPolicyRule.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 22, // 8: openshell.sandbox.v1.NetworkPolicyRule.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 39, // 9: openshell.sandbox.v1.NetworkMiddlewareConfig.config:type_name -> google.protobuf.Struct - 13, // 10: openshell.sandbox.v1.NetworkMiddlewareConfig.endpoints:type_name -> openshell.sandbox.v1.MiddlewareEndpointSelector - 1, // 11: openshell.sandbox.v1.NetworkEndpoint.tls:type_name -> openshell.sandbox.v1.NetworkTlsMode - 2, // 12: openshell.sandbox.v1.NetworkEndpoint.enforcement:type_name -> openshell.sandbox.v1.NetworkEnforcementMode - 3, // 13: openshell.sandbox.v1.NetworkEndpoint.access:type_name -> openshell.sandbox.v1.NetworkAccessPreset - 19, // 14: openshell.sandbox.v1.NetworkEndpoint.rules:type_name -> openshell.sandbox.v1.L7Rule - 18, // 15: openshell.sandbox.v1.NetworkEndpoint.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 32, // 16: openshell.sandbox.v1.NetworkEndpoint.graphql_persisted_queries:type_name -> openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry - 16, // 17: openshell.sandbox.v1.NetworkEndpoint.mcp:type_name -> openshell.sandbox.v1.McpOptions - 14, // 18: openshell.sandbox.v1.NetworkEndpoint.credential_binding:type_name -> openshell.sandbox.v1.NetworkCredentialBinding - 33, // 19: openshell.sandbox.v1.L7DenyRule.query:type_name -> openshell.sandbox.v1.L7DenyRule.QueryEntry - 34, // 20: openshell.sandbox.v1.L7DenyRule.params:type_name -> openshell.sandbox.v1.L7DenyRule.ParamsEntry - 20, // 21: openshell.sandbox.v1.L7Rule.allow:type_name -> openshell.sandbox.v1.L7Allow - 35, // 22: openshell.sandbox.v1.L7Allow.query:type_name -> openshell.sandbox.v1.L7Allow.QueryEntry - 36, // 23: openshell.sandbox.v1.L7Allow.params:type_name -> openshell.sandbox.v1.L7Allow.ParamsEntry - 40, // 24: openshell.sandbox.v1.GetSandboxConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 37, // 25: openshell.sandbox.v1.GetGatewayConfigResponse.settings:type_name -> openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry - 26, // 26: openshell.sandbox.v1.EffectiveSetting.value:type_name -> openshell.sandbox.v1.SettingValue - 4, // 27: openshell.sandbox.v1.EffectiveSetting.scope:type_name -> openshell.sandbox.v1.SettingScope - 6, // 28: openshell.sandbox.v1.GetSandboxConfigResponse.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 38, // 29: openshell.sandbox.v1.GetSandboxConfigResponse.settings:type_name -> openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry - 5, // 30: openshell.sandbox.v1.GetSandboxConfigResponse.policy_source:type_name -> openshell.sandbox.v1.PolicySource - 29, // 31: openshell.sandbox.v1.GetSandboxConfigResponse.supervisor_middleware_services:type_name -> openshell.sandbox.v1.SupervisorMiddlewareService - 41, // 32: openshell.sandbox.v1.SupervisorMiddlewareService.request_timeout:type_name -> google.protobuf.Duration - 11, // 33: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry.value:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 12, // 34: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry.value:type_name -> openshell.sandbox.v1.NetworkMiddlewareConfig - 17, // 35: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry.value:type_name -> openshell.sandbox.v1.GraphqlOperation - 21, // 36: openshell.sandbox.v1.L7DenyRule.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 21, // 37: openshell.sandbox.v1.L7DenyRule.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 21, // 38: openshell.sandbox.v1.L7Allow.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 21, // 39: openshell.sandbox.v1.L7Allow.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 26, // 40: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.SettingValue - 27, // 41: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.EffectiveSetting - 42, // [42:42] is the sub-list for method output_type - 42, // [42:42] is the sub-list for method input_type - 42, // [42:42] is the sub-list for extension type_name - 42, // [42:42] is the sub-list for extension extendee - 0, // [0:42] is the sub-list for field type_name + 6, // 0: openshell.sandbox.v1.SandboxPolicy.filesystem:type_name -> openshell.sandbox.v1.FilesystemPolicy + 7, // 1: openshell.sandbox.v1.SandboxPolicy.landlock:type_name -> openshell.sandbox.v1.LandlockPolicy + 8, // 2: openshell.sandbox.v1.SandboxPolicy.process:type_name -> openshell.sandbox.v1.ProcessPolicy + 28, // 3: openshell.sandbox.v1.SandboxPolicy.network_policies:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry + 29, // 4: openshell.sandbox.v1.SandboxPolicy.network_middlewares:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry + 13, // 5: openshell.sandbox.v1.NetworkPolicyRule.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 20, // 6: openshell.sandbox.v1.NetworkPolicyRule.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 37, // 7: openshell.sandbox.v1.NetworkMiddlewareConfig.config:type_name -> google.protobuf.Struct + 11, // 8: openshell.sandbox.v1.NetworkMiddlewareConfig.endpoints:type_name -> openshell.sandbox.v1.MiddlewareEndpointSelector + 0, // 9: openshell.sandbox.v1.NetworkEndpoint.tls:type_name -> openshell.sandbox.v1.NetworkTlsMode + 1, // 10: openshell.sandbox.v1.NetworkEndpoint.enforcement:type_name -> openshell.sandbox.v1.NetworkEnforcementMode + 2, // 11: openshell.sandbox.v1.NetworkEndpoint.access:type_name -> openshell.sandbox.v1.NetworkAccessPreset + 17, // 12: openshell.sandbox.v1.NetworkEndpoint.rules:type_name -> openshell.sandbox.v1.L7Rule + 16, // 13: openshell.sandbox.v1.NetworkEndpoint.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 30, // 14: openshell.sandbox.v1.NetworkEndpoint.graphql_persisted_queries:type_name -> openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry + 14, // 15: openshell.sandbox.v1.NetworkEndpoint.mcp:type_name -> openshell.sandbox.v1.McpOptions + 12, // 16: openshell.sandbox.v1.NetworkEndpoint.credential_binding:type_name -> openshell.sandbox.v1.NetworkCredentialBinding + 31, // 17: openshell.sandbox.v1.L7DenyRule.query:type_name -> openshell.sandbox.v1.L7DenyRule.QueryEntry + 32, // 18: openshell.sandbox.v1.L7DenyRule.params:type_name -> openshell.sandbox.v1.L7DenyRule.ParamsEntry + 18, // 19: openshell.sandbox.v1.L7Rule.allow:type_name -> openshell.sandbox.v1.L7Allow + 33, // 20: openshell.sandbox.v1.L7Allow.query:type_name -> openshell.sandbox.v1.L7Allow.QueryEntry + 34, // 21: openshell.sandbox.v1.L7Allow.params:type_name -> openshell.sandbox.v1.L7Allow.ParamsEntry + 38, // 22: openshell.sandbox.v1.GetSandboxConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 35, // 23: openshell.sandbox.v1.GetGatewayConfigResponse.settings:type_name -> openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry + 24, // 24: openshell.sandbox.v1.EffectiveSetting.value:type_name -> openshell.sandbox.v1.SettingValue + 3, // 25: openshell.sandbox.v1.EffectiveSetting.scope:type_name -> openshell.sandbox.v1.SettingScope + 5, // 26: openshell.sandbox.v1.GetSandboxConfigResponse.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 36, // 27: openshell.sandbox.v1.GetSandboxConfigResponse.settings:type_name -> openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry + 4, // 28: openshell.sandbox.v1.GetSandboxConfigResponse.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 27, // 29: openshell.sandbox.v1.GetSandboxConfigResponse.supervisor_middleware_services:type_name -> openshell.sandbox.v1.SupervisorMiddlewareService + 39, // 30: openshell.sandbox.v1.SupervisorMiddlewareService.request_timeout:type_name -> google.protobuf.Duration + 9, // 31: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry.value:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 10, // 32: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry.value:type_name -> openshell.sandbox.v1.NetworkMiddlewareConfig + 15, // 33: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry.value:type_name -> openshell.sandbox.v1.GraphqlOperation + 19, // 34: openshell.sandbox.v1.L7DenyRule.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 19, // 35: openshell.sandbox.v1.L7DenyRule.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 19, // 36: openshell.sandbox.v1.L7Allow.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 19, // 37: openshell.sandbox.v1.L7Allow.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 24, // 38: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.SettingValue + 25, // 39: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.EffectiveSetting + 40, // [40:40] is the sub-list for method output_type + 40, // [40:40] is the sub-list for method input_type + 40, // [40:40] is the sub-list for extension type_name + 40, // [40:40] is the sub-list for extension extendee + 0, // [0:40] is the sub-list for field type_name } func init() { file_sandbox_proto_init() } @@ -2751,8 +2599,8 @@ func file_sandbox_proto_init() { if File_sandbox_proto != nil { return } - file_sandbox_proto_msgTypes[10].OneofWrappers = []any{} - file_sandbox_proto_msgTypes[20].OneofWrappers = []any{ + file_sandbox_proto_msgTypes[9].OneofWrappers = []any{} + file_sandbox_proto_msgTypes[19].OneofWrappers = []any{ (*SettingValue_StringValue)(nil), (*SettingValue_BoolValue)(nil), (*SettingValue_IntValue)(nil), @@ -2763,8 +2611,8 @@ func file_sandbox_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_sandbox_proto_rawDesc), len(file_sandbox_proto_rawDesc)), - NumEnums: 6, - NumMessages: 33, + NumEnums: 5, + NumMessages: 32, NumExtensions: 0, NumServices: 0, }, diff --git a/skills/generate-sandbox-policy/SKILL.md b/skills/generate-sandbox-policy/SKILL.md index b2390654a..db349e006 100644 --- a/skills/generate-sandbox-policy/SKILL.md +++ b/skills/generate-sandbox-policy/SKILL.md @@ -11,7 +11,7 @@ Generate YAML sandbox network policies and network middleware configuration from This skill translates a user's plain-language policy intent into a valid sandbox policy. The amount of detail the user provides determines the granularity of the generated policy — from broad L4 or preset-based policies (just a host:port) up to fine-grained per-endpoint L7 rules (full API docs). -The output is a `network_policies` YAML block, an optional `network_middlewares` block, an optional static `ui` block when explicitly requested, and optionally a full policy file that conforms to the sandbox policy schema. +The output is a `network_policies` YAML block, an optional `network_middlewares` block, and optionally a full policy file that conforms to the sandbox policy schema. ## Step 1: Gather Inputs @@ -177,7 +177,6 @@ Key sections to reference: - **Private IP Access via `allowed_ips`** — CIDR allowlist for private IP space - **Network Middleware** - top-level middleware configs, ordering, host selection, and failure behavior - **Validation Rules** — what combinations are valid/invalid -- **UI** — static, portable capabilities and runtime support boundaries When middleware is requested, also read the published [supervisor middleware guide](https://docs.nvidia.com/openshell/latest/extensibility/supervisor-middleware.md). @@ -274,27 +273,6 @@ Use the most specific pattern that covers the intent. Prefer narrow globs over ` ## Step 5: Generate the Policy -### UI Policy - -Emit `ui` only when the user explicitly requests a graphical surface, -clipboard access, or synthetic input. Choose the narrowest capability and keep -unrequested fields omitted so they remain deny by default: - -```yaml -ui: - allow_graphical_ui: true - clipboard: read # none | read | write | all - allow_input_injection: false -``` - -Treat clipboard direction from the sandbox's perspective. Warn that UI is a -static sandbox-creation control. It requires the selected compute driver to -advertise `openshell.policy.ui.v1` through existing extension metadata. A driver -without that capability rejects any explicit UI section, including `{}`, before -provisioning. Omit the -section rather than emitting deny-only UI for those drivers; omission preserves -their existing behavior. - ### Output Format Generate a complete `network_policies` entry. Use this template: @@ -426,7 +404,6 @@ Before presenting the policy to the user, verify correctness **and** flag breadt - [ ] Any required WebSocket control advertises `WEBSOCKET_MESSAGE/PRE_CREDENTIALS`, and the user understands that V1 does not inspect binary messages - [ ] Any required response control advertises `HTTP_RESPONSE/PRE_RETURN` - [ ] Endpoints contributed by a credentialed provider are not L4-only or `tls: skip` unless `allow_uninspected_credentials: true` explicitly records the exception -- [ ] An explicit `ui` section targets a configured driver/backend that advertises complete UI-policy support ### Schema Warnings (log-only, but should be fixed) @@ -489,7 +466,7 @@ The policy needs to go somewhere. Determine which mode applies: 1. **Read the existing file** to understand current state: - What policies already exist under `network_policies` - - What the `filesystem_policy`, `landlock`, `process`, and `ui` sections look like + - What the `filesystem_policy`, `landlock`, and `process` sections look like - Whether the file uses compact (`{ host: ..., port: ... }`) or expanded YAML style 2. **Check for conflicts**: @@ -508,7 +485,7 @@ The policy needs to go somewhere. Determine which mode applies: - **Modifying an existing policy**: Edit the specific policy in place — add/remove endpoints, change access presets, update rules, add binaries, etc. A rule authorizes every binary it lists to reach every endpoint and port it lists, so adding one binary grants it all of that rule's endpoints, and adding one endpoint grants it to all of that rule's binaries. State the resulting pairs to the user before writing them. When the user wants a binary to reach only part of a rule's endpoints, put that binary and those endpoints in a separate rule instead of extending the existing one. An empty `binaries` list means any binary, so leaving it off widens the rule to every process. - **Removing a policy**: Delete the policy block if the user asks. -4. **Preserve everything else**: Do not modify `filesystem_policy`, `landlock`, `process`, `ui`, or other policies unless the user explicitly asks. +4. **Preserve everything else**: Do not modify `filesystem_policy`, `landlock`, `process`, or other policies unless the user explicitly asks. ### Mode B: Create a New Policy File diff --git a/skills/generate-sandbox-policy/examples.md b/skills/generate-sandbox-policy/examples.md index 96a703afe..17b7ca464 100644 --- a/skills/generate-sandbox-policy/examples.md +++ b/skills/generate-sandbox-policy/examples.md @@ -747,7 +747,7 @@ An exact IP is treated as `/32` — only that specific address is permitted. - { path: /usr/bin/curl } ``` -The agent inserts the new entry after the last existing policy in the `network_policies` block. All other sections (`filesystem_policy`, `landlock`, `process`, `ui`) are untouched. +The agent inserts the new entry after the last existing policy in the `network_policies` block. All other sections (`filesystem_policy`, `landlock`, `process`) are untouched. --- diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index ed7a6b557..ce8dcca29 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -506,13 +506,7 @@ for verification behavior and release compatibility. This is the most important multi-step workflow. It enables a tight feedback cycle where sandbox policy is refined based on observed activity. -**Key concept**: Policies have static fields (immutable after activation: `filesystem_policy`, `landlock`, `process`, `ui`) and two dynamic fields: `network_policies` and `network_middlewares`. Both dynamic fields can be updated without recreating the sandbox when the selected compute driver supports live policy updates. Drivers without the standard supervisor fetch revisions through the sandbox configuration API and report whether they loaded them. - -Explicit `ui` requires the selected driver to advertise -`openshell.policy.ui.v1` in its existing supported extension capabilities, -visible through `openshell gateway info`. Unsupported drivers reject even -`ui: {}` before provisioning. Omit UI unless requested. UI changes require -sandbox recreation. +**Key concept**: Policies have static fields (immutable after activation: `filesystem_policy`, `landlock`, `process`) and two dynamic fields: `network_policies` and `network_middlewares`. Both dynamic fields can be updated without recreating the sandbox when the selected compute driver supports live policy updates. Drivers without the standard supervisor fetch revisions through the sandbox configuration API and report whether they loaded them. If startup reports `ConfigurationInvalid`, inspect `openshell sandbox get` and repair the complete policy or provider set through the gateway. The workload