refactor(runtime): defer UI policy support to MXC integration

Signed-off-by: Drew Newberry <anewberry@nvidia.com>
This commit is contained in:
Drew Newberry
2026-10-08 23:05:03 -07:00
parent 376652a5eb
commit 2ca39a8010
25 changed files with 197 additions and 1287 deletions
-13
View File
@@ -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
@@ -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();
-27
View File
@@ -113,10 +113,6 @@ impl TryFrom<ProtoSandboxPolicy> for SandboxPolicy {
type Error = miette::Report;
fn try_from(proto: ProtoSandboxPolicy) -> Result<Self, Self::Error> {
// UI capabilities are intentionally absent from the portable supervisor
// runtime. Non-Windows compute paths do not expose them, so even a
// schema-level UI allowance cannot grant a UI surface there. 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<ProtoProcessPolicy> 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());
}
}
@@ -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,
-42
View File
@@ -195,12 +195,6 @@ pub struct PolicyDocument {
skip_serializing_if = "Option::is_none"
)]
pub process: Option<ProcessPolicy>,
#[serde(
default,
deserialize_with = "deserialize_non_null_optional_field",
skip_serializing_if = "Option::is_none"
)]
pub ui: Option<UiPolicy>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub network_policies: BTreeMap<String, NetworkPolicyRule>,
#[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",
+1 -163
View File
@@ -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<JsonRpcConfigDef> {
@@ -628,11 +609,6 @@ fn to_proto(raw: PolicyFile) -> Result<SandboxPolicy> {
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<PolicyFile> {
}
});
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<PolicyFile> {
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(),
};
+7 -14
View File
@@ -83,11 +83,6 @@ impl ContainmentEndpoint for Endpoint {
pub fn parse_policy_str(source: &str) -> Result<ContainmentPolicy, ParsePolicyError> {
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<ContainmentPolicy, ParsePolicyEr
landlock,
process,
network_middlewares,
ui: _,
} = document;
Ok(ContainmentPolicy {
filesystem_policy,
@@ -2256,14 +2250,13 @@ mod tests {
}
#[test]
fn ui_policy_is_not_silently_omitted_from_containment_checks() {
let error = parse_policy_str("version: 1\nui:\n allow_graphical_ui: false\n")
.expect_err("unmodeled UI authority must fail closed");
assert!(
error
.to_string()
.contains("UI policy containment is not supported")
);
fn unknown_policy_controls_are_not_silently_omitted_from_containment_checks() {
for control in ["ui", "unsupported_control"] {
let source = format!("version: 1\n{control}: {{}}\n");
let error =
parse_policy_str(&source).expect_err("unknown policy authority must fail closed");
assert!(error.to_string().contains(control));
}
}
fn options() -> CheckOptions {
+1 -152
View File
@@ -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());
+2 -214
View File
@@ -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};
+2 -41
View File
@@ -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]
+6 -7
View File
@@ -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);
@@ -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
+2 -3
View File
@@ -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).
-28
View File
@@ -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
-30
View File
@@ -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<string, NetworkMiddlewareConfig> 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.
-4
View File
@@ -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 {
-13
View File
@@ -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) {
@@ -171,7 +171,6 @@ func TestConverterCoversAllProtoFields_SandboxPolicy(t *testing.T) {
"network_policies": true,
"process": true,
"landlock": true,
"ui": true,
"network_middlewares": true,
}
@@ -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(),
@@ -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,
+1 -31
View File
@@ -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).
+170 -322
View File
@@ -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,
},
+3 -26
View File
@@ -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
+1 -1
View File
@@ -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.
---
+1 -7
View File
@@ -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