diff --git a/crates/openshell-cli/src/run.rs b/crates/openshell-cli/src/run.rs index eb224685ed..680f877a67 100644 --- a/crates/openshell-cli/src/run.rs +++ b/crates/openshell-cli/src/run.rs @@ -702,6 +702,11 @@ pub async fn sandbox_create( )), await_main_process_attachment, workload_template: template.unwrap_or_default().to_string(), + forward_ports: forward + .as_ref() + .map(|spec| u32::from(spec.port)) + .into_iter() + .collect(), service_exposures: expose .map(|target_port| SandboxServiceExposure { service: String::new(), @@ -1688,6 +1693,33 @@ where println!(" {} {}", "Id:".dimmed(), id); println!(" {} {}", "Name:".dimmed(), name); println!(" {} {}", "Phase:".dimmed(), phase_name(sandbox.phase())); + if let Some(ingress) = sandbox + .status + .as_ref() + .and_then(|status| status.ingress_admission.as_ref()) + { + let ports = if ingress.all_ports { + "all".to_string() + } else { + ingress + .ports + .iter() + .map(u32::to_string) + .collect::>() + .join(", ") + }; + println!( + " {} {}; ports: {ports}", + "Ingress:".dimmed(), + ingress_scope_name(ingress.scope) + ); + } else { + println!( + " {} legacy driver (admission unavailable)", + "Ingress:".dimmed() + ); + } + if let Some(status) = sandbox.status.as_ref() { for condition in &status.conditions { if matches!( @@ -2169,8 +2201,12 @@ pub async fn service_forward_tcp( let (bind_addr, bind_port) = parse_tcp_forward_spec(local, target_port)?; let mut client = grpc_client(server, tls).await?; - let mut replica = fetch_ready_sandbox_for_forward(&mut client, name, workspace).await?; + let (mut replica, scope) = + fetch_ready_sandbox_for_forward(&mut client, name, workspace, target_port).await?; + if scope == openshell_core::proto::IngressScope::SharedHostLoopback { + eprintln!("Target is an admitted shared-host loopback service."); + } let listener = tokio::net::TcpListener::bind((bind_addr.as_str(), bind_port)) .await .into_diagnostic() @@ -2203,7 +2239,7 @@ pub async fn service_forward_tcp( } _ = health_check.tick() => { - replica = fetch_ready_sandbox_for_forward(&mut client, name, workspace).await?; + replica = fetch_ready_sandbox_for_forward(&mut client, name, workspace, target_port).await?.0; } accepted = listener.accept() => { @@ -2274,7 +2310,11 @@ async fn fetch_ready_sandbox_for_forward( client: &mut crate::tls::GrpcClient, name: &str, workspace: &str, -) -> Result> { + target_port: u16, +) -> Result<( + Option, + openshell_core::proto::IngressScope, +)> { let response = match client .get_sandbox(with_owner_hint(GetSandboxRequest { name: name.to_string(), @@ -2307,7 +2347,17 @@ async fn fetch_ready_sandbox_for_forward( )); } - Ok(replica) + let scope = openshell_core::ingress::admit_port( + sandbox + .status + .as_ref() + .and_then(|status| status.ingress_admission.as_ref()), + u32::from(target_port), + false, + ) + .map_err(|error| miette::miette!("{error}"))?; + + Ok((replica, scope)) } #[derive(Debug)] @@ -3012,6 +3062,16 @@ fn configuration_failure_message(sandbox: &Sandbox) -> Option<&str> { .filter(|message| !message.is_empty()) } +fn ingress_scope_name(scope: i32) -> &'static str { + use openshell_core::proto::IngressScope; + match IngressScope::try_from(scope) { + Ok(IngressScope::IsolatedLoopback) => "isolated_loopback", + Ok(IngressScope::SharedHostLoopback) => "shared_host_loopback", + Ok(IngressScope::Unsupported) => "unsupported", + Ok(IngressScope::Unspecified) | Err(_) => "unknown", + } +} + fn sandbox_to_json(sandbox: &Sandbox) -> serde_json::Value { use openshell_core::proto::ConfigurationAdmissionState; @@ -3123,6 +3183,11 @@ fn sandbox_to_json(sandbox: &Sandbox) -> serde_json::Value { "conditions": conditions, "endpoint_statuses": endpoint_statuses, "last_token_grant_failure": last_token_grant_failure, + "ingress_admission": sandbox.status.as_ref().and_then(|status| status.ingress_admission.as_ref()).map(|ingress| serde_json::json!({ + "scope": ingress_scope_name(ingress.scope), + "all_ports": ingress.all_ports, + "ports": ingress.ports, + })), "configuration_admission": admission, "provisioning": provisioning, "created_from_workload_template": created_from_workload_template, @@ -8829,6 +8894,37 @@ mod tests { .error .clear(); assert_eq!(super::configuration_failure_message(&sandbox), None); + assert!(super::sandbox_to_json(&sandbox)["ingress_admission"].is_null()); + for (scope, expected) in [ + ( + openshell_core::proto::IngressScope::IsolatedLoopback as i32, + "isolated_loopback", + ), + ( + openshell_core::proto::IngressScope::SharedHostLoopback as i32, + "shared_host_loopback", + ), + ( + openshell_core::proto::IngressScope::Unsupported as i32, + "unsupported", + ), + (0, "unknown"), + (99, "unknown"), + ] { + sandbox.status.as_mut().unwrap().ingress_admission = + Some(openshell_core::proto::SandboxIngressAdmission { + scope, + ports: vec![8080], + all_ports: false, + }); + let output = super::sandbox_to_json(&sandbox); + assert_eq!(output["ingress_admission"]["scope"], expected); + assert_eq!( + output["ingress_admission"]["ports"], + serde_json::json!([8080]) + ); + assert_eq!(output["ingress_admission"]["all_ports"], false); + } } #[test] diff --git a/crates/openshell-cli/src/ssh.rs b/crates/openshell-cli/src/ssh.rs index d161a4c165..950d223058 100644 --- a/crates/openshell-cli/src/ssh.rs +++ b/crates/openshell-cli/src/ssh.rs @@ -111,6 +111,7 @@ struct SshSessionConfig { gateway_url: String, token: String, main_terminal: bool, + ingress_admission: Option, replica: Option, } @@ -203,6 +204,10 @@ async fn ssh_session_config( ); Ok(SshSessionConfig { + ingress_admission: sandbox + .status + .as_ref() + .and_then(|status| status.ingress_admission.clone()), proxy_command, sandbox_id: session.sandbox_id.clone(), sandbox_name: name.to_string(), @@ -742,9 +747,18 @@ pub async fn sandbox_forward( tls: &TlsOptions, workspace: &str, ) -> Result<()> { - openshell_core::forward::check_port_available(spec)?; - let session = ssh_session_config(server, name, tls, workspace, None).await?; + let scope = openshell_core::ingress::admit_port( + session.ingress_admission.as_ref(), + u32::from(spec.port), + false, + ) + .map_err(|error| miette::miette!("{error}"))?; + if scope == openshell_core::proto::IngressScope::SharedHostLoopback { + eprintln!("Target is an admitted shared-host loopback service."); + } + + openshell_core::forward::check_port_available(spec)?; let mut command = TokioCommand::from(ssh_forward_command( &session.proxy_command, @@ -2548,6 +2562,7 @@ mod tests { async move { if setup { let session = SshSessionConfig { + ingress_admission: None, proxy_command: String::new(), sandbox_id: String::new(), sandbox_name: String::new(), diff --git a/crates/openshell-core/src/extension_protocol.rs b/crates/openshell-core/src/extension_protocol.rs index d6d93418d8..b2515cab18 100644 --- a/crates/openshell-core/src/extension_protocol.rs +++ b/crates/openshell-core/src/extension_protocol.rs @@ -28,6 +28,8 @@ pub const COMPUTE_SUSPEND_RESUME: &str = "openshell.compute.suspend-resume"; /// Optional stopped-state workload configuration updates retaining the resource and storage. pub const COMPUTE_UPDATE_SANDBOX_CONFIGURATION: &str = "openshell.compute.update-sandbox-configuration"; +/// Immutable per-sandbox forwarding and service exposure admission. +pub const COMPUTE_INGRESS_ADMISSION: &str = "openshell.compute.ingress-admission"; const MAX_IMPLEMENTATION_NAME_BYTES: usize = 128; const MAX_IMPLEMENTATION_VERSION_BYTES: usize = 128; @@ -133,6 +135,7 @@ pub fn gateway_metadata(family: ExtensionFamily) -> PeerMetadata { supported_capabilities.push(COMPUTE_LAUNCH_AUTHENTICATION.to_string()); supported_capabilities.push(COMPUTE_ISOLATION_BACKEND.to_string()); supported_capabilities.push(COMPUTE_UPDATE_SANDBOX_CONFIGURATION.to_string()); + supported_capabilities.push(COMPUTE_INGRESS_ADMISSION.to_string()); } PeerMetadata { protocol_version: Some(ProtocolVersion { diff --git a/crates/openshell-core/src/ingress.rs b/crates/openshell-core/src/ingress.rs new file mode 100644 index 0000000000..b22f4e4205 --- /dev/null +++ b/crates/openshell-core/src/ingress.rs @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Shared validation of compute-admitted ingress; the backend enforces targets. + +use crate::proto::{IngressScope, SandboxIngressAdmission}; +use std::collections::BTreeSet; + +/// Validate a negotiated descriptor without treating unknown evidence as legacy. +pub fn validate(admission: &SandboxIngressAdmission) -> Result { + let scope = + IngressScope::try_from(admission.scope).map_err(|_| "unknown compute ingress scope")?; + if scope == IngressScope::Unspecified { + return Err( + "compute ingress admission is unavailable; recreate the sandbox with an ingress-aware driver", + ); + } + if (admission.all_ports && !admission.ports.is_empty()) + || (scope == IngressScope::Unsupported + && (admission.all_ports || !admission.ports.is_empty())) + || admission.ports.len() > 65535 + { + return Err("invalid compute ingress envelope"); + } + let mut seen = BTreeSet::new(); + for port in &admission.ports { + if !(1..=65535).contains(port) || !seen.insert(port) { + return Err("compute ingress ports must be unique and between 1 and 65535"); + } + } + Ok(scope) +} + +/// Authorize before listeners, service persistence, or any pooled upstream use. +/// Legacy absence is permitted only when the gateway has not negotiated ingress. +pub fn admit_port( + admission: Option<&SandboxIngressAdmission>, + port: u32, + required: bool, +) -> Result { + if !(1..=65535).contains(&port) { + return Err("target port must be between 1 and 65535"); + } + let Some(admission) = admission else { + return if required { + Err("compute ingress admission is missing; recreate the sandbox") + } else { + Ok(IngressScope::Unspecified) + }; + }; + let scope = validate(admission)?; + if scope == IngressScope::Unsupported { + return Err("the compute driver does not support sandbox ingress"); + } + if !admission.all_ports && !admission.ports.contains(&port) { + return Err( + "target port was not admitted by the compute driver; recreate the sandbox with that service port", + ); + } + Ok(scope) +} diff --git a/crates/openshell-core/src/lib.rs b/crates/openshell-core/src/lib.rs index 83faf18ef0..53f0edb474 100644 --- a/crates/openshell-core/src/lib.rs +++ b/crates/openshell-core/src/lib.rs @@ -35,6 +35,7 @@ pub mod gpu; pub mod grpc_client; pub mod host_pattern; pub mod image; +pub mod ingress; pub mod isolation_registration; pub mod jwt; pub mod local_api_socket; diff --git a/crates/openshell-driver-docker/src/lib.rs b/crates/openshell-driver-docker/src/lib.rs index 6b761f2f59..a10cc02e4e 100644 --- a/crates/openshell-driver-docker/src/lib.rs +++ b/crates/openshell-driver-docker/src/lib.rs @@ -1094,7 +1094,7 @@ impl DockerComputeDriver { openshell_core::extension_protocol::ExtensionFamily::Compute, "openshell/docker", openshell_core::VERSION, - [], + [openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION.to_string()], )), } } @@ -3354,7 +3354,13 @@ impl ComputeDriver for DockerComputeDriver { CdiGpuDefaultSelector::peek_device_ids, ) .await?; - Ok(Response::new(ValidateSandboxCreateResponse {})) + Ok(Response::new(ValidateSandboxCreateResponse { + ingress_admission: Some(openshell_core::proto::SandboxIngressAdmission { + scope: openshell_core::proto::IngressScope::IsolatedLoopback as i32, + all_ports: true, + ports: Vec::new(), + }), + })) } async fn get_sandbox( diff --git a/crates/openshell-driver-kubernetes/src/driver.rs b/crates/openshell-driver-kubernetes/src/driver.rs index afc06e58c2..c8044ee743 100644 --- a/crates/openshell-driver-kubernetes/src/driver.rs +++ b/crates/openshell-driver-kubernetes/src/driver.rs @@ -1330,6 +1330,7 @@ impl KubernetesComputeDriver { [ openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION .to_string(), + openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION.to_string(), ], )), }) diff --git a/crates/openshell-driver-kubernetes/src/grpc.rs b/crates/openshell-driver-kubernetes/src/grpc.rs index c9adffcbf5..501299c014 100644 --- a/crates/openshell-driver-kubernetes/src/grpc.rs +++ b/crates/openshell-driver-kubernetes/src/grpc.rs @@ -102,7 +102,13 @@ impl ComputeDriver for ComputeDriverService { .sandbox .ok_or_else(|| Status::invalid_argument("sandbox is required"))?; self.driver.validate_sandbox_create(&sandbox).await?; - Ok(Response::new(ValidateSandboxCreateResponse {})) + Ok(Response::new(ValidateSandboxCreateResponse { + ingress_admission: Some(openshell_core::proto::SandboxIngressAdmission { + scope: openshell_core::proto::IngressScope::IsolatedLoopback as i32, + all_ports: true, + ports: Vec::new(), + }), + })) }) .await } diff --git a/crates/openshell-driver-mxc/src/driver.rs b/crates/openshell-driver-mxc/src/driver.rs index 2772f1a69c..e49fdda56f 100644 --- a/crates/openshell-driver-mxc/src/driver.rs +++ b/crates/openshell-driver-mxc/src/driver.rs @@ -480,7 +480,7 @@ impl MxcComputeBackend { openshell_core::extension_protocol::ExtensionFamily::Compute, "openshell/mxc", openshell_core::VERSION, - [], + [openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION.to_string()], )), } } diff --git a/crates/openshell-driver-mxc/src/grpc.rs b/crates/openshell-driver-mxc/src/grpc.rs index ca834987cb..071191de71 100644 --- a/crates/openshell-driver-mxc/src/grpc.rs +++ b/crates/openshell-driver-mxc/src/grpc.rs @@ -70,7 +70,13 @@ impl ComputeDriver for ComputeDriverService { .sandbox .ok_or_else(|| Status::invalid_argument("sandbox is required"))?; self.backend.validate_sandbox_create(&sandbox)?; - Ok(Response::new(ValidateSandboxCreateResponse {})) + Ok(Response::new(ValidateSandboxCreateResponse { + ingress_admission: Some(openshell_core::proto::SandboxIngressAdmission { + scope: openshell_core::proto::IngressScope::Unsupported as i32, + all_ports: false, + ports: Vec::new(), + }), + })) } async fn get_sandbox( diff --git a/crates/openshell-driver-podman/src/driver.rs b/crates/openshell-driver-podman/src/driver.rs index c70cc6eca1..6877f4ac59 100644 --- a/crates/openshell-driver-podman/src/driver.rs +++ b/crates/openshell-driver-podman/src/driver.rs @@ -744,7 +744,7 @@ impl PodmanComputeDriver { openshell_core::extension_protocol::ExtensionFamily::Compute, "openshell/podman", openshell_core::VERSION, - [], + [openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION.to_string()], )), }) } diff --git a/crates/openshell-driver-podman/src/grpc.rs b/crates/openshell-driver-podman/src/grpc.rs index dff752db24..b632649b6e 100644 --- a/crates/openshell-driver-podman/src/grpc.rs +++ b/crates/openshell-driver-podman/src/grpc.rs @@ -100,7 +100,13 @@ impl ComputeDriver for ComputeDriverService { .validate_sandbox_create(&sandbox) .await .map_err(Status::from)?; - Ok(Response::new(ValidateSandboxCreateResponse {})) + Ok(Response::new(ValidateSandboxCreateResponse { + ingress_admission: Some(openshell_core::proto::SandboxIngressAdmission { + scope: openshell_core::proto::IngressScope::IsolatedLoopback as i32, + all_ports: true, + ports: Vec::new(), + }), + })) }) .await } diff --git a/crates/openshell-driver-vm/src/driver.rs b/crates/openshell-driver-vm/src/driver.rs index f7946c34c2..653bc54942 100644 --- a/crates/openshell-driver-vm/src/driver.rs +++ b/crates/openshell-driver-vm/src/driver.rs @@ -1539,7 +1539,7 @@ impl VmDriver { openshell_core::extension_protocol::ExtensionFamily::Compute, "openshell/vm", openshell_core::VERSION, - [], + [openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION.to_string()], ); extension .required_capabilities @@ -5334,7 +5334,13 @@ impl ComputeDriver for VmDriver { .sandbox .ok_or_else(|| Status::invalid_argument("sandbox is required"))?; self.validate_sandbox(&sandbox)?; - Ok(Response::new(ValidateSandboxCreateResponse {})) + Ok(Response::new(ValidateSandboxCreateResponse { + ingress_admission: Some(openshell_core::proto::SandboxIngressAdmission { + scope: openshell_core::proto::IngressScope::IsolatedLoopback as i32, + all_ports: true, + ports: Vec::new(), + }), + })) } async fn create_sandbox( diff --git a/crates/openshell-gateway-interceptors/src/proto_json.rs b/crates/openshell-gateway-interceptors/src/proto_json.rs index f34c791adc..0763d7bf1d 100644 --- a/crates/openshell-gateway-interceptors/src/proto_json.rs +++ b/crates/openshell-gateway-interceptors/src/proto_json.rs @@ -322,6 +322,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }; let bytes = request.encode_to_vec(); let json = codec diff --git a/crates/openshell-gateway-interceptors/src/runtime.rs b/crates/openshell-gateway-interceptors/src/runtime.rs index 21de44fb9c..c102e106c7 100644 --- a/crates/openshell-gateway-interceptors/src/runtime.rs +++ b/crates/openshell-gateway-interceptors/src/runtime.rs @@ -1094,6 +1094,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }; let bytes = request.encode_to_vec(); diff --git a/crates/openshell-sdk/README.md b/crates/openshell-sdk/README.md index 001b2e9249..da180b8ce2 100644 --- a/crates/openshell-sdk/README.md +++ b/crates/openshell-sdk/README.md @@ -212,3 +212,9 @@ These helpers use the raw client's authentication slot. They do not perform OIDC - Async-only. Tonic is async-native; callers needing a blocking call can wrap with their own runtime. - The curated surface will grow as more RPCs graduate from `raw`. + +## Next minor API migration + +Raw `SandboxStatus` adds optional `ingress_admission`, and raw `CreateSandboxRequest` adds `forward_ports`. Compute-driver `ValidateSandboxCreateResponse` also adds optional `ingress_admission`. Complete generated Rust literals must initialize optional descriptors to `None` and ports to an empty vector, or use `..Default::default()`. + +Upgrade gateway replicas together. If forwarding reports missing admission after an upgrade, recreate the sandbox with the required service ports. diff --git a/crates/openshell-sdk/src/client.rs b/crates/openshell-sdk/src/client.rs index 1f03916ef2..91897d4fa9 100644 --- a/crates/openshell-sdk/src/client.rs +++ b/crates/openshell-sdk/src/client.rs @@ -1471,6 +1471,7 @@ fn create_sandbox_request(spec: SandboxSpec) -> proto::CreateSandboxRequest { command, tty, service_exposures, + forward_ports, restart_policy, } = spec; let template = image.map(|image| proto::SandboxTemplate { @@ -1498,6 +1499,7 @@ fn create_sandbox_request(spec: SandboxSpec) -> proto::CreateSandboxRequest { workspace_scope: Some(proto::workspace_selector("default")), await_main_process_attachment: false, workload_template: String::new(), + forward_ports: forward_ports.into_iter().map(u32::from).collect(), service_exposures: service_exposures .into_iter() .map(|exposure| proto::SandboxServiceExposure { @@ -1523,6 +1525,7 @@ fn create_sandbox_from_template_request( tty, policy, service_exposures, + forward_ports, } = spec; proto::CreateSandboxRequest { request_id: String::new(), @@ -1539,6 +1542,7 @@ fn create_sandbox_from_template_request( workspace_scope: Some(proto::workspace_selector("default")), workload_template: template_name, await_main_process_attachment: false, + forward_ports: forward_ports.into_iter().map(u32::from).collect(), service_exposures: service_exposures .into_iter() .map(|exposure| proto::SandboxServiceExposure { diff --git a/crates/openshell-sdk/src/types.rs b/crates/openshell-sdk/src/types.rs index 571ee42b68..7f6913516e 100644 --- a/crates/openshell-sdk/src/types.rs +++ b/crates/openshell-sdk/src/types.rs @@ -297,6 +297,8 @@ pub struct SandboxSpec { pub tty: bool, /// Loopback HTTP services to expose when the sandbox is created. pub service_exposures: Vec, + /// Target ports to admit before provisioning; does not open listeners. + pub forward_ports: Vec, /// Restart behavior after the canonical main process exits. pub restart_policy: SandboxRestartPolicy, } @@ -348,6 +350,8 @@ pub struct SandboxTemplateCreateSpec { pub tty: bool, /// Loopback HTTP services to expose when the sandbox is created. pub service_exposures: Vec, + /// Target ports to admit before provisioning; does not open listeners. + pub forward_ports: Vec, /// Create-time sandbox policy. The named workload template supplies runtime /// workload fields; policy remains part of the sandbox's governance spec. pub policy: Option, @@ -389,6 +393,8 @@ pub struct SandboxTemplateListOptions { #[derive(Clone, Debug)] #[non_exhaustive] pub struct SandboxRef { + /// Immutable compute-admitted ingress envelope, absent on legacy gateways. + pub ingress_admission: Option, pub id: String, pub name: String, pub workspace: String, @@ -444,6 +450,10 @@ impl SandboxRef { }); let meta = sandbox.metadata.unwrap_or_default(); Self { + ingress_admission: sandbox + .status + .as_ref() + .and_then(|status| status.ingress_admission.clone()), id: meta.id, name: meta.name, workspace: meta.workspace, diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index 1f3f791a08..ab9871e4eb 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -1246,6 +1246,7 @@ async fn create_sandbox_passes_spec_through() { image: Some("ghcr.io/foo:bar".to_string()), labels: labels.clone(), gpu: true, + forward_ports: vec![8080], service_exposures: vec![ServiceExposure { service: "web".to_string(), target_port: 8080, @@ -1266,6 +1267,7 @@ async fn create_sandbox_passes_spec_through() { assert_eq!(observed.name, "my-box"); assert_eq!(observed.labels, labels); assert!(observed.annotations.is_empty()); + assert_eq!(observed.forward_ports, vec![8080]); assert_eq!(observed.service_exposures.len(), 1); assert_eq!(observed.service_exposures[0].service, "web"); assert_eq!(observed.service_exposures[0].target_port, 8080); diff --git a/crates/openshell-sdk/tests/sandbox_status_compatibility.rs b/crates/openshell-sdk/tests/sandbox_status_compatibility.rs index 7a080a381f..d7af4d432d 100644 --- a/crates/openshell-sdk/tests/sandbox_status_compatibility.rs +++ b/crates/openshell-sdk/tests/sandbox_status_compatibility.rs @@ -1,14 +1,18 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Compile-time source-compatibility fixture for the v0.1.5 public status shape. +//! Exhaustive raw status fixture for the documented next-minor API transition. +//! +//! This intentionally advances the v0.1.5 source baseline. Legacy wire payloads +//! still decode; complete raw Rust literals need the new optional field. +//! See the SDK README migration notice. Do not backport into a 0.1.x patch train. use openshell_sdk::raw::proto::SandboxStatus; #[test] -fn baseline_exhaustive_sandbox_status_literal_still_compiles() { - // Intentionally no `..Default::default()`: adding even an optional public - // field breaks existing downstream Rust exhaustive struct literals. +fn next_minor_exhaustive_sandbox_status_literal_compiles() { + // Intentionally no `..Default::default()`: future shape changes must be + // reviewed against this declared minor baseline, never silently accepted. let status = SandboxStatus { agent_pod: String::new(), agent_fd: String::new(), @@ -26,6 +30,7 @@ fn baseline_exhaustive_sandbox_status_literal_still_compiles() { next_restart_time: None, main_process_started_time: None, last_token_grant_failure: None, + ingress_admission: None, }; assert_eq!(status, SandboxStatus::default()); } diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index 95ec004c6f..8c3246dbf7 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -685,7 +685,7 @@ impl AcquiredRemoteDriverEndpoint { struct RemoteComputeDriver { client: RemoteComputeDriverClient, configuration_updates_client: openshell_core::proto::compute::v1::compute_driver_configuration_updates_client::ComputeDriverConfigurationUpdatesClient>, - admission_acknowledgement: Arc>>, + admission_handshake: Arc>>, } type RemoteComputeDriverClient = ComputeDriverClient< @@ -697,7 +697,7 @@ impl RemoteComputeDriver { Self { client: ComputeDriverClient::with_interceptor(channel.clone(), TraceContextInterceptor), configuration_updates_client: openshell_core::proto::compute::v1::compute_driver_configuration_updates_client::ComputeDriverConfigurationUpdatesClient::with_interceptor(channel, TraceContextInterceptor), - admission_acknowledgement: Arc::new(StdMutex::new(None)), + admission_handshake: Arc::new(StdMutex::new(None)), } } @@ -706,8 +706,8 @@ impl RemoteComputeDriver { } async fn verify_admission_policy(&self, external_isolation: bool) -> Result<(), Status> { - let expected = self - .admission_acknowledgement + let (expected, require_ingress) = self + .admission_handshake .lock() .map_err(|_| Status::internal("admission handshake lock poisoned"))? .clone() @@ -728,6 +728,17 @@ impl RemoteComputeDriver { "remote compute driver no longer supports isolation backend registration; restart the gateway after upgrading the driver", )); } + if require_ingress + && !current.extension.as_ref().is_some_and(|metadata| { + metadata.supported_capabilities.iter().any(|capability| { + capability == openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION + }) + }) + { + return Err(Status::failed_precondition( + "remote compute driver no longer supports negotiated ingress admission; restart the gateway after upgrading the driver", + )); + } if current.resource_admission_policy != expected { return Err(Status::failed_precondition( "remote driver admission policy changed; restart gateway after configuring matching policy", @@ -765,10 +776,13 @@ impl ComputeDriver for RemoteComputeDriver { { let mut client = self.client(); let response = client.get_capabilities(request).await?; - self.admission_acknowledgement + self.admission_handshake .lock() .map_err(|_| Status::internal("admission handshake lock poisoned"))? - .get_or_insert_with(|| response.get_ref().resource_admission_policy.clone()); + .get_or_insert_with(|| ( + response.get_ref().resource_admission_policy.clone(), + response.get_ref().extension.as_ref().is_some_and(|metadata| metadata.supported_capabilities.iter().any(|capability| capability == openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION)), + )); Ok(response) } @@ -1437,6 +1451,41 @@ impl ComputeRuntime { } } + pub(crate) fn supports_ingress_admission(&self) -> bool { + self.driver_info + .negotiated_extension + .supported_capabilities + .iter() + .any(|capability| { + capability == openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION + }) + } + + pub(crate) fn admit_ingress_port(&self, sandbox: &Sandbox, port: u32) -> Result<(), Status> { + openshell_core::ingress::admit_port( + sandbox + .status + .as_ref() + .and_then(|status| status.ingress_admission.as_ref()), + port, + self.supports_ingress_admission(), + ) + .map(|_| ()) + .map_err(Status::failed_precondition) + } + + pub(crate) fn project_ingress_admission(&self, sandbox: &mut Sandbox) { + if self.supports_ingress_admission() { + // A retained legacy resource under a modern driver has no evidence. + // Publish explicit unavailable evidence so clients never infer legacy. + sandbox + .status + .get_or_insert_with(Default::default) + .ingress_admission + .get_or_insert_with(Default::default); + } + } + pub async fn validate_sandbox_create(&self, sandbox: &Sandbox) -> Result<(), Status> { self.validate_sandbox_create_with_runtime_inputs( sandbox, @@ -1444,6 +1493,7 @@ impl ComputeRuntime { false, ) .await + .map(|_| ()) } pub(crate) async fn validate_sandbox_create_with_runtime_inputs( @@ -1451,7 +1501,7 @@ impl ComputeRuntime { sandbox: &Sandbox, runtime_inputs: &SandboxCreateRuntimeInputs, await_main_process_attachment: bool, - ) -> Result<(), Status> { + ) -> Result, Status> { self.validate_caller_driver_config( sandbox .spec @@ -1473,7 +1523,8 @@ impl ComputeRuntime { let staged = self.rootfs_tar_staging.peek(&token)?; set_rootfs_tar_path(&mut driver_sandbox, &staged); } - self.driver + let response = self + .driver .call( openshell_otel::rpc::VALIDATE_SANDBOX_CREATE, Some(sandbox.object_id()), @@ -1485,8 +1536,17 @@ impl ComputeRuntime { .await }, ) - .await - .map(|_| ()) + .await? + .into_inner(); + if self.supports_ingress_admission() { + let admission = response.ingress_admission.ok_or_else(|| { + Status::failed_precondition("compute driver omitted negotiated ingress admission") + })?; + openshell_core::ingress::validate(&admission).map_err(Status::failed_precondition)?; + Ok(Some(admission)) + } else { + Ok(None) + } } pub async fn create_sandbox( @@ -1634,6 +1694,26 @@ impl ComputeRuntime { self.isolation_backend_name().into(), ); + if self.supports_ingress_admission() + && sandbox + .status + .as_ref() + .and_then(|status| status.ingress_admission.as_ref()) + .is_none() + { + let admission = self + .validate_sandbox_create_with_runtime_inputs( + &sandbox, + &runtime_inputs, + await_main_process_attachment, + ) + .await?; + sandbox + .status + .get_or_insert_with(Default::default) + .ingress_admission = admission; + } + // Strip the staging token from the public sandbox before anything // persists it: the object store copy is readable by every member of the // workspace, and the token is a bearer credential for the staged @@ -7565,6 +7645,7 @@ fn public_status_from_driver( next_restart_time: None, main_process_started_time: None, last_token_grant_failure: None, + ingress_admission: None, } } @@ -7721,6 +7802,9 @@ fn apply_driver_snapshot( .configuration_admission .clone_from(¤t_status.configuration_admission); status.configuration_activated = current_status.configuration_activated; + status + .ingress_admission + .clone_from(¤t_status.ingress_admission); status.provisioning.clone_from(¤t_status.provisioning); } if old_phase != phase { @@ -8443,7 +8527,7 @@ impl ComputeDriver for NoopTestDriver { Status, > { Ok(tonic::Response::new( - openshell_core::proto::compute::v1::ValidateSandboxCreateResponse {}, + openshell_core::proto::compute::v1::ValidateSandboxCreateResponse::default(), )) } @@ -9085,7 +9169,9 @@ mod tests { .lock() .expect("validated sandbox observation lock poisoned") .push(request.into_inner().sandbox.expect("validation sandbox")); - Ok(tonic::Response::new(ValidateSandboxCreateResponse {})) + Ok(tonic::Response::new( + ValidateSandboxCreateResponse::default(), + )) } async fn get_sandbox( @@ -9537,7 +9623,9 @@ mod tests { &self, _request: Request, ) -> Result, Status> { - Ok(tonic::Response::new(ValidateSandboxCreateResponse {})) + Ok(tonic::Response::new( + ValidateSandboxCreateResponse::default(), + )) } async fn get_sandbox( @@ -16119,59 +16207,78 @@ mod tests { } #[tokio::test] - async fn apply_sandbox_update_without_status_preserves_existing_status() { - let runtime = test_runtime(Arc::new(TestDriver::default())).await; - let mut sandbox = sandbox_record("sb-1", "sandbox-a", SandboxPhase::Ready); - sandbox.status = Some(SandboxStatus { - conditions: vec![SandboxCondition { - r#type: "Ready".to_string(), - status: "True".to_string(), - reason: "DependenciesReady".to_string(), - message: "Pod is Ready".to_string(), - transition_time: None, - }], - current_policy_version: 7, - ..Default::default() - }); - sandbox.set_phase(SandboxPhase::Ready as i32); - runtime.store.put_message(&sandbox).await.unwrap(); + async fn apply_sandbox_update_preserves_gateway_owned_status() { + for observed_status in [ + None, + Some(make_driver_status(DriverCondition { + status: "True".into(), + ..make_driver_condition("DependenciesReady", "Pod is Ready") + })), + ] { + let mut runtime = test_runtime(Arc::new(TestDriver::default())).await; + runtime.driver_info.driver_reports_runtime_readiness = true; + let mut sandbox = sandbox_record("sb-1", "sandbox-a", SandboxPhase::Ready); + sandbox.status = Some(SandboxStatus { + conditions: vec![SandboxCondition { + r#type: "Ready".to_string(), + status: "True".to_string(), + reason: "DependenciesReady".to_string(), + message: "Pod is Ready".to_string(), + transition_time: None, + }], + current_policy_version: 7, + ..Default::default() + }); + sandbox.set_phase(SandboxPhase::Ready as i32); + let ingress = openshell_core::proto::SandboxIngressAdmission { + scope: openshell_core::proto::IngressScope::SharedHostLoopback as i32, + all_ports: false, + ports: vec![8080], + }; + sandbox.status.as_mut().unwrap().ingress_admission = Some(ingress.clone()); + runtime.store.put_message(&sandbox).await.unwrap(); - runtime - .apply_sandbox_update(DriverSandbox { - id: "sb-1".to_string(), - name: "sandbox-a".to_string(), - namespace: "default".to_string(), - spec: None, - status: None, - workspace: "default".to_string(), - }) - .await - .unwrap(); + runtime + .apply_sandbox_update(DriverSandbox { + id: "sb-1".to_string(), + name: "sandbox-a".to_string(), + namespace: "default".to_string(), + spec: None, + status: observed_status, + workspace: "default".to_string(), + }) + .await + .unwrap(); - let stored = runtime - .store - .get_message::("sb-1") - .await - .unwrap() - .unwrap(); - assert_eq!( - SandboxPhase::try_from(stored.phase()).unwrap(), - SandboxPhase::Ready - ); - assert_eq!(stored.current_policy_version(), 7); - let ready = stored - .status - .as_ref() - .and_then(|status| { - status - .conditions - .iter() - .find(|condition| condition.r#type == "Ready") - }) - .unwrap(); - assert_eq!(ready.status, "True"); - assert_eq!(ready.reason, "DependenciesReady"); - assert_eq!(ready.message, "Pod is Ready"); + let stored = runtime + .store + .get_message::("sb-1") + .await + .unwrap() + .unwrap(); + assert_eq!( + SandboxPhase::try_from(stored.phase()).unwrap(), + SandboxPhase::Ready + ); + assert_eq!(stored.current_policy_version(), 7); + assert_eq!( + stored.status.as_ref().unwrap().ingress_admission.as_ref(), + Some(&ingress) + ); + let ready = stored + .status + .as_ref() + .and_then(|status| { + status + .conditions + .iter() + .find(|condition| condition.r#type == "Ready") + }) + .unwrap(); + assert_eq!(ready.status, "True"); + assert_eq!(ready.reason, "DependenciesReady"); + assert_eq!(ready.message, "Pod is Ready"); + } } #[tokio::test] @@ -18571,57 +18678,65 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" #[cfg(unix)] async fn remote_compute_driver_rejects_policy_changes_before_forwarding() { use crate::test_support::{FakeComputeDriver, FakeComputeDriverCall}; - let dir = tempfile::tempdir().unwrap(); - let socket_path = dir.path().join("admission.sock"); - let driver = FakeComputeDriver::new(); - let _server = driver.serve_uds(&socket_path).unwrap(); - let endpoint = connect_remote_compute_driver("external-test", &socket_path) - .await - .unwrap(); - let remote = RemoteComputeDriver::new(endpoint.channel); - remote - .get_capabilities(Request::new(GetCapabilitiesRequest { - gateway: Some(gateway_metadata(ExtensionFamily::Compute)), - })) - .await - .unwrap(); - driver.set_admission_acknowledgement(String::new()); - driver.clear_calls(); - let sandbox = DriverSandbox::default(); - let status = remote - .validate_sandbox_create(Request::new(ValidateSandboxCreateRequest { - sandbox: Some(sandbox.clone()), - })) - .await - .unwrap_err(); - assert_eq!(status.code(), Code::FailedPrecondition); - assert!( + for remove_ingress in [false, true] { + let dir = tempfile::tempdir().unwrap(); + let socket_path = dir.path().join("admission.sock"); + let driver = FakeComputeDriver::new(); + driver.set_ingress_capability(true); + let _server = driver.serve_uds(&socket_path).unwrap(); + let endpoint = connect_remote_compute_driver("external-test", &socket_path) + .await + .unwrap(); + let remote = RemoteComputeDriver::new(endpoint.channel); remote - .create_sandbox(Request::new(CreateSandboxRequest { - sandbox: Some(sandbox) + .get_capabilities(Request::new(GetCapabilitiesRequest { + gateway: Some(gateway_metadata(ExtensionFamily::Compute)), })) .await - .is_err() - ); - assert!( - remote - .start_sandbox(Request::new(StartSandboxRequest::default())) + .unwrap(); + if remove_ingress { + driver.set_ingress_capability(false); + } else { + driver.set_admission_acknowledgement(String::new()); + } + driver.clear_calls(); + let sandbox = DriverSandbox::default(); + let status = remote + .validate_sandbox_create(Request::new(ValidateSandboxCreateRequest { + sandbox: Some(sandbox.clone()), + })) .await - .is_err() - ); - let status = openshell_core::compute::ComputeDriver::update_sandbox_configuration( - &remote, - Request::new( - openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest::default(), - ), - ) - .await - .unwrap_err(); - assert_eq!(status.code(), Code::FailedPrecondition); - assert_eq!( - driver.calls(), - vec![FakeComputeDriverCall::GetCapabilities; 4] - ); + .unwrap_err(); + assert_eq!(status.code(), Code::FailedPrecondition); + assert!( + remote + .create_sandbox(Request::new(CreateSandboxRequest { + sandbox: Some(sandbox) + })) + .await + .is_err() + ); + assert!( + remote + .start_sandbox(Request::new(StartSandboxRequest::default())) + .await + .is_err() + ); + let status = openshell_core::compute::ComputeDriver::update_sandbox_configuration( + &remote, + Request::new( + openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest::default( + ), + ), + ) + .await + .unwrap_err(); + assert_eq!(status.code(), Code::FailedPrecondition); + assert_eq!( + driver.calls(), + vec![FakeComputeDriverCall::GetCapabilities; 4] + ); + } } #[tokio::test] diff --git a/crates/openshell-server/src/grpc/mod.rs b/crates/openshell-server/src/grpc/mod.rs index d066845fa4..832e8aa6e1 100644 --- a/crates/openshell-server/src/grpc/mod.rs +++ b/crates/openshell-server/src/grpc/mod.rs @@ -248,7 +248,11 @@ impl openshell_core::proto::sandbox_updates_server::SandboxUpdates for OpenShell &self, request: Request, ) -> Result, Status> { - mutation_replay::run(&self.state, request).await + let mut response = mutation_replay::run(&self.state, request).await?; + if let Some(sandbox) = response.get_mut().sandbox.as_mut() { + self.state.compute.project_ingress_admission(sandbox); + } + Ok(response) } } @@ -329,7 +333,11 @@ impl OpenShell for OpenShellService { &self, request: Request, ) -> Result, Status> { - mutation_replay::run(&self.state, request).await + let mut response = mutation_replay::run(&self.state, request).await?; + if let Some(sandbox) = response.get_mut().sandbox.as_mut() { + self.state.compute.project_ingress_admission(sandbox); + } + Ok(response) } async fn begin_rootfs_tar_staging( @@ -401,14 +409,22 @@ impl OpenShell for OpenShellService { &self, request: Request, ) -> Result, Status> { - mutation_replay::run(&self.state, request).await + let mut response = mutation_replay::run(&self.state, request).await?; + if let Some(sandbox) = response.get_mut().sandbox.as_mut() { + self.state.compute.project_ingress_admission(sandbox); + } + Ok(response) } async fn detach_sandbox_provider( &self, request: Request, ) -> Result, Status> { - mutation_replay::run(&self.state, request).await + let mut response = mutation_replay::run(&self.state, request).await?; + if let Some(sandbox) = response.get_mut().sandbox.as_mut() { + self.state.compute.project_ingress_admission(sandbox); + } + Ok(response) } async fn get_sandbox_provider_status( @@ -436,14 +452,22 @@ impl OpenShell for OpenShellService { &self, request: Request, ) -> Result, Status> { - mutation_replay::run(&self.state, request).await + let mut response = mutation_replay::run(&self.state, request).await?; + if let Some(sandbox) = response.get_mut().sandbox.as_mut() { + self.state.compute.project_ingress_admission(sandbox); + } + Ok(response) } async fn start_sandbox( &self, request: Request, ) -> Result, Status> { - mutation_replay::run(&self.state, request).await + let mut response = mutation_replay::run(&self.state, request).await?; + if let Some(sandbox) = response.get_mut().sandbox.as_mut() { + self.state.compute.project_ingress_admission(sandbox); + } + Ok(response) } async fn suspend_sandbox( diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index a797da2589..3989b3de78 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -79,7 +79,7 @@ use crate::persistence::current_time_ms; const TCP_FORWARD_CHUNK_SIZE: usize = 64 * 1024; const NO_LOGIN_SHELL_ENV: (&str, &str) = ("OPENSHELL_NO_LOGIN_SHELL", "1"); const MAX_TEMPLATES_PER_WORKSPACE: u32 = 1000; -const MAX_CREATE_SERVICE_EXPOSURES: usize = 32; +const MAX_CREATE_INGRESS_PORTS: usize = 32; const SANDBOX_CAS_RETRY_LIMIT: usize = 16; #[cfg(test)] @@ -363,7 +363,7 @@ pub(super) async fn handle_update_sandbox( ) .await?; Ok(Response::new(SandboxResponse { - sandbox: Some(sandbox), + sandbox: Some(project_public_sandbox(state, sandbox)), service_urls: HashMap::new(), })) } @@ -773,7 +773,7 @@ async fn handle_create_sandbox_inner( state .compute .validate_launch_signer_configured(state.sandbox_session_jwt_authority.is_some())?; - state + let ingress_admission = state .compute .validate_sandbox_create_with_runtime_inputs( &sandbox, @@ -786,6 +786,19 @@ async fn handle_create_sandbox_inner( status })?; + sandbox + .status + .get_or_insert_with(Default::default) + .ingress_admission = ingress_admission; + for port in request.forward_ports.iter().copied().chain( + request + .service_exposures + .iter() + .map(|exposure| exposure.target_port), + ) { + state.compute.admit_ingress_port(&sandbox, port)?; + } + let runtime_identity = crate::auth::sandbox_session::PersistedSandboxIdentity::new() .map_err(|error| Status::internal(error.to_string()))?; if let Some(metadata) = sandbox.metadata.as_mut() { @@ -872,11 +885,18 @@ async fn handle_create_sandbox_inner( "CreateSandbox request completed successfully" ); Ok(Response::new(SandboxResponse { - sandbox: Some(sandbox), + sandbox: Some(project_public_sandbox(state, sandbox)), service_urls, })) } +/// Project gateway-owned evidence on every outward sandbox value without +/// rewriting retained legacy records or accepting driver-supplied evidence. +fn project_public_sandbox(state: &ServerState, mut sandbox: Sandbox) -> Sandbox { + state.compute.project_ingress_admission(&mut sandbox); + sandbox +} + fn validate_create_sandbox_request_pre_io( request: &CreateSandboxRequest, workload_template_name: &str, @@ -885,9 +905,23 @@ fn validate_create_sandbox_request_pre_io( crate::grpc::validation::validate_labels(&request.labels)?; crate::grpc::validation::validate_caller_annotations(&request.annotations, "annotations")?; - if request.service_exposures.len() > MAX_CREATE_SERVICE_EXPOSURES { + if request.forward_ports.len() > MAX_CREATE_INGRESS_PORTS { + return Err(Status::invalid_argument(format!( + "forward_ports must contain at most {MAX_CREATE_INGRESS_PORTS} entries" + ))); + } + if request + .forward_ports + .iter() + .any(|port| !(1..=65535).contains(port)) + { + return Err(Status::invalid_argument( + "forward_ports must be between 1 and 65535", + )); + } + if request.service_exposures.len() > MAX_CREATE_INGRESS_PORTS { return Err(Status::invalid_argument(format!( - "service_exposures must contain at most {MAX_CREATE_SERVICE_EXPOSURES} entries" + "service_exposures must contain at most {MAX_CREATE_INGRESS_PORTS} entries" ))); } let mut service_names = HashSet::with_capacity(request.service_exposures.len()); @@ -1050,7 +1084,7 @@ pub(super) async fn handle_get_sandbox( None }; let mut response = Response::new(SandboxResponse { - sandbox: Some(sandbox), + sandbox: Some(project_public_sandbox(state, sandbox)), service_urls: HashMap::new(), }); if let Some(value) = owner.and_then(|owner| owner.parse().ok()) { @@ -1106,11 +1140,14 @@ pub(super) async fn handle_list_sandboxes( label_selector: selector, }, }; - let page = state + let mut page = state .store .list_message_page::(query, after.as_ref(), pagination.page_size()) .await .map_err(|e| Status::internal(format!("list sandboxes failed: {e}")))?; + for sandbox in &mut page.messages { + state.compute.project_ingress_admission(sandbox); + } let next_page_token = pagination.next_object_token(page.next_cursor.as_ref()); Ok(Response::new(ListSandboxesResponse { sandboxes: page.messages, @@ -1635,7 +1672,7 @@ pub(super) async fn handle_attach_sandbox_provider( ); Ok(Response::new(AttachSandboxProviderResponse { - sandbox: Some(sandbox), + sandbox: Some(project_public_sandbox(state, sandbox)), attached, receipt: Some(receipt), })) @@ -1763,7 +1800,7 @@ pub(super) async fn handle_detach_sandbox_provider( ); Ok(Response::new(DetachSandboxProviderResponse { - sandbox: Some(sandbox), + sandbox: Some(project_public_sandbox(state, sandbox)), detached, receipt: Some(receipt), })) @@ -1873,7 +1910,7 @@ async fn handle_stop_sandbox_inner( let sandbox = state.compute.stop_sandbox(workspace, name).await?; info!(sandbox_name = %name, "StopSandbox request completed successfully"); Ok(Response::new(SandboxResponse { - sandbox: Some(sandbox), + sandbox: Some(project_public_sandbox(state, sandbox)), service_urls: HashMap::new(), })) } @@ -1928,7 +1965,7 @@ async fn handle_start_sandbox_inner( .project_endpoint_status(&mut sandbox, remote_authority); info!(sandbox_name = %name, "StartSandbox request completed successfully"); Ok(Response::new(SandboxResponse { - sandbox: Some(sandbox), + sandbox: Some(project_public_sandbox(state, sandbox)), service_urls: HashMap::new(), })) } @@ -1969,7 +2006,7 @@ async fn handle_suspend_sandbox_inner( let sandbox = state.compute.suspend_sandbox(workspace, name).await?; info!(sandbox_name = %name, "SuspendSandbox request completed successfully"); Ok(Response::new(SandboxResponse { - sandbox: Some(sandbox), + sandbox: Some(project_public_sandbox(state, sandbox)), service_urls: HashMap::new(), })) } @@ -2025,7 +2062,7 @@ async fn handle_resume_sandbox_inner( .project_endpoint_status(&mut sandbox, remote_authority); info!(sandbox_name = %name, "ResumeSandbox request completed successfully"); Ok(Response::new(SandboxResponse { - sandbox: Some(sandbox), + sandbox: Some(project_public_sandbox(state, sandbox)), service_urls: HashMap::new(), })) } @@ -2223,7 +2260,7 @@ pub(super) async fn handle_watch_sandbox( .send(Ok(SandboxStreamEvent { payload: Some( openshell_core::proto::sandbox_stream_event::Payload::Sandbox( - sandbox.clone(), + project_public_sandbox(&state, sandbox.clone()), ), ), // Status snapshots are re-read, not resumed by cursor. @@ -2503,7 +2540,7 @@ pub(super) async fn handle_watch_sandbox( match state.store.get_message::(&sandbox_id).await { Ok(Some(sandbox)) => { state.sandbox_index.update_from_sandbox(&sandbox); - if tx.send(Ok(SandboxStreamEvent { payload: Some(openshell_core::proto::sandbox_stream_event::Payload::Sandbox(sandbox.clone())), cursor: String::new() })).await.is_err() { + if tx.send(Ok(SandboxStreamEvent { payload: Some(openshell_core::proto::sandbox_stream_event::Payload::Sandbox(project_public_sandbox(&state, sandbox.clone()))), cursor: String::new() })).await.is_err() { return; } if stop_on_terminal { @@ -2869,6 +2906,10 @@ pub(super) async fn handle_forward_tcp( ) .await?; + if let relay_open::Target::Tcp(target) = &target { + state.compute.admit_ingress_port(&sandbox, target.port)?; + } + // The main process may finish between minting the SSH token and opening // its transport. Keep the relay reachable until terminal delivery is // finalized so fast commands can attach without a readiness race. @@ -4302,6 +4343,377 @@ mod tests { GpuResourceRequirements, SandboxServiceExposure, ServiceAuthorizationMode, ServiceEndpoint, }; + #[tokio::test] + async fn ingress_admission_rejects_unadmitted_create_ports_before_provisioning() { + use crate::test_support::{FakeComputeDriver, FakeComputeDriverCall}; + use openshell_core::extension_protocol::{ + COMPUTE_INGRESS_ADMISSION, ExtensionFamily, extension_metadata, + }; + use openshell_core::proto::compute::v1::GetCapabilitiesResponse; + use openshell_core::proto::{IngressScope, SandboxIngressAdmission}; + + use futures::StreamExt as _; + use openshell_core::proto::open_shell_server::OpenShell as _; + let directory = tempfile::tempdir().unwrap(); + let key = directory.path().join("private-key"); + std::fs::write(&key, b"test-only stable fingerprint material").unwrap(); + let exact = SandboxIngressAdmission { + scope: IngressScope::SharedHostLoopback as i32, + ports: vec![8080], + all_ports: false, + }; + for (modern, admission, port, accepted) in [ + (false, None, 8081, true), + (true, None, 8080, false), + (true, Some(SandboxIngressAdmission::default()), 8080, false), + ( + true, + Some(SandboxIngressAdmission { + scope: IngressScope::Unsupported as i32, + ..Default::default() + }), + 8080, + false, + ), + (true, Some(exact.clone()), 8081, false), + (true, Some(exact.clone()), 8080, true), + (true, Some(exact.clone()), 0, false), + ( + true, + Some(SandboxIngressAdmission { + ports: vec![8080, 8080], + ..exact.clone() + }), + 8080, + false, + ), + ( + true, + Some(SandboxIngressAdmission { + all_ports: true, + ..exact.clone() + }), + 8080, + false, + ), + ( + true, + Some(SandboxIngressAdmission { + scope: IngressScope::IsolatedLoopback as i32, + all_ports: true, + ports: vec![], + }), + 8081, + true, + ), + ] { + for forward in [false, true] { + let mut state = test_server_state().await; + Arc::get_mut(&mut state).unwrap().config.gateway_jwt = + Some(openshell_core::config::GatewayJwtConfig { + signing_key_path: key.clone(), + public_key_path: directory.path().join("public"), + kid_path: directory.path().join("kid"), + gateway_id: "test".into(), + ttl_secs: None, + }); + let driver = Arc::new( + FakeComputeDriver::new() + .with_ingress_admission(admission.clone()) + .with_capabilities(GetCapabilitiesResponse { + driver_name: "test".into(), + default_image: "test/image".into(), + resource_admission_policy: + openshell_core::resource_admission::DriverAdmissionConfig::default() + .acknowledgement(), + extension: Some(extension_metadata( + ExtensionFamily::Compute, + "openshell/test", + "test", + if modern { + vec![COMPUTE_INGRESS_ADMISSION.to_string()] + } else { + vec![] + }, + )), + ..Default::default() + }), + ); + let compute = crate::compute::ComputeRuntime::from_driver( + "test".into(), + driver.clone(), + None, + state.store.clone(), + crate::sandbox_index::SandboxIndex::new(), + crate::sandbox_watch::SandboxWatchBus::new(), + crate::tracing_bus::TracingLogBus::new(), + Arc::new(crate::supervisor_session::SupervisorSessionRegistry::new()), + ) + .await + .unwrap(); + Arc::get_mut(&mut state).unwrap().compute = compute; + let result = handle_create_sandbox( + &state, + authed_request(CreateSandboxRequest { + name: "ingress".into(), + workspace_scope: Some(openshell_core::proto::workspace_selector("default")), + spec: Some(SandboxSpec { + policy: Some(openshell_policy::restrictive_default_policy()), + ..Default::default() + }), + forward_ports: if forward { vec![port] } else { vec![] }, + service_exposures: if forward { + vec![] + } else { + vec![SandboxServiceExposure { + target_port: port, + ..Default::default() + }] + }, + ..Default::default() + }), + ) + .await; + assert_eq!( + result.is_ok(), + accepted, + "modern={modern}, admission={admission:?}, port={port}" + ); + let provisioned = driver + .calls() + .iter() + .any(|call| matches!(call, FakeComputeDriverCall::CreateSandbox { .. })); + assert_eq!(provisioned, accepted); + let stored = state + .store + .get_message_by_name::("default", "ingress") + .await + .unwrap(); + assert_eq!(stored.is_some(), accepted); + if accepted && modern { + let sandbox = stored.unwrap(); + assert_eq!( + sandbox.status.as_ref().unwrap().ingress_admission, + admission + ); + if !admission.as_ref().unwrap().all_ports { + assert!( + super::super::service::expose_service_endpoint( + &state, + "default", + &sandbox, + "unadmitted", + 8081, + ServiceAuthorizationMode::Strip + ) + .await + .is_err() + ); + assert!( + state + .store + .get_message_by_name::( + "default", + "ingress--unadmitted" + ) + .await + .unwrap() + .is_none() + ); + // A resource created before ingress negotiation has no + // retained evidence. Every current read must expose its + // unavailability without rewriting that legacy record. + let mut legacy = sandbox.clone(); + let metadata = legacy.metadata.as_mut().unwrap(); + metadata.id = "legacy-ingress".into(); + metadata.name = "legacy-ingress".into(); + metadata.resource_version = 0; + legacy.set_phase(SandboxPhase::Ready as i32); + legacy.status.as_mut().unwrap().ingress_admission = None; + state.store.put_message(&legacy).await.unwrap(); + let get = handle_get_sandbox( + &state, + authed_request(GetSandboxRequest { + name: "legacy-ingress".into(), + workspace_scope: Some(openshell_core::proto::workspace_selector( + "default", + )), + }), + ) + .await + .unwrap() + .into_inner() + .sandbox + .unwrap(); + assert!( + openshell_core::ingress::admit_port( + get.status.as_ref().unwrap().ingress_admission.as_ref(), + 8080, + false + ) + .is_err() + ); + let service = crate::grpc::OpenShellService::new(state.clone()); + let start = StartSandboxRequest { + name: "legacy-ingress".into(), + workspace_scope: Some(openshell_core::proto::workspace_selector( + "default", + )), + request_id: uuid::Uuid::new_v4().to_string(), + }; + for replay in [false, true] { + let started = service + .start_sandbox(authed_request(start.clone())) + .await + .unwrap(); + assert_eq!( + started.metadata().contains_key("openshell-replayed"), + replay + ); + let descriptor = started + .into_inner() + .sandbox + .unwrap() + .status + .unwrap() + .ingress_admission; + assert!(descriptor.is_some()); + assert!( + openshell_core::ingress::admit_port( + descriptor.as_ref(), + 8080, + false + ) + .is_err() + ); + } + let mut stream = handle_watch_sandbox( + &state, + authed_request(WatchSandboxRequest { + sandbox: "legacy-ingress".into(), + workspace_scope: Some(openshell_core::proto::workspace_selector( + "default", + )), + follow_status: true, + ..Default::default() + }), + ) + .await + .unwrap() + .into_inner(); + for updated in [false, true] { + if updated { + state.sandbox_watch_bus.notify("legacy-ingress"); + } + let event = tokio::time::timeout( + std::time::Duration::from_secs(1), + stream.next(), + ) + .await + .unwrap() + .unwrap() + .unwrap(); + let Some( + openshell_core::proto::sandbox_stream_event::Payload::Sandbox( + snapshot, + ), + ) = event.payload + else { + panic!("expected status snapshot") + }; + assert!(snapshot.status.unwrap().ingress_admission.is_some()); + } + assert!( + state + .store + .get_message::("legacy-ingress") + .await + .unwrap() + .unwrap() + .status + .unwrap() + .ingress_admission + .is_none() + ); + } + } + } + } + } + + #[tokio::test] + async fn ingress_admission_guards_live_tcp_targets_without_blocking_ssh_transport() { + use openshell_core::proto::open_shell_client::OpenShellClient; + use openshell_core::proto::open_shell_server::OpenShellServer; + use openshell_core::proto::{IngressScope, SandboxIngressAdmission, tcp_forward_frame}; + use tokio_stream::wrappers::TcpListenerStream; + + let state = test_server_state().await; + let mut sandbox = Sandbox { + metadata: Some(ObjectMeta { + id: "ingress-live".into(), + name: "ingress-live".into(), + workspace: "default".into(), + ..Default::default() + }), + ..Default::default() + }; + sandbox.set_phase(SandboxPhase::Stopped as i32); + sandbox.status.as_mut().unwrap().ingress_admission = Some(SandboxIngressAdmission { + scope: IngressScope::SharedHostLoopback as i32, + all_ports: false, + ports: vec![8080], + }); + state.store.put_message(&sandbox).await.unwrap(); + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let address = listener.local_addr().unwrap(); + let server = tokio::spawn( + tonic::transport::Server::builder() + .add_service(OpenShellServer::with_interceptor( + crate::OpenShellService::new(state), + crate::test_support::authenticate_as_dev_user, + )) + .serve_with_incoming(TcpListenerStream::new(listener)), + ); + let mut client = OpenShellClient::connect(format!("http://{address}")) + .await + .unwrap(); + for (target, diagnostic) in [ + ( + tcp_forward_init::Target::Tcp(TcpRelayTarget { + host: "127.0.0.1".into(), + port: 8081, + }), + "target port was not admitted", + ), + ( + tcp_forward_init::Target::Tcp(TcpRelayTarget { + host: "127.0.0.1".into(), + port: 8080, + }), + "sandbox is not ready", + ), + ( + tcp_forward_init::Target::Ssh(SshRelayTarget::default()), + "sandbox is not ready", + ), + ] { + let error = client + .forward_tcp(tokio_stream::iter([TcpForwardFrame { + payload: Some(tcp_forward_frame::Payload::Init(TcpForwardInit { + sandbox: "ingress-live".into(), + workspace: "default".into(), + target: Some(target), + ..Default::default() + })), + }])) + .await + .unwrap_err(); + assert!(error.message().contains(diagnostic), "{error}"); + } + server.abort(); + } + #[tokio::test] async fn missing_launch_signer_precedes_driver_validation_and_preserves_staged_archive() { let directory = tempfile::tempdir().unwrap(); @@ -7039,6 +7451,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -7114,6 +7527,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -7152,6 +7566,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -7234,6 +7649,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -7614,6 +8030,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -7677,6 +8094,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -8002,6 +8420,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -8073,6 +8492,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -8124,6 +8544,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -8168,6 +8589,7 @@ mod tests { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -8828,6 +9250,7 @@ mod tests { workload_template: "gpu-kata".to_string(), await_main_process_attachment: false, service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -8917,6 +9340,7 @@ mod tests { workload_template: "default-image".to_string(), await_main_process_attachment: false, service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -8971,6 +9395,7 @@ mod tests { workload_template: "default-gpu".to_string(), await_main_process_attachment: false, service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -9012,6 +9437,7 @@ mod tests { workload_template: "corrupt-template".to_string(), await_main_process_attachment: false, service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -9054,6 +9480,7 @@ mod tests { workload_template: "gpu-kata".to_string(), await_main_process_attachment: false, service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -9081,6 +9508,7 @@ mod tests { workload_template: "Invalid_Template_Name".to_string(), await_main_process_attachment: false, service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -9111,6 +9539,7 @@ mod tests { workload_template: "missing-template".to_string(), await_main_process_attachment: false, service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await @@ -9141,6 +9570,7 @@ mod tests { workload_template: String::new(), await_main_process_attachment: false, service_exposures: Vec::new(), + forward_ports: Vec::new(), }), ) .await diff --git a/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs b/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs index e83d786ee0..e00ccd1d21 100644 --- a/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs +++ b/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs @@ -135,7 +135,10 @@ async fn state() -> (Arc, Arc, Sandbox) { openshell_core::extension_protocol::ExtensionFamily::Compute, "openshell/image-test", "test", - [openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION.into()], + [ + openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION.into(), + openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION.into(), + ], )), ..Default::default() }), @@ -258,6 +261,20 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re .sandbox .unwrap(); assert_eq!(updated.object_id(), sandbox.object_id()); + assert_eq!( + updated.status.as_ref().unwrap().ingress_admission, + Some(openshell_core::proto::SandboxIngressAdmission::default()) + ); + let stored = state + .store + .get_message::(sandbox.object_id()) + .await + .unwrap() + .unwrap(); + assert!( + stored.status.as_ref().unwrap().ingress_admission.is_none(), + "inspection projection must not invent durable admission evidence" + ); assert_eq!( updated .spec diff --git a/crates/openshell-server/src/grpc/service.rs b/crates/openshell-server/src/grpc/service.rs index bea999e5af..21f9771b44 100644 --- a/crates/openshell-server/src/grpc/service.rs +++ b/crates/openshell-server/src/grpc/service.rs @@ -93,6 +93,7 @@ pub(super) async fn expose_service_endpoint( target_port: u32, authorization_mode: ServiceAuthorizationMode, ) -> Result, Status> { + state.compute.admit_ingress_port(sandbox, target_port)?; let sandbox_name = sandbox.object_name(); // Count and persist under the same fleet-wide sandbox guard, including // create-time exposure, so concurrent gateways cannot overfill the allowlist. diff --git a/crates/openshell-server/src/service_routing.rs b/crates/openshell-server/src/service_routing.rs index ece2add1e0..ac4e035849 100644 --- a/crates/openshell-server/src/service_routing.rs +++ b/crates/openshell-server/src/service_routing.rs @@ -777,6 +777,23 @@ async fn proxy_to_endpoint( return Err(err); } + if state + .compute + .admit_ingress_port(&sandbox, endpoint.target_port) + .is_err() + { + let err = ServiceRouteError::endpoint_unavailable(); + emit_service_http_failure( + &state, + &req, + &sandbox_name, + &service_name, + Some(&endpoint), + &err, + ); + return Err(err); + } + let websocket_upgrade = is_websocket_upgrade(&req); let downstream_upgrade = websocket_upgrade.then(|| hyper::upgrade::on(&mut req)); @@ -2332,6 +2349,53 @@ mod tests { ); } + #[tokio::test] + async fn ingress_admission_is_checked_before_a_pooled_upstream_is_taken() { + use openshell_core::proto::{IngressScope, SandboxIngressAdmission}; + let state = crate::grpc::test_support::test_server_state().await; + let endpoint = endpoint(); + let mut sandbox = Sandbox { + metadata: Some(openshell_core::proto::datamodel::v1::ObjectMeta { + id: endpoint.sandbox_id.clone(), + name: endpoint.sandbox.clone(), + workspace: "default".into(), + ..Default::default() + }), + ..Default::default() + }; + sandbox.set_phase(SandboxPhase::Ready as i32); + sandbox.status.as_mut().unwrap().ingress_admission = Some(SandboxIngressAdmission { + scope: IngressScope::SharedHostLoopback as i32, + all_ports: false, + ports: vec![9090], + }); + state.store.put_message(&sandbox).await.unwrap(); + state.store.put_message(&endpoint).await.unwrap(); + let key = upstream_pool_key(endpoint.object_id(), 8080); + let (sender, _peer) = test_upstream().await; + state.service_upstreams.put(&key, sender); + let result = tokio::time::timeout( + Duration::from_millis(250), + proxy_to_endpoint( + state.clone(), + Request::builder().uri("/").body(Body::empty()).unwrap(), + "default", + endpoint.sandbox, + endpoint.name, + ), + ) + .await + .expect("an unadmitted route must reject before pooled I/O"); + assert_eq!( + result.unwrap_err().reason, + ServiceRouteError::endpoint_unavailable().reason + ); + assert!( + state.service_upstreams.take(&key).is_some(), + "admission must precede taking any pooled connection" + ); + } + #[tokio::test] async fn pool_hands_back_a_ready_upstream() { let pool = ServiceUpstreamPool::default(); diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index 5f7d87555b..a536a11b59 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -178,11 +178,11 @@ mod tests { // image wire identity, now with explicit presence. Compute configuration // updates use a separate capability/service and add one classified RPC. const PUBLIC_RPC_SCHEMA_SHA256: &str = - "33e32bb6cb2251b3e75c6425555502e6c2fd675b640094437ef06856a46866e3"; + "8489ca488c0f1e70ab23970fd364cf9e1c0e09b84e945761a0f2056da2aac03c"; const DURABLE_SCHEMA_SHA256: &str = - "cb15f8f79a855064a43fe8c6cd908bf07eca6604e2bf8ab7d2de0ef33e97da4e"; + "a8aa47c33c3fdb54a25c229a1d23600c2ae69daf3d0fa5191b88a8f4a9829dde"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = - "c0c3ea17f105aaa6d843c466fd4240451c2105dce7675384935d4aaecdac8abf"; + "afbb27866df733be657a985ce68702e515f40cb95764817d427a9578f9884897"; // Encoded with the schema that omitted stable_placeholder. Keep these // bytes fixed so the current encoder cannot hide a compatibility change. const LEGACY_STATIC_PROFILE: &str = "0a240a116c65676163792d70726f66696c652d6964120d6c65676163792d737461746963280712510a0d6c65676163792d73746174696312184c6567616379207374617469632063726564656e7469616c2a260a076170695f6b65791a1153594e5448455449435f4150495f4b455920012a06626561726572"; @@ -723,9 +723,9 @@ mod tests { overlap_hash.as_str(), ), ( - (335, 31), - (100, 22), - (86, 22), + (336, 32), + (101, 23), + (87, 23), PUBLIC_RPC_SCHEMA_SHA256, DURABLE_SCHEMA_SHA256, PUBLIC_DURABLE_OVERLAP_SHA256 @@ -783,6 +783,7 @@ mod tests { assert!(status.configuration_admission.is_none()); assert_eq!(status.configuration_activated, None); assert!(status.provisioning.is_none()); + assert!(status.ingress_admission.is_none()); assert!(!crate::policy_store::permits_initial_static_policy_repair( &sandbox )); diff --git a/crates/openshell-server/src/test_support.rs b/crates/openshell-server/src/test_support.rs index e12bd617a9..d63bfdd488 100644 --- a/crates/openshell-server/src/test_support.rs +++ b/crates/openshell-server/src/test_support.rs @@ -143,6 +143,7 @@ pub struct FakeComputeDriver { #[derive(Debug)] struct FakeComputeDriverState { capabilities: GetCapabilitiesResponse, + ingress_admission: Option, sandboxes: HashMap, calls: Vec, traceparents: Vec, @@ -165,10 +166,20 @@ impl FakeComputeDriver { self } + #[must_use] + pub fn with_ingress_admission( + self, + admission: Option, + ) -> Self { + self.with_state(|state| state.ingress_admission = admission); + self + } + #[must_use] pub fn new() -> Self { Self { state: Arc::new(Mutex::new(FakeComputeDriverState { + ingress_admission: None, capabilities: GetCapabilitiesResponse { resource_admission_policy: openshell_core::resource_admission::DriverAdmissionConfig::default() @@ -237,6 +248,24 @@ impl FakeComputeDriver { self } + pub fn set_ingress_capability(&self, supported: bool) { + self.with_state(|state| { + let capabilities = &mut state + .capabilities + .extension + .as_mut() + .unwrap() + .supported_capabilities; + capabilities.retain(|capability| { + capability != openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION + }); + if supported { + capabilities + .push(openshell_core::extension_protocol::COMPUTE_INGRESS_ADMISSION.into()); + } + }); + } + #[must_use] pub fn with_sandbox_image_updates(self) -> Self { self.with_state(|state| { @@ -439,7 +468,9 @@ impl ComputeDriver for FakeComputeDriver { sandbox: request.sandbox, }); }); - Ok(Response::new(ValidateSandboxCreateResponse {})) + Ok(Response::new(ValidateSandboxCreateResponse { + ingress_admission: self.with_state(|state| state.ingress_admission.clone()), + })) } async fn get_sandbox( diff --git a/crates/openshell-tui/src/lib.rs b/crates/openshell-tui/src/lib.rs index 133d7d5c0a..343cebbadb 100644 --- a/crates/openshell-tui/src/lib.rs +++ b/crates/openshell-tui/src/lib.rs @@ -1442,6 +1442,7 @@ fn spawn_create_sandbox(app: &mut App, tx: mpsc::UnboundedSender) { await_main_process_attachment: false, workload_template: String::new(), service_exposures: Vec::new(), + forward_ports: ports.iter().map(|spec| u32::from(spec.port)).collect(), }; let sandbox_name = @@ -1470,7 +1471,7 @@ fn spawn_create_sandbox(app: &mut App, tx: mpsc::UnboundedSender) { // If ports or command are set, wait for Ready before finishing. if need_ready { let mut attempts = 0; - let _sandbox_id = loop { + let ready_sandbox = loop { attempts += 1; if attempts > 150 { let _ = tx.send(Event::CreateResult(Err( @@ -1491,7 +1492,7 @@ fn spawn_create_sandbox(app: &mut App, tx: mpsc::UnboundedSender) { && let Some(sandbox) = resp.into_inner().sandbox { if sandbox.phase() == SandboxPhase::Ready as i32 { - break sandbox.object_id().to_string(); + break sandbox; } if sandbox.phase() == SandboxPhase::Error as i32 { let _ = tx.send(Event::CreateResult(Err( @@ -1502,6 +1503,25 @@ fn spawn_create_sandbox(app: &mut App, tx: mpsc::UnboundedSender) { } }; + // Inspect admission before creating any SSH sessions or listeners. + for spec in &ports { + if let Err(error) = openshell_core::ingress::admit_port( + ready_sandbox + .status + .as_ref() + .and_then(|status| status.ingress_admission.as_ref()), + u32::from(spec.port), + false, + ) { + let _ = tx.send(Event::ForwardWarnings(vec![format!( + "port {}: {error}", + spec.port + )])); + let _ = tx.send(Event::CreateResult(Ok((sandbox_name, workspace)))); + return; + } + } + // Start port forwards if requested. if !ports.is_empty() { let forward_warnings = start_port_forwards( diff --git a/docs/extensibility/isolation-backends.mdx b/docs/extensibility/isolation-backends.mdx index 8dd5903176..c8743a6555 100644 --- a/docs/extensibility/isolation-backends.mdx +++ b/docs/extensibility/isolation-backends.mdx @@ -39,6 +39,10 @@ accept an operator-selected `IsolationBackendRegistration`, including its Unix, TCP, or vsock endpoint. The driver provisions the resource and delivers the backend's trusted launch metadata to the supervisor. +Compute drivers that advertise `openshell.compute.ingress-admission` return +the supported forwarding scope and allowed ports from `ValidateSandboxCreate`. +The isolation backend must enforce those limits when connecting to a service. + ## Who Owns What | Component | Owns | @@ -50,3 +54,8 @@ backend's trusted launch metadata to the supervisor. For how `openshell-sandbox` enforces the boundary, refer to [Inside the Sandbox Boundary](/about/architecture#inside-the-sandbox-boundary). For driver-specific workload behavior, refer to [Runtimes](/how-it-works/sandboxes/runtimes). + +## Release compatibility + +Upgrade gateway replicas together. For source compatibility changes, see the +[SDK migration notes](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-sdk/README.md#next-minor-api-migration). diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index 2ac6a4f69d..37abfcfa22 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -826,6 +826,12 @@ Press `c` in the Sandboxes panel to create a sandbox. In the optional Command fi ## Port Forwarding +Compute drivers can restrict which service ports you can forward. Declare the +target port at creation with `--forward `. Disallowed ports are rejected +before a local listener opens. If forwarding reports missing admission after an +upgrade, recreate the sandbox with the required port. A shared-host loopback +target is an operator-approved service on the compute host. + Forward a local port to a running sandbox to access services inside it, such as a web server or database: ```shell diff --git a/examples/isolation-backend-v8/src/driver.rs b/examples/isolation-backend-v8/src/driver.rs index adce131a8f..4d4c9eff64 100644 --- a/examples/isolation-backend-v8/src/driver.rs +++ b/examples/isolation-backend-v8/src/driver.rs @@ -384,7 +384,7 @@ impl compute_driver_server::ComputeDriver for DriverService { .as_ref() .ok_or_else(|| Status::invalid_argument("sandbox required"))?, )?; - Ok(Response::new(ValidateSandboxCreateResponse {})) + Ok(Response::new(ValidateSandboxCreateResponse::default())) } async fn create_sandbox( &self, diff --git a/proto/compute_driver.proto b/proto/compute_driver.proto index e50f41d0ee..5167bfd1eb 100644 --- a/proto/compute_driver.proto +++ b/proto/compute_driver.proto @@ -438,7 +438,12 @@ message ValidateSandboxCreateRequest { DriverSandbox sandbox = 1; } -message ValidateSandboxCreateResponse {} +message ValidateSandboxCreateResponse { + // Required when openshell.compute.ingress-admission is negotiated. Complete + // immutable envelope, including an explicit unsupported result. Create/start + // must enforce this envelope from the same retained template/configuration. + openshell.sandbox.v1.SandboxIngressAdmission ingress_admission = 1; +} message GetSandboxRequest { // Stable sandbox ID stored by the gateway. diff --git a/proto/openshell.proto b/proto/openshell.proto index e498a84af9..b3d490616e 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -1258,6 +1258,9 @@ message SandboxStatus { // failures before a configured endpoint or credential could be selected. // Matching grant success or a policy, provider, or supervisor reset clears it. TokenGrantFailureObservation last_token_grant_failure = 17; + // Gateway-retained immutable compute-driver ingress admission. Absence is + // legacy behavior only when the selected driver has not negotiated ingress. + openshell.sandbox.v1.SandboxIngressAdmission ingress_admission = 19; } // User-facing sandbox condition derived from platform or gateway observations. @@ -1344,6 +1347,9 @@ message CreateSandboxRequest { // registered after the sandbox has been persisted and route only while the // sandbox is ready. repeated SandboxServiceExposure service_exposures = 9; + // Requested local forward targets, checked before provisioning. This does + // not open a listener; clients establish the admitted forwards after create. + repeated uint32 forward_ports = 10; } // Update selected configuration of a stopped sandbox. Omitted fields are unchanged. diff --git a/proto/sandbox.proto b/proto/sandbox.proto index b57c5d4cda..65be37f18d 100644 --- a/proto/sandbox.proto +++ b/proto/sandbox.proto @@ -17,6 +17,23 @@ import "datamodel.proto"; // - Public sandbox resource types live in `openshell.proto`. // - Internal compute-driver sandbox observation types live in `compute_driver.proto`. +// Immutable ingress envelope admitted from the compute driver's resolved inputs. +// Presence with an unspecified scope is invalid; it never means legacy support. +message SandboxIngressAdmission { + IngressScope scope = 1; + // Mutually exclusive with ports. False with an empty list admits no ports. + bool all_ports = 2; + repeated uint32 ports = 3; +} + +enum IngressScope { + INGRESS_SCOPE_UNSPECIFIED = 0; + INGRESS_SCOPE_UNSUPPORTED = 1; + INGRESS_SCOPE_ISOLATED_LOOPBACK = 2; + // The driver has admitted its operator-controlled shared-host opt-in. + INGRESS_SCOPE_SHARED_HOST_LOOPBACK = 3; +} + // Sandbox security policy configuration. message SandboxPolicy { // Policy version. diff --git a/python/openshell/__init__.py b/python/openshell/__init__.py index c99c3b48e0..f52d196b57 100644 --- a/python/openshell/__init__.py +++ b/python/openshell/__init__.py @@ -18,6 +18,7 @@ SandboxClient, SandboxConditionRef, SandboxError, + SandboxIngressAdmissionRef, SandboxRef, SandboxSession, SandboxStatusRef, @@ -54,6 +55,7 @@ "SandboxClient", "SandboxConditionRef", "SandboxError", + "SandboxIngressAdmissionRef", "SandboxRef", "SandboxSession", "SandboxStatusRef", diff --git a/python/openshell/sandbox.py b/python/openshell/sandbox.py index c02a33cdbf..f38b9cdb31 100644 --- a/python/openshell/sandbox.py +++ b/python/openshell/sandbox.py @@ -515,6 +515,15 @@ class SandboxConditionRef: transition_time_ms: int | None = None +@dataclass(frozen=True) +class SandboxIngressAdmissionRef: + """Compute-admitted loopback namespace and immutable target ports.""" + + scope: int + all_ports: bool + ports: tuple[int, ...] + + @dataclass(frozen=True) class SandboxStatusRef: phase: int @@ -524,6 +533,7 @@ class SandboxStatusRef: next_restart_at_ms: int | None = None main_process_started_at_ms: int | None = None conditions: tuple[SandboxConditionRef, ...] = () + ingress_admission: SandboxIngressAdmissionRef | None = None class ServiceAuthorizationMode(IntEnum): @@ -923,6 +933,7 @@ def create( name: str | None = None, labels: Mapping[str, str] | None = None, service_exposures: Sequence[ServiceExposure] | None = None, + forward_ports: Sequence[int] | None = None, ) -> SandboxRef: request_spec = spec if spec is not None else _default_spec() response = self._stub.CreateSandbox( @@ -932,6 +943,7 @@ def create( name=name or "", labels=dict(labels) if labels else {}, service_exposures=_service_exposure_messages(service_exposures), + forward_ports=list(forward_ports or ()), ), timeout=self._timeout, ) @@ -949,6 +961,7 @@ def create_from_template( name: str | None = None, labels: Mapping[str, str] | None = None, service_exposures: Sequence[ServiceExposure] | None = None, + forward_ports: Sequence[int] | None = None, ) -> SandboxRef: if not workload_template.strip(): raise SandboxError("workload_template is required") @@ -961,6 +974,7 @@ def create_from_template( labels=dict(labels) if labels else {}, workload_template=workload_template, service_exposures=_service_exposure_messages(service_exposures), + forward_ports=list(forward_ports or ()), ), timeout=self._timeout, ) @@ -977,6 +991,7 @@ def create_session( name: str | None = None, labels: Mapping[str, str] | None = None, service_exposures: Sequence[ServiceExposure] | None = None, + forward_ports: Sequence[int] | None = None, ) -> SandboxSession: return SandboxSession( self, @@ -986,6 +1001,7 @@ def create_session( name=name, labels=labels, service_exposures=service_exposures, + forward_ports=forward_ports, ), ) @@ -998,6 +1014,7 @@ def create_session_from_template( name: str | None = None, labels: Mapping[str, str] | None = None, service_exposures: Sequence[ServiceExposure] | None = None, + forward_ports: Sequence[int] | None = None, ) -> SandboxSession: return SandboxSession( self, @@ -1008,6 +1025,7 @@ def create_session_from_template( name=name, labels=labels, service_exposures=service_exposures, + forward_ports=forward_ports, ), ) @@ -2012,6 +2030,13 @@ def _sandbox_ref( if status is not None and status.HasField("main_process_started_time") else None, conditions=_sandbox_conditions(status), + ingress_admission=SandboxIngressAdmissionRef( + scope=status.ingress_admission.scope, + all_ports=status.ingress_admission.all_ports, + ports=tuple(status.ingress_admission.ports), + ) + if status is not None and status.HasField("ingress_admission") + else None, ), labels=sandbox.metadata.labels if sandbox.metadata else {}, created_from_workload_template=provenance, diff --git a/python/openshell/sandbox_test.py b/python/openshell/sandbox_test.py index 3fed31734e..34cfe0bfba 100644 --- a/python/openshell/sandbox_test.py +++ b/python/openshell/sandbox_test.py @@ -21,7 +21,7 @@ from google.protobuf.struct_pb2 import Struct import openshell.sandbox as sandbox_module -from openshell._proto import openshell_pb2, openshell_pb2_grpc +from openshell._proto import openshell_pb2, openshell_pb2_grpc, sandbox_pb2 from openshell.mutations import DeletionOutcome from openshell.sandbox import ( _OIDC_TOKEN_EXPIRY_GRACE_SECONDS, @@ -2359,6 +2359,7 @@ def test_create_forwards_service_exposures() -> None: ref = client.create( workspace="default", name="app-server", + forward_ports=[8080], service_exposures=[ ServiceExposure(target_port=4500), ServiceExposure( @@ -2370,6 +2371,7 @@ def test_create_forwards_service_exposures() -> None: ) assert stub.create_request is not None + assert list(stub.create_request.forward_ports) == [8080] assert [ (exposure.service, exposure.target_port, exposure.authorization_mode) for exposure in stub.create_request.service_exposures @@ -2920,6 +2922,19 @@ def test_sandbox_ref_exposes_host_identity_and_accepts_legacy_response() -> None assert _sandbox_ref(proto).host_key_fingerprint is None proto.host_key_fingerprint = "SHA256:expected" assert _sandbox_ref(proto).host_key_fingerprint == "SHA256:expected" + assert _sandbox_ref(proto).status.ingress_admission is None + proto.status.ingress_admission.scope = ( + sandbox_pb2.INGRESS_SCOPE_SHARED_HOST_LOOPBACK + ) + proto.status.ingress_admission.ports.append(8080) + admission = _sandbox_ref(proto).status.ingress_admission + assert ( + admission is not None + and admission.ports == (8080,) + and admission.scope == sandbox_pb2.INGRESS_SCOPE_SHARED_HOST_LOOPBACK + ) + proto.status.ingress_admission.ports[0] = 9090 + assert admission.ports == (8080,) def test_sandbox_ref_includes_main_process_result() -> None: diff --git a/sdk/go/openshell/v1/exec_client_test.go b/sdk/go/openshell/v1/exec_client_test.go index fbf5140311..793e51727a 100644 --- a/sdk/go/openshell/v1/exec_client_test.go +++ b/sdk/go/openshell/v1/exec_client_test.go @@ -24,14 +24,15 @@ import ( // stubSandboxResolver implements SandboxInterface for testing name-to-ID resolution. // Get returns a Sandbox with ID = "sb-" + name. All other methods panic. type stubSandboxResolver struct { - getErr error // if non-nil, Get returns this error + getErr error // if non-nil, Get returns this error + ingressAdmission *SandboxIngressAdmission } func (r *stubSandboxResolver) Get(_ context.Context, _, name string) (*Sandbox, error) { if r.getErr != nil { return nil, r.getErr } - return &Sandbox{ID: "sb-" + name, Name: name}, nil + return &Sandbox{ID: "sb-" + name, Name: name, Status: SandboxStatus{IngressAdmission: r.ingressAdmission}}, nil } func (r *stubSandboxResolver) Create(context.Context, string, string, *SandboxSpec, ...CreateOption) (*Sandbox, error) { diff --git a/sdk/go/openshell/v1/fake/fake_test.go b/sdk/go/openshell/v1/fake/fake_test.go index 12e44badd5..8018102556 100644 --- a/sdk/go/openshell/v1/fake/fake_test.go +++ b/sdk/go/openshell/v1/fake/fake_test.go @@ -208,9 +208,11 @@ func TestFakeClient_SandboxEndpointStatuses_DeepCopy(t *testing.T) { LastReportedAt: "2026-09-11T10:00:00Z", }}}, } + sb.Status.IngressAdmission = &types.SandboxIngressAdmission{Scope: types.IngressSharedHostLoopback, Ports: []uint32{8080}} fc.AddSandbox("default", sb) // Neither the seed object nor returned snapshots may mutate stored endpoints. + sb.Status.IngressAdmission.Ports[0] = 9090 sb.Status.EndpointStatuses[0].Host = "seed-changed.example.test" sb.Status.EndpointStatuses[0].Ports[0] = 80 sb.Status.EndpointStatuses[0].LastResult = types.EndpointHTTPResponseReceived @@ -220,6 +222,8 @@ func TestFakeClient_SandboxEndpointStatuses_DeepCopy(t *testing.T) { EndpointID: "endpoint-one", Host: "tools.example.test", Ports: []uint32{443, 8443}, Path: "/mcp", LastResult: types.EndpointTransportFailed, LastReportedAt: "2026-09-11T10:00:00Z", }}, got.Status.EndpointStatuses) + assert.Equal(t, []uint32{8080}, got.Status.IngressAdmission.Ports) + got.Status.IngressAdmission.Ports[0] = 9091 got.Status.EndpointStatuses[0].Path = "/changed" got.Status.EndpointStatuses[0].Ports[1] = 8080 got.Status.EndpointStatuses[0].LastReportedAt = "changed" @@ -227,6 +231,7 @@ func TestFakeClient_SandboxEndpointStatuses_DeepCopy(t *testing.T) { listed, err := fc.Sandboxes().ListAll(ctx, "default") require.NoError(t, err) require.Len(t, listed, 1) + assert.Equal(t, []uint32{8080}, listed[0].Status.IngressAdmission.Ports) assert.Equal(t, "/mcp", listed[0].Status.EndpointStatuses[0].Path) assert.Equal(t, []uint32{443, 8443}, listed[0].Status.EndpointStatuses[0].Ports) assert.Equal(t, "2026-09-11T10:00:00Z", listed[0].Status.EndpointStatuses[0].LastReportedAt) diff --git a/sdk/go/openshell/v1/fake/sandbox.go b/sdk/go/openshell/v1/fake/sandbox.go index 221e1f7524..775bef3064 100644 --- a/sdk/go/openshell/v1/fake/sandbox.go +++ b/sdk/go/openshell/v1/fake/sandbox.go @@ -234,6 +234,11 @@ func copySandboxStatus(s types.SandboxStatus) types.SandboxStatus { s.Conditions = conds } // Callers may mutate endpoint snapshots without changing the fake's storage. + if s.IngressAdmission != nil { + admission := *s.IngressAdmission + admission.Ports = slices.Clone(admission.Ports) + s.IngressAdmission = &admission + } s.EndpointStatuses = slices.Clone(s.EndpointStatuses) for i := range s.EndpointStatuses { s.EndpointStatuses[i].Ports = slices.Clone(s.EndpointStatuses[i].Ports) diff --git a/sdk/go/openshell/v1/internal/converter/coverage_test.go b/sdk/go/openshell/v1/internal/converter/coverage_test.go index 8a457d0014..5a9e3b87b8 100644 --- a/sdk/go/openshell/v1/internal/converter/coverage_test.go +++ b/sdk/go/openshell/v1/internal/converter/coverage_test.go @@ -126,6 +126,7 @@ func TestConverterCoversAllProtoFields_SandboxStatus(t *testing.T) { "current_policy_version": true, "exit_code": true, "configuration_admission": true, + "ingress_admission": true, "restart_count": true, "next_restart_time": true, "main_process_started_time": true, @@ -462,3 +463,7 @@ func assertAllFieldsCovered( } } } + +func TestConverterCoversAllProtoFields_SandboxIngressAdmission(t *testing.T) { + assertAllFieldsCovered(t, (&sandboxpb.SandboxIngressAdmission{}).ProtoReflect().Descriptor(), fieldSet{"scope": true, "all_ports": true, "ports": true}, nil) +} diff --git a/sdk/go/openshell/v1/internal/converter/sandbox.go b/sdk/go/openshell/v1/internal/converter/sandbox.go index e679fba176..362b9a2eea 100644 --- a/sdk/go/openshell/v1/internal/converter/sandbox.go +++ b/sdk/go/openshell/v1/internal/converter/sandbox.go @@ -11,6 +11,7 @@ import ( "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types" dm "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1" pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1" + sandboxpb "github.com/NVIDIA/OpenShell/sdk/go/proto/sandboxv1" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/structpb" ) @@ -132,6 +133,18 @@ func sandboxStatusFromProto(status *pb.SandboxStatus) types.SandboxStatus { Failure: endpointFailureFromProto(observation.GetFailure()), } } + if admission := status.GetIngressAdmission(); admission != nil { + scope := types.IngressUnknown + switch admission.GetScope() { + case sandboxpb.IngressScope_INGRESS_SCOPE_UNSUPPORTED: + scope = types.IngressUnsupported + case sandboxpb.IngressScope_INGRESS_SCOPE_ISOLATED_LOOPBACK: + scope = types.IngressIsolatedLoopback + case sandboxpb.IngressScope_INGRESS_SCOPE_SHARED_HOST_LOOPBACK: + scope = types.IngressSharedHostLoopback + } + result.IngressAdmission = &types.SandboxIngressAdmission{Scope: scope, AllPorts: admission.GetAllPorts(), Ports: slices.Clone(admission.GetPorts())} + } result.ExitCode = CopyInt32Ptr(status.ExitCode) if admission := status.GetConfigurationAdmission(); admission != nil { state := types.ConfigurationAdmissionUnknown diff --git a/sdk/go/openshell/v1/internal/converter/sandbox_test.go b/sdk/go/openshell/v1/internal/converter/sandbox_test.go index 756fd72338..8a7a3526e2 100644 --- a/sdk/go/openshell/v1/internal/converter/sandbox_test.go +++ b/sdk/go/openshell/v1/internal/converter/sandbox_test.go @@ -19,6 +19,21 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" ) +func TestSandboxIngressAdmissionFromProto(t *testing.T) { + for _, scope := range []sandboxpb.IngressScope{sandboxpb.IngressScope_INGRESS_SCOPE_ISOLATED_LOOPBACK, sandboxpb.IngressScope_INGRESS_SCOPE_SHARED_HOST_LOOPBACK, sandboxpb.IngressScope(99)} { + wire := &pb.SandboxStatus{IngressAdmission: &sandboxpb.SandboxIngressAdmission{Scope: scope, Ports: []uint32{8080}}} + got := sandboxStatusFromProto(wire).IngressAdmission + require.NotNil(t, got) + assert.Equal(t, []uint32{8080}, got.Ports) + if scope == sandboxpb.IngressScope(99) { + assert.Equal(t, v1.IngressUnknown, got.Scope) + } + wire.IngressAdmission.Ports[0] = 9090 + assert.Equal(t, uint32(8080), got.Ports[0]) + } + assert.Nil(t, sandboxStatusFromProto(&pb.SandboxStatus{}).IngressAdmission) +} + func TestSandboxConfigurationAdmissionFromProto(t *testing.T) { for _, tc := range []struct { wire pb.ConfigurationAdmissionState diff --git a/sdk/go/openshell/v1/options.go b/sdk/go/openshell/v1/options.go index 5d603552ea..bcb29e6e48 100644 --- a/sdk/go/openshell/v1/options.go +++ b/sdk/go/openshell/v1/options.go @@ -48,3 +48,6 @@ func listPageSize(opts []ListOptions) (int32, error) { } return int32(opts[0].PageSize), nil } + +// WithForwardPorts requests admission of target ports before creating a sandbox. +var WithForwardPorts = types.WithForwardPorts diff --git a/sdk/go/openshell/v1/sandbox_client.go b/sdk/go/openshell/v1/sandbox_client.go index 5d042b2101..3e36bfc65f 100644 --- a/sdk/go/openshell/v1/sandbox_client.go +++ b/sdk/go/openshell/v1/sandbox_client.go @@ -43,6 +43,7 @@ func (s *sandboxClient) Create(ctx context.Context, workspace, name string, spec Annotations: converter.CopyStringMap(cfg.Annotations()), WorkspaceScope: namedWorkspaceScope(workspace), ServiceExposures: serviceExposuresToProto(cfg.ServiceExposures()), + ForwardPorts: cfg.ForwardPorts(), } resp, err := s.client.CreateSandbox(ctx, req) if err != nil { @@ -75,6 +76,7 @@ func (s *sandboxClient) CreateFromTemplate(ctx context.Context, workspace, name, WorkspaceScope: namedWorkspaceScope(workspace), WorkloadTemplate: templateName, ServiceExposures: serviceExposuresToProto(cfg.ServiceExposures()), + ForwardPorts: cfg.ForwardPorts(), } resp, err := s.client.CreateSandbox(ctx, req) if err != nil { diff --git a/sdk/go/openshell/v1/sandbox_client_test.go b/sdk/go/openshell/v1/sandbox_client_test.go index 8e2e83b50d..cb91792ff5 100644 --- a/sdk/go/openshell/v1/sandbox_client_test.go +++ b/sdk/go/openshell/v1/sandbox_client_test.go @@ -342,6 +342,7 @@ func TestSandboxCreate(t *testing.T) { "my-sandbox", spec, WithLabels(labels), + WithForwardPorts(8080, 9090), WithServiceExposures( ServiceExposure{TargetPort: 4500}, ServiceExposure{ @@ -362,6 +363,7 @@ func TestSandboxCreate(t *testing.T) { "": "https://.example.test/", "metrics": "https://metrics.example.test/", }, result.ServiceURLs) + assert.Equal(t, []uint32{8080, 9090}, mock.createRequest.GetForwardPorts()) require.Len(t, mock.createRequest.GetServiceExposures(), 2) assert.Equal(t, uint32(4500), mock.createRequest.GetServiceExposures()[0].GetTargetPort()) assert.Equal(t, pb.ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_STRIP, mock.createRequest.GetServiceExposures()[0].GetAuthorizationMode()) diff --git a/sdk/go/openshell/v1/tcp_client.go b/sdk/go/openshell/v1/tcp_client.go index 010658e334..72d3b0f2df 100644 --- a/sdk/go/openshell/v1/tcp_client.go +++ b/sdk/go/openshell/v1/tcp_client.go @@ -8,9 +8,12 @@ import ( "fmt" "io" "net" + "slices" "strconv" "sync" + "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types" + "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/internal/converter" "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/internal/options" pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1" @@ -37,10 +40,20 @@ func (t *tcpClient) Forward(ctx context.Context, workspace, sandboxName string, Message: fmt.Sprintf("port must be in range 1-65535, got %d", port), } } - owner, err := sandboxOwner(ctx, t.sandboxes, workspace, sandboxName) + var sandbox *Sandbox + var owner string + var err error + if g, ok := t.sandboxes.(ownerGetter); ok { + sandbox, owner, err = g.getWithOwner(ctx, workspace, sandboxName) + } else { + sandbox, err = t.sandboxes.Get(ctx, workspace, sandboxName) + } if err != nil { return nil, err } + if err := admitSandboxIngress(sandbox.Status.IngressAdmission, port); err != nil { + return nil, err + } var cfg forwardConfig options.Apply(&cfg, opts) @@ -106,6 +119,14 @@ func (t *tcpClient) Listen(ctx context.Context, workspace, sandboxName string, r } } + sandbox, err := t.sandboxes.Get(ctx, workspace, sandboxName) + if err != nil { + return nil, err + } + if err := admitSandboxIngress(sandbox.Status.IngressAdmission, remotePort); err != nil { + return nil, err + } + addr := net.JoinHostPort(cfg.bindAddress, strconv.FormatUint(uint64(localPort), 10)) inner, err := net.Listen("tcp", addr) if err != nil { @@ -350,3 +371,21 @@ func (c *tcpForwardConn) Close() error { <-c.done return err } + +func admitSandboxIngress(admission *types.SandboxIngressAdmission, port uint32) error { + if admission == nil { + return nil + } // Explicit legacy absence from the gateway. + valid := admission.Scope == types.IngressIsolatedLoopback || admission.Scope == types.IngressSharedHostLoopback + seen := make(map[uint32]bool, len(admission.Ports)) + for _, admitted := range admission.Ports { + if admitted == 0 || admitted > 65535 || seen[admitted] { + valid = false + } + seen[admitted] = true + } + if !valid || (admission.AllPorts && len(admission.Ports) != 0) || (!admission.AllPorts && !slices.Contains(admission.Ports, port)) { + return &StatusError{Code: ErrorPermissionDenied, Message: "target port was not admitted by the compute driver"} + } + return nil +} diff --git a/sdk/go/openshell/v1/tcp_client_test.go b/sdk/go/openshell/v1/tcp_client_test.go index 46b0f586d9..fc493c5848 100644 --- a/sdk/go/openshell/v1/tcp_client_test.go +++ b/sdk/go/openshell/v1/tcp_client_test.go @@ -1130,16 +1130,17 @@ func TestTCPListen_TunnelFailureWithContextCancel(t *testing.T) { srv.Stop() }() - // Resolver always fails: Forward will error on every attempt. - resolver := &flippableResolver{ - failErr: &StatusError{Code: ErrorUnavailable, Message: "permanent failure"}, - } + // Admit the listener, then fail its per-connection tunnel setup. + resolver := &flippableResolver{} client := newTCPClient(conn, resolver, nil) ctx, cancel := context.WithCancel(context.Background()) ln, err := client.Listen(ctx, "default", "my-sandbox", 8080, 0) require.NoError(t, err) + resolver.mu.Lock() + resolver.failErr = &StatusError{Code: ErrorUnavailable, Message: "permanent failure"} + resolver.mu.Unlock() // Trigger a connection that will fail tunnel setup. c, err := net.Dial("tcp", ln.Addr().String()) @@ -1156,3 +1157,19 @@ func TestTCPListen_TunnelFailureWithContextCancel(t *testing.T) { return ln.Close() == nil }, 5*time.Second, 10*time.Millisecond) } + +func TestTCPIngressAdmissionBeforeForwardOrListen(t *testing.T) { + mock := newMockTCPServer() + client, cleanup := setupTCPTest(t, mock) + defer cleanup() + client.sandboxes = &stubSandboxResolver{ingressAdmission: &SandboxIngressAdmission{Scope: IngressSharedHostLoopback, Ports: []uint32{8080}}} + conn, err := client.Forward(context.Background(), "default", "sb", 9090) + require.Error(t, err) + assert.Nil(t, conn) + listener, err := client.Listen(context.Background(), "default", "sb", 9090, 0) + require.Error(t, err) + assert.Nil(t, listener) + mock.mu.Lock() + assert.Nil(t, mock.lastInit) + mock.mu.Unlock() +} diff --git a/sdk/go/openshell/v1/types.go b/sdk/go/openshell/v1/types.go index a09acd28fa..7f2a76a40c 100644 --- a/sdk/go/openshell/v1/types.go +++ b/sdk/go/openshell/v1/types.go @@ -57,3 +57,17 @@ const ( // TLSConfig holds TLS connection settings. type TLSConfig = types.TLSConfig + +// SandboxIngressAdmission describes the admitted target ports and network scope. +type SandboxIngressAdmission = types.SandboxIngressAdmission + +// IngressScope identifies the admitted loopback namespace. +type IngressScope = types.IngressScope + +// IngressScope values identify the admitted loopback namespace. +const ( + IngressUnknown = types.IngressUnknown + IngressUnsupported = types.IngressUnsupported + IngressIsolatedLoopback = types.IngressIsolatedLoopback + IngressSharedHostLoopback = types.IngressSharedHostLoopback +) diff --git a/sdk/go/openshell/v1/types/options.go b/sdk/go/openshell/v1/types/options.go index eccf21e979..6c336b48a6 100644 --- a/sdk/go/openshell/v1/types/options.go +++ b/sdk/go/openshell/v1/types/options.go @@ -4,6 +4,7 @@ package types import ( + "slices" "time" "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/internal/options" @@ -14,6 +15,7 @@ type createConfig struct { labels map[string]string annotations map[string]string serviceExposures []ServiceExposure + forwardPorts []uint32 } // CreateOption configures a Create call. @@ -105,3 +107,12 @@ type ExecOptions struct { // for automation and managed checks that need predictable startup behavior. NoLoginShell bool } + +// WithForwardPorts requests admission before sandbox creation. It does not open listeners. +func WithForwardPorts(ports ...uint32) CreateOption { + snapshot := slices.Clone(ports) + return func(c *createConfig) { c.forwardPorts = slices.Clone(snapshot) } +} + +// ForwardPorts returns the requested target ports. +func (c *createConfig) ForwardPorts() []uint32 { return slices.Clone(c.forwardPorts) } diff --git a/sdk/go/openshell/v1/types/sandbox.go b/sdk/go/openshell/v1/types/sandbox.go index f1cedb595f..bd04a16e80 100644 --- a/sdk/go/openshell/v1/types/sandbox.go +++ b/sdk/go/openshell/v1/types/sandbox.go @@ -115,6 +115,7 @@ type SandboxWorkloadTemplateProvenance struct { // SandboxStatus holds the observed state of a sandbox. type SandboxStatus struct { + IngressAdmission *SandboxIngressAdmission AgentPod string AgentFd string SandboxFd string @@ -276,3 +277,22 @@ type DetachProviderResult struct { Sandbox *Sandbox Detached bool } + +// IngressScope describes the network namespace of admitted service targets. +type IngressScope string + +// IngressScope values identify the admitted loopback namespace. +const ( + IngressUnknown IngressScope = "unknown" + IngressUnsupported IngressScope = "unsupported" + IngressIsolatedLoopback IngressScope = "isolated_loopback" + IngressSharedHostLoopback IngressScope = "shared_host_loopback" +) + +// SandboxIngressAdmission is the immutable compute-admitted forwarding envelope. +// Nil indicates legacy absence; Unknown never grants a target port. +type SandboxIngressAdmission struct { + Scope IngressScope + AllPorts bool + Ports []uint32 +} diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index 1ae1800784..a3f3ade193 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -3253,8 +3253,11 @@ type SandboxStatus struct { // failures before a configured endpoint or credential could be selected. // Matching grant success or a policy, provider, or supervisor reset clears it. LastTokenGrantFailure *TokenGrantFailureObservation `protobuf:"bytes,17,opt,name=last_token_grant_failure,json=lastTokenGrantFailure,proto3" json:"last_token_grant_failure,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Gateway-retained immutable compute-driver ingress admission. Absence is + // legacy behavior only when the selected driver has not negotiated ingress. + IngressAdmission *sandboxv1.SandboxIngressAdmission `protobuf:"bytes,19,opt,name=ingress_admission,json=ingressAdmission,proto3" json:"ingress_admission,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SandboxStatus) Reset() { @@ -3399,6 +3402,13 @@ func (x *SandboxStatus) GetLastTokenGrantFailure() *TokenGrantFailureObservation return nil } +func (x *SandboxStatus) GetIngressAdmission() *sandboxv1.SandboxIngressAdmission { + if x != nil { + return x.IngressAdmission + } + return nil +} + // User-facing sandbox condition derived from platform or gateway observations. type SandboxCondition struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -3598,8 +3608,11 @@ type CreateSandboxRequest struct { // registered after the sandbox has been persisted and route only while the // sandbox is ready. ServiceExposures []*SandboxServiceExposure `protobuf:"bytes,9,rep,name=service_exposures,json=serviceExposures,proto3" json:"service_exposures,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Requested local forward targets, checked before provisioning. This does + // not open a listener; clients establish the admitted forwards after create. + ForwardPorts []uint32 `protobuf:"varint,10,rep,packed,name=forward_ports,json=forwardPorts,proto3" json:"forward_ports,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CreateSandboxRequest) Reset() { @@ -3695,6 +3708,13 @@ func (x *CreateSandboxRequest) GetServiceExposures() []*SandboxServiceExposure { return nil } +func (x *CreateSandboxRequest) GetForwardPorts() []uint32 { + if x != nil { + return x.ForwardPorts + } + return nil +} + // Update selected configuration of a stopped sandbox. Omitted fields are unchanged. // Start explicitly after a successful update. With no fields selected, resume // the pending operation stored by the gateway using the current resource version. @@ -19881,7 +19901,7 @@ const file_openshell_proto_rawDesc = "" + "\tmax_burst\x18\x02 \x01(\rR\bmaxBurst\"b\n" + "!SandboxWorkloadTemplateProvenance\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12)\n" + - "\x10resource_version\x18\x02 \x01(\tR\x0fresourceVersion\"\xf2\a\n" + + "\x10resource_version\x18\x02 \x01(\tR\x0fresourceVersion\"\xce\b\n" + "\rSandboxStatus\x12\x1b\n" + "\tagent_pod\x18\x02 \x01(\tR\bagentPod\x12\x19\n" + "\bagent_fd\x18\x03 \x01(\tR\aagentFd\x12\x1d\n" + @@ -19902,7 +19922,8 @@ const file_openshell_proto_rawDesc = "" + "\rrestart_count\x18\x0e \x01(\rR\frestartCount\x12F\n" + "\x11next_restart_time\x18\x0f \x01(\v2\x1a.google.protobuf.TimestampR\x0fnextRestartTime\x12U\n" + "\x19main_process_started_time\x18\x10 \x01(\v2\x1a.google.protobuf.TimestampR\x16mainProcessStartedTime\x12c\n" + - "\x18last_token_grant_failure\x18\x11 \x01(\v2*.openshell.v1.TokenGrantFailureObservationR\x15lastTokenGrantFailureB\f\n" + + "\x18last_token_grant_failure\x18\x11 \x01(\v2*.openshell.v1.TokenGrantFailureObservationR\x15lastTokenGrantFailure\x12Z\n" + + "\x11ingress_admission\x18\x13 \x01(\v2-.openshell.sandbox.v1.SandboxIngressAdmissionR\x10ingressAdmissionB\f\n" + "\n" + "_exit_codeB\x1a\n" + "\x18_configuration_activated\"\xd1\x01\n" + @@ -19922,7 +19943,7 @@ const file_openshell_proto_rawDesc = "" + "\bmetadata\x18\x06 \x03(\v2).openshell.v1.PlatformEvent.MetadataEntryR\bmetadata\x1a;\n" + "\rMetadataEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01J\x04\b\x01\x10\x02R\ftimestamp_ms\"\xa9\x05\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01J\x04\b\x01\x10\x02R\ftimestamp_ms\"\xce\x05\n" + "\x14CreateSandboxRequest\x12R\n" + "\x0fworkspace_scope\x18\a \x01(\v2).openshell.datamodel.v1.WorkspaceSelectorR\x0eworkspaceScope\x12-\n" + "\x04spec\x18\x01 \x01(\v2\x19.openshell.v1.SandboxSpecR\x04spec\x12\x12\n" + @@ -19933,7 +19954,9 @@ const file_openshell_proto_rawDesc = "" + "\x11workload_template\x18\x06 \x01(\tR\x10workloadTemplate\x12\x1d\n" + "\n" + "request_id\x18\b \x01(\tR\trequestId\x12Q\n" + - "\x11service_exposures\x18\t \x03(\v2$.openshell.v1.SandboxServiceExposureR\x10serviceExposures\x1a9\n" + + "\x11service_exposures\x18\t \x03(\v2$.openshell.v1.SandboxServiceExposureR\x10serviceExposures\x12#\n" + + "\rforward_ports\x18\n" + + " \x03(\rR\fforwardPorts\x1a9\n" + "\vLabelsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a>\n" + @@ -21883,21 +21906,22 @@ var file_openshell_proto_goTypes = []any{ (*sandboxv1.SandboxPolicy)(nil), // 305: openshell.sandbox.v1.SandboxPolicy (*structpb.Struct)(nil), // 306: google.protobuf.Struct (*durationpb.Duration)(nil), // 307: google.protobuf.Duration - (*datamodelv1.WorkspaceSelector)(nil), // 308: openshell.datamodel.v1.WorkspaceSelector - (*datamodelv1.Provider)(nil), // 309: openshell.datamodel.v1.Provider - (sandboxv1.PolicySource)(0), // 310: openshell.sandbox.v1.PolicySource - (*sandboxv1.NetworkEndpoint)(nil), // 311: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 312: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 313: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 314: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 315: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 316: openshell.sandbox.v1.L7Rule - (*sandboxv1.SandboxConfigSnapshot)(nil), // 317: openshell.sandbox.v1.SandboxConfigSnapshot - (*datamodelv1.Workspace)(nil), // 318: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 319: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 320: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 321: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 322: openshell.sandbox.v1.GetGatewayConfigResponse + (*sandboxv1.SandboxIngressAdmission)(nil), // 308: openshell.sandbox.v1.SandboxIngressAdmission + (*datamodelv1.WorkspaceSelector)(nil), // 309: openshell.datamodel.v1.WorkspaceSelector + (*datamodelv1.Provider)(nil), // 310: openshell.datamodel.v1.Provider + (sandboxv1.PolicySource)(0), // 311: openshell.sandbox.v1.PolicySource + (*sandboxv1.NetworkEndpoint)(nil), // 312: openshell.sandbox.v1.NetworkEndpoint + (*sandboxv1.NetworkBinary)(nil), // 313: openshell.sandbox.v1.NetworkBinary + (*sandboxv1.SettingValue)(nil), // 314: openshell.sandbox.v1.SettingValue + (*sandboxv1.NetworkPolicyRule)(nil), // 315: openshell.sandbox.v1.NetworkPolicyRule + (*sandboxv1.L7DenyRule)(nil), // 316: openshell.sandbox.v1.L7DenyRule + (*sandboxv1.L7Rule)(nil), // 317: openshell.sandbox.v1.L7Rule + (*sandboxv1.SandboxConfigSnapshot)(nil), // 318: openshell.sandbox.v1.SandboxConfigSnapshot + (*datamodelv1.Workspace)(nil), // 319: openshell.datamodel.v1.Workspace + (*sandboxv1.GetSandboxConfigRequest)(nil), // 320: openshell.sandbox.v1.GetSandboxConfigRequest + (*sandboxv1.GetGatewayConfigRequest)(nil), // 321: openshell.sandbox.v1.GetGatewayConfigRequest + (*sandboxv1.GetSandboxConfigResponse)(nil), // 322: openshell.sandbox.v1.GetSandboxConfigResponse + (*sandboxv1.GetGatewayConfigResponse)(nil), // 323: openshell.sandbox.v1.GetGatewayConfigResponse } var file_openshell_proto_depIdxs = []int32{ 303, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp @@ -21947,505 +21971,506 @@ var file_openshell_proto_depIdxs = []int32{ 303, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp 303, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp 270, // 46: openshell.v1.SandboxStatus.last_token_grant_failure:type_name -> openshell.v1.TokenGrantFailureObservation - 303, // 47: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp - 303, // 48: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp - 281, // 49: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 308, // 50: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 40, // 51: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 282, // 52: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 283, // 53: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 274, // 54: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure - 308, // 55: openshell.v1.UpdateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 56, // 56: openshell.v1.UpdateSandboxRequest.command:type_name -> openshell.v1.SandboxCommandUpdate - 57, // 57: openshell.v1.UpdateSandboxRequest.environment:type_name -> openshell.v1.SandboxMapUpdate - 57, // 58: openshell.v1.UpdateSandboxRequest.labels:type_name -> openshell.v1.SandboxMapUpdate - 57, // 59: openshell.v1.UpdateSandboxRequest.annotations:type_name -> openshell.v1.SandboxMapUpdate - 284, // 60: openshell.v1.SandboxMapUpdate.values:type_name -> openshell.v1.SandboxMapUpdate.ValuesEntry - 308, // 61: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 44, // 62: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 308, // 63: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 64: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 65: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 44, // 66: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 44, // 67: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate - 18, // 68: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 308, // 69: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 303, // 70: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp - 308, // 71: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 72: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 73: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 74: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 75: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 76: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 77: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 78: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 79: openshell.v1.SuspendSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 80: openshell.v1.ResumeSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 39, // 81: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 285, // 82: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry - 39, // 83: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 309, // 84: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 39, // 85: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 86, // 86: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 39, // 87: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 86, // 88: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 84, // 89: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision - 82, // 90: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity - 310, // 91: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource - 5, // 92: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent - 83, // 93: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision - 7, // 94: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState - 6, // 95: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 303, // 96: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp - 303, // 97: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp - 303, // 98: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp - 2, // 99: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind - 82, // 100: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity - 303, // 101: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp - 4, // 102: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason - 86, // 103: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 3, // 104: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState - 4, // 105: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason - 87, // 106: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation - 303, // 107: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp - 303, // 108: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp - 85, // 109: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation - 308, // 110: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 88, // 111: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus - 87, // 112: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation - 307, // 113: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration - 307, // 114: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration - 18, // 115: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 308, // 116: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 303, // 117: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp - 308, // 118: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 20, // 119: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 308, // 120: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 121: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 103, // 122: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 308, // 123: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 124: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 304, // 125: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 20, // 126: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 102, // 127: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint - 18, // 128: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 308, // 129: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 286, // 130: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 307, // 131: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration - 107, // 132: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout - 108, // 133: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr - 109, // 134: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 213, // 135: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 214, // 136: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget - 111, // 137: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit - 106, // 138: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest - 114, // 139: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 304, // 140: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 303, // 141: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp - 308, // 142: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 303, // 143: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp - 39, // 144: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox - 118, // 145: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine - 53, // 146: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent - 119, // 147: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 230, // 148: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 303, // 149: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp - 287, // 150: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 308, // 151: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 309, // 152: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 308, // 153: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 154: openshell.v1.GetProviderCredentialsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 307, // 155: openshell.v1.GetProviderCredentialsRequest.minimum_remaining_lifetime:type_name -> google.protobuf.Duration - 303, // 156: openshell.v1.ProviderCredentialValue.expiration_time:type_name -> google.protobuf.Timestamp - 288, // 157: openshell.v1.GetProviderCredentialsResponse.credentials:type_name -> openshell.v1.GetProviderCredentialsResponse.CredentialsEntry - 308, // 158: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 159: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 309, // 160: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 289, // 161: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - 308, // 162: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 309, // 163: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider - 86, // 164: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt - 309, // 165: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 308, // 166: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 167: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 151, // 168: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 307, // 169: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration - 134, // 170: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride - 8, // 171: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType - 135, // 172: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken - 140, // 173: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh - 136, // 174: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant - 9, // 175: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 307, // 176: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration - 307, // 177: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration - 138, // 178: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial - 139, // 179: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput - 9, // 180: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 303, // 181: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp - 303, // 182: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp - 303, // 183: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp - 16, // 184: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 303, // 185: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp - 308, // 186: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 141, // 187: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 308, // 188: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 9, // 189: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 290, // 190: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 303, // 191: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp - 141, // 192: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 308, // 193: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 141, // 194: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 308, // 195: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 196: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 10, // 197: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory - 137, // 198: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 311, // 199: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 312, // 200: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 142, // 201: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 291, // 202: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 152, // 203: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile - 151, // 204: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 151, // 205: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 308, // 206: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 132, // 207: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 133, // 208: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 151, // 209: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 308, // 210: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 132, // 211: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 133, // 212: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 151, // 213: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 308, // 214: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 132, // 215: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 133, // 216: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 18, // 217: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 308, // 218: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 219: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 165, // 220: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 292, // 221: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 293, // 222: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - 294, // 223: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 295, // 224: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 4, // 225: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 296, // 226: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - 11, // 227: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification - 166, // 228: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding - 303, // 229: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp - 168, // 230: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue - 297, // 231: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry - 4, // 232: openshell.v1.ProviderEnvironmentSnapshot.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 298, // 233: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - 307, // 234: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration - 308, // 235: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 236: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 313, // 237: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 173, // 238: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 299, // 239: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 174, // 240: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 175, // 241: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 176, // 242: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 178, // 243: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 179, // 244: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 180, // 245: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 314, // 246: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 312, // 247: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 315, // 248: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 177, // 249: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget - 316, // 250: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 177, // 251: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget - 300, // 252: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 308, // 253: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 191, // 254: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 308, // 255: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 191, // 256: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 13, // 257: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 12, // 258: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState - 188, // 259: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 13, // 260: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 303, // 261: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp - 303, // 262: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp - 305, // 263: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 301, // 264: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 308, // 265: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 303, // 266: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp - 118, // 267: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 118, // 268: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 198, // 269: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 206, // 270: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 223, // 271: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 224, // 272: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 202, // 273: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult - 199, // 274: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 204, // 275: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 207, // 276: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 212, // 277: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 224, // 278: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 205, // 279: openshell.v1.GatewayMessage.session_redirect:type_name -> openshell.v1.SessionRedirect - 200, // 280: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate - 200, // 281: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigUpdate - 307, // 282: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration - 317, // 283: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot - 169, // 284: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot - 6, // 285: openshell.v1.ConfigUpdateResult.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 201, // 286: openshell.v1.ConfigUpdateResult.failure:type_name -> openshell.v1.ConfigApplyFailure - 188, // 287: openshell.v1.ConfigUpdateResult.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 203, // 288: openshell.v1.ConfigUpdateResult.policy_load:type_name -> openshell.v1.PolicyLoadResult - 213, // 289: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 214, // 290: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 215, // 291: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 212, // 292: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen - 217, // 293: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit - 219, // 294: openshell.v1.PeerNotifyConfigUpdateRequest.sandbox:type_name -> openshell.v1.PeerConfigSandboxTarget - 220, // 295: openshell.v1.PeerNotifyConfigUpdateRequest.provider:type_name -> openshell.v1.PeerConfigProviderTarget - 303, // 296: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp - 303, // 297: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp - 225, // 298: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 227, // 299: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 314, // 300: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 303, // 301: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp - 303, // 302: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp - 303, // 303: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp - 303, // 304: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp - 305, // 305: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 305, // 306: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 308, // 307: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 226, // 308: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 229, // 309: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 228, // 310: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 308, // 311: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 229, // 312: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 303, // 313: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp - 308, // 314: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 315: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 316: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 239, // 317: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval - 308, // 318: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 314, // 319: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 308, // 320: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 321: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 322: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 303, // 323: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp - 249, // 324: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 302, // 325: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 318, // 326: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 318, // 327: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 318, // 328: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 18, // 329: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 304, // 330: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 15, // 331: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 308, // 332: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 15, // 333: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 259, // 334: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 308, // 335: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 336: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 308, // 337: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 259, // 338: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 303, // 339: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp - 19, // 340: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult - 275, // 341: openshell.v1.EndpointObservation.failure:type_name -> openshell.v1.EndpointFailure - 267, // 342: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation - 269, // 343: openshell.v1.ReportEndpointStatusRequest.token_grant_status:type_name -> openshell.v1.TokenGrantStatus - 270, // 344: openshell.v1.TokenGrantStatus.last_failure:type_name -> openshell.v1.TokenGrantFailureObservation - 275, // 345: openshell.v1.TokenGrantFailureObservation.failure:type_name -> openshell.v1.EndpointFailure - 19, // 346: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult - 303, // 347: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp - 275, // 348: openshell.v1.EndpointStatus.last_failure:type_name -> openshell.v1.EndpointFailure - 303, // 349: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp - 303, // 350: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp - 303, // 351: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp - 303, // 352: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp - 303, // 353: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp - 303, // 354: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp - 303, // 355: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp - 303, // 356: openshell.v1.SandboxProvisioning.preparation_deadline:type_name -> google.protobuf.Timestamp - 303, // 357: openshell.v1.SandboxProvisioning.admission_start_time:type_name -> google.protobuf.Timestamp - 20, // 358: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 21, // 359: openshell.v1.EndpointFailure.domain:type_name -> openshell.v1.EndpointFailureDomain - 16, // 360: openshell.v1.EndpointFailure.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 123, // 361: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry.value:type_name -> openshell.v1.ProviderCredentialValue - 303, // 362: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 303, // 363: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 137, // 364: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 166, // 365: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 137, // 366: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 26, // 367: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 28, // 368: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 30, // 369: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 54, // 370: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 65, // 371: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest - 67, // 372: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 68, // 373: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 58, // 374: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 59, // 375: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 60, // 376: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 61, // 377: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 69, // 378: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 70, // 379: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 71, // 380: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 89, // 381: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 72, // 382: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 73, // 383: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 74, // 384: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 75, // 385: openshell.v1.OpenShell.SuspendSandbox:input_type -> openshell.v1.SuspendSandboxRequest - 76, // 386: openshell.v1.OpenShell.ResumeSandbox:input_type -> openshell.v1.ResumeSandboxRequest - 94, // 387: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 96, // 388: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 97, // 389: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 98, // 390: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 100, // 391: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 104, // 392: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 106, // 393: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 112, // 394: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 113, // 395: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 120, // 396: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 121, // 397: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 122, // 398: openshell.v1.OpenShell.GetProviderCredentials:input_type -> openshell.v1.GetProviderCredentialsRequest - 125, // 399: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 130, // 400: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 131, // 401: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 155, // 402: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 157, // 403: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 159, // 404: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 126, // 405: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 143, // 406: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 145, // 407: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 147, // 408: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 149, // 409: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 127, // 410: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 162, // 411: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 319, // 412: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 320, // 413: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 172, // 414: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 182, // 415: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 184, // 416: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 186, // 417: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 268, // 418: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 91, // 419: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 189, // 420: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest - 164, // 421: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 170, // 422: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest - 192, // 423: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 193, // 424: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 196, // 425: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 208, // 426: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest - 210, // 427: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest - 216, // 428: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 218, // 429: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame - 91, // 430: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 268, // 431: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 89, // 432: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 221, // 433: openshell.v1.OpenShell.PeerNotifyConfigUpdate:input_type -> openshell.v1.PeerNotifyConfigUpdateRequest - 116, // 434: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 231, // 435: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 233, // 436: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 235, // 437: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 237, // 438: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 240, // 439: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 242, // 440: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 244, // 441: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 246, // 442: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 248, // 443: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 22, // 444: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 24, // 445: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 251, // 446: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 253, // 447: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 255, // 448: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 257, // 449: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 260, // 450: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 262, // 451: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 264, // 452: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 55, // 453: openshell.v1.SandboxUpdates.UpdateSandbox:input_type -> openshell.v1.UpdateSandboxRequest - 27, // 454: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 29, // 455: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 31, // 456: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 77, // 457: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 66, // 458: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse - 77, // 459: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 78, // 460: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 62, // 461: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 62, // 462: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 63, // 463: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 64, // 464: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 79, // 465: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 80, // 466: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 81, // 467: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 90, // 468: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 93, // 469: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 77, // 470: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 77, // 471: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 77, // 472: openshell.v1.OpenShell.SuspendSandbox:output_type -> openshell.v1.SandboxResponse - 77, // 473: openshell.v1.OpenShell.ResumeSandbox:output_type -> openshell.v1.SandboxResponse - 95, // 474: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 103, // 475: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 103, // 476: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 99, // 477: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 101, // 478: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 105, // 479: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 110, // 480: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 112, // 481: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 110, // 482: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 128, // 483: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 128, // 484: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 124, // 485: openshell.v1.OpenShell.GetProviderCredentials:output_type -> openshell.v1.GetProviderCredentialsResponse - 129, // 486: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 154, // 487: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 153, // 488: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 156, // 489: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 158, // 490: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 160, // 491: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 128, // 492: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 144, // 493: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 146, // 494: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 148, // 495: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 150, // 496: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 161, // 497: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 163, // 498: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 321, // 499: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 322, // 500: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 181, // 501: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 183, // 502: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 185, // 503: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 187, // 504: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 271, // 505: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 92, // 506: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 190, // 507: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse - 167, // 508: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 171, // 509: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse - 195, // 510: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 194, // 511: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 197, // 512: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 209, // 513: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse - 211, // 514: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse - 216, // 515: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 218, // 516: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame - 92, // 517: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 271, // 518: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 90, // 519: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 222, // 520: openshell.v1.OpenShell.PeerNotifyConfigUpdate:output_type -> openshell.v1.PeerNotifyConfigUpdateResponse - 117, // 521: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 232, // 522: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 234, // 523: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 236, // 524: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 238, // 525: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 241, // 526: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 243, // 527: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 245, // 528: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 247, // 529: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 250, // 530: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 23, // 531: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 25, // 532: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 252, // 533: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 254, // 534: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 256, // 535: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 258, // 536: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 261, // 537: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 263, // 538: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 265, // 539: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 77, // 540: openshell.v1.SandboxUpdates.UpdateSandbox:output_type -> openshell.v1.SandboxResponse - 454, // [454:541] is the sub-list for method output_type - 367, // [367:454] is the sub-list for method input_type - 367, // [367:367] is the sub-list for extension type_name - 367, // [367:367] is the sub-list for extension extendee - 0, // [0:367] is the sub-list for field type_name + 308, // 47: openshell.v1.SandboxStatus.ingress_admission:type_name -> openshell.sandbox.v1.SandboxIngressAdmission + 303, // 48: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp + 303, // 49: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp + 281, // 50: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 309, // 51: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 40, // 52: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec + 282, // 53: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 283, // 54: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 274, // 55: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure + 309, // 56: openshell.v1.UpdateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 56, // 57: openshell.v1.UpdateSandboxRequest.command:type_name -> openshell.v1.SandboxCommandUpdate + 57, // 58: openshell.v1.UpdateSandboxRequest.environment:type_name -> openshell.v1.SandboxMapUpdate + 57, // 59: openshell.v1.UpdateSandboxRequest.labels:type_name -> openshell.v1.SandboxMapUpdate + 57, // 60: openshell.v1.UpdateSandboxRequest.annotations:type_name -> openshell.v1.SandboxMapUpdate + 284, // 61: openshell.v1.SandboxMapUpdate.values:type_name -> openshell.v1.SandboxMapUpdate.ValuesEntry + 309, // 62: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 44, // 63: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 309, // 64: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 65: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 66: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 44, // 67: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 44, // 68: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate + 18, // 69: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 309, // 70: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 303, // 71: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp + 309, // 72: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 73: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 74: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 75: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 76: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 77: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 78: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 79: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 80: openshell.v1.SuspendSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 81: openshell.v1.ResumeSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 39, // 82: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox + 285, // 83: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry + 39, // 84: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox + 310, // 85: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 39, // 86: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 86, // 87: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 39, // 88: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 86, // 89: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 84, // 90: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision + 82, // 91: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity + 311, // 92: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 5, // 93: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent + 83, // 94: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision + 7, // 95: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState + 6, // 96: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome + 303, // 97: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp + 303, // 98: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp + 303, // 99: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp + 2, // 100: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind + 82, // 101: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity + 303, // 102: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp + 4, // 103: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason + 86, // 104: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 3, // 105: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState + 4, // 106: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason + 87, // 107: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation + 303, // 108: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp + 303, // 109: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp + 85, // 110: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation + 309, // 111: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 88, // 112: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus + 87, // 113: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation + 307, // 114: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration + 307, // 115: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration + 18, // 116: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 309, // 117: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 303, // 118: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp + 309, // 119: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 20, // 120: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 309, // 121: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 122: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 103, // 123: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse + 309, // 124: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 125: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 304, // 126: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 20, // 127: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 102, // 128: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint + 18, // 129: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 309, // 130: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 286, // 131: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 307, // 132: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration + 107, // 133: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout + 108, // 134: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr + 109, // 135: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit + 213, // 136: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget + 214, // 137: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget + 111, // 138: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit + 106, // 139: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest + 114, // 140: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize + 304, // 141: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 303, // 142: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp + 309, // 143: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 303, // 144: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp + 39, // 145: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox + 118, // 146: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine + 53, // 147: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent + 119, // 148: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning + 230, // 149: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 303, // 150: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp + 287, // 151: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 309, // 152: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 310, // 153: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 309, // 154: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 155: openshell.v1.GetProviderCredentialsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 307, // 156: openshell.v1.GetProviderCredentialsRequest.minimum_remaining_lifetime:type_name -> google.protobuf.Duration + 303, // 157: openshell.v1.ProviderCredentialValue.expiration_time:type_name -> google.protobuf.Timestamp + 288, // 158: openshell.v1.GetProviderCredentialsResponse.credentials:type_name -> openshell.v1.GetProviderCredentialsResponse.CredentialsEntry + 309, // 159: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 160: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 310, // 161: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 289, // 162: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + 309, // 163: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 310, // 164: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 86, // 165: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt + 310, // 166: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 309, // 167: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 168: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 151, // 169: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile + 307, // 170: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration + 134, // 171: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride + 8, // 172: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType + 135, // 173: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken + 140, // 174: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh + 136, // 175: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant + 9, // 176: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 307, // 177: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration + 307, // 178: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration + 138, // 179: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial + 139, // 180: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput + 9, // 181: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 303, // 182: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp + 303, // 183: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp + 303, // 184: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp + 16, // 185: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 303, // 186: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp + 309, // 187: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 141, // 188: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 309, // 189: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 9, // 190: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 290, // 191: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 303, // 192: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp + 141, // 193: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 309, // 194: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 141, // 195: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 309, // 196: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 197: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 10, // 198: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory + 137, // 199: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential + 312, // 200: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 313, // 201: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 142, // 202: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery + 291, // 203: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 152, // 204: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile + 151, // 205: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile + 151, // 206: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 309, // 207: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 132, // 208: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 133, // 209: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 151, // 210: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 309, // 211: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 132, // 212: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem + 133, // 213: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 151, // 214: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile + 309, // 215: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 132, // 216: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 133, // 217: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 18, // 218: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 309, // 219: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 220: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 165, // 221: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding + 292, // 222: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 293, // 223: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + 294, // 224: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 295, // 225: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 4, // 226: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason + 296, // 227: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + 11, // 228: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification + 166, // 229: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding + 303, // 230: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp + 168, // 231: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue + 297, // 232: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + 4, // 233: openshell.v1.ProviderEnvironmentSnapshot.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason + 298, // 234: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry + 307, // 235: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration + 309, // 236: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 237: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 314, // 238: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 173, // 239: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation + 299, // 240: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 174, // 241: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule + 175, // 242: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint + 176, // 243: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule + 178, // 244: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules + 179, // 245: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules + 180, // 246: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary + 315, // 247: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 313, // 248: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 316, // 249: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 177, // 250: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget + 317, // 251: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 177, // 252: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget + 300, // 253: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 309, // 254: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 191, // 255: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 309, // 256: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 191, // 257: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 13, // 258: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 12, // 259: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState + 188, // 260: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 13, // 261: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 303, // 262: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp + 303, // 263: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp + 305, // 264: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 301, // 265: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 309, // 266: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 303, // 267: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp + 118, // 268: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 118, // 269: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 198, // 270: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello + 206, // 271: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat + 223, // 272: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 224, // 273: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 202, // 274: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult + 199, // 275: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted + 204, // 276: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected + 207, // 277: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat + 212, // 278: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen + 224, // 279: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 205, // 280: openshell.v1.GatewayMessage.session_redirect:type_name -> openshell.v1.SessionRedirect + 200, // 281: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate + 200, // 282: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigUpdate + 307, // 283: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration + 318, // 284: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot + 169, // 285: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot + 6, // 286: openshell.v1.ConfigUpdateResult.outcome:type_name -> openshell.v1.ConfigApplyOutcome + 201, // 287: openshell.v1.ConfigUpdateResult.failure:type_name -> openshell.v1.ConfigApplyFailure + 188, // 288: openshell.v1.ConfigUpdateResult.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 203, // 289: openshell.v1.ConfigUpdateResult.policy_load:type_name -> openshell.v1.PolicyLoadResult + 213, // 290: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget + 214, // 291: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget + 215, // 292: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit + 212, // 293: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen + 217, // 294: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit + 219, // 295: openshell.v1.PeerNotifyConfigUpdateRequest.sandbox:type_name -> openshell.v1.PeerConfigSandboxTarget + 220, // 296: openshell.v1.PeerNotifyConfigUpdateRequest.provider:type_name -> openshell.v1.PeerConfigProviderTarget + 303, // 297: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp + 303, // 298: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp + 225, // 299: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 227, // 300: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 315, // 301: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 303, // 302: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp + 303, // 303: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp + 303, // 304: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp + 303, // 305: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp + 305, // 306: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 305, // 307: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 309, // 308: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 226, // 309: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 229, // 310: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 228, // 311: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 309, // 312: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 229, // 313: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 303, // 314: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp + 309, // 315: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 316: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 317: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 239, // 318: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval + 309, // 319: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 315, // 320: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 309, // 321: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 322: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 309, // 323: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 303, // 324: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp + 249, // 325: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 302, // 326: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 319, // 327: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 319, // 328: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 319, // 329: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 18, // 330: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 304, // 331: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 15, // 332: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 309, // 333: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 15, // 334: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 259, // 335: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 309, // 336: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 337: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 309, // 338: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 259, // 339: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 303, // 340: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp + 19, // 341: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult + 275, // 342: openshell.v1.EndpointObservation.failure:type_name -> openshell.v1.EndpointFailure + 267, // 343: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation + 269, // 344: openshell.v1.ReportEndpointStatusRequest.token_grant_status:type_name -> openshell.v1.TokenGrantStatus + 270, // 345: openshell.v1.TokenGrantStatus.last_failure:type_name -> openshell.v1.TokenGrantFailureObservation + 275, // 346: openshell.v1.TokenGrantFailureObservation.failure:type_name -> openshell.v1.EndpointFailure + 19, // 347: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult + 303, // 348: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp + 275, // 349: openshell.v1.EndpointStatus.last_failure:type_name -> openshell.v1.EndpointFailure + 303, // 350: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp + 303, // 351: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp + 303, // 352: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp + 303, // 353: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp + 303, // 354: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp + 303, // 355: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp + 303, // 356: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp + 303, // 357: openshell.v1.SandboxProvisioning.preparation_deadline:type_name -> google.protobuf.Timestamp + 303, // 358: openshell.v1.SandboxProvisioning.admission_start_time:type_name -> google.protobuf.Timestamp + 20, // 359: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 21, // 360: openshell.v1.EndpointFailure.domain:type_name -> openshell.v1.EndpointFailureDomain + 16, // 361: openshell.v1.EndpointFailure.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 123, // 362: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry.value:type_name -> openshell.v1.ProviderCredentialValue + 303, // 363: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 303, // 364: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 137, // 365: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 166, // 366: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 137, // 367: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 26, // 368: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 28, // 369: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 30, // 370: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 54, // 371: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 65, // 372: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest + 67, // 373: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 68, // 374: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 58, // 375: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 59, // 376: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 60, // 377: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 61, // 378: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 69, // 379: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 70, // 380: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 71, // 381: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 89, // 382: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 72, // 383: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 73, // 384: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 74, // 385: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 75, // 386: openshell.v1.OpenShell.SuspendSandbox:input_type -> openshell.v1.SuspendSandboxRequest + 76, // 387: openshell.v1.OpenShell.ResumeSandbox:input_type -> openshell.v1.ResumeSandboxRequest + 94, // 388: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 96, // 389: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 97, // 390: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 98, // 391: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 100, // 392: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 104, // 393: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 106, // 394: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 112, // 395: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 113, // 396: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 120, // 397: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 121, // 398: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 122, // 399: openshell.v1.OpenShell.GetProviderCredentials:input_type -> openshell.v1.GetProviderCredentialsRequest + 125, // 400: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 130, // 401: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 131, // 402: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 155, // 403: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 157, // 404: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 159, // 405: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 126, // 406: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 143, // 407: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 145, // 408: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 147, // 409: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 149, // 410: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 127, // 411: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 162, // 412: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 320, // 413: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 321, // 414: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 172, // 415: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 182, // 416: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 184, // 417: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 186, // 418: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 268, // 419: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 91, // 420: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 189, // 421: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest + 164, // 422: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 170, // 423: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest + 192, // 424: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 193, // 425: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 196, // 426: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 208, // 427: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest + 210, // 428: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest + 216, // 429: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 218, // 430: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame + 91, // 431: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 268, // 432: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 89, // 433: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 221, // 434: openshell.v1.OpenShell.PeerNotifyConfigUpdate:input_type -> openshell.v1.PeerNotifyConfigUpdateRequest + 116, // 435: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 231, // 436: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 233, // 437: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 235, // 438: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 237, // 439: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 240, // 440: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 242, // 441: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 244, // 442: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 246, // 443: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 248, // 444: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 22, // 445: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 24, // 446: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 251, // 447: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 253, // 448: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 255, // 449: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 257, // 450: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 260, // 451: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 262, // 452: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 264, // 453: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 55, // 454: openshell.v1.SandboxUpdates.UpdateSandbox:input_type -> openshell.v1.UpdateSandboxRequest + 27, // 455: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 29, // 456: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 31, // 457: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 77, // 458: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 66, // 459: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse + 77, // 460: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 78, // 461: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 62, // 462: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 62, // 463: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 63, // 464: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 64, // 465: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 79, // 466: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 80, // 467: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 81, // 468: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 90, // 469: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 93, // 470: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 77, // 471: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 77, // 472: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 77, // 473: openshell.v1.OpenShell.SuspendSandbox:output_type -> openshell.v1.SandboxResponse + 77, // 474: openshell.v1.OpenShell.ResumeSandbox:output_type -> openshell.v1.SandboxResponse + 95, // 475: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 103, // 476: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 103, // 477: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 99, // 478: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 101, // 479: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 105, // 480: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 110, // 481: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 112, // 482: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 110, // 483: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 128, // 484: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 128, // 485: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 124, // 486: openshell.v1.OpenShell.GetProviderCredentials:output_type -> openshell.v1.GetProviderCredentialsResponse + 129, // 487: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 154, // 488: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 153, // 489: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 156, // 490: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 158, // 491: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 160, // 492: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 128, // 493: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 144, // 494: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 146, // 495: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 148, // 496: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 150, // 497: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 161, // 498: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 163, // 499: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 322, // 500: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 323, // 501: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 181, // 502: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 183, // 503: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 185, // 504: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 187, // 505: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 271, // 506: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 92, // 507: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 190, // 508: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse + 167, // 509: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 171, // 510: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse + 195, // 511: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 194, // 512: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 197, // 513: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 209, // 514: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse + 211, // 515: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse + 216, // 516: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 218, // 517: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame + 92, // 518: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 271, // 519: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 90, // 520: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 222, // 521: openshell.v1.OpenShell.PeerNotifyConfigUpdate:output_type -> openshell.v1.PeerNotifyConfigUpdateResponse + 117, // 522: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 232, // 523: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 234, // 524: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 236, // 525: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 238, // 526: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 241, // 527: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 243, // 528: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 245, // 529: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 247, // 530: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 250, // 531: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 23, // 532: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 25, // 533: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 252, // 534: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 254, // 535: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 256, // 536: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 258, // 537: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 261, // 538: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 263, // 539: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 265, // 540: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 77, // 541: openshell.v1.SandboxUpdates.UpdateSandbox:output_type -> openshell.v1.SandboxResponse + 455, // [455:542] is the sub-list for method output_type + 368, // [368:455] is the sub-list for method input_type + 368, // [368:368] is the sub-list for extension type_name + 368, // [368:368] is the sub-list for extension extendee + 0, // [0:368] is the sub-list for field type_name } func init() { file_openshell_proto_init() } diff --git a/sdk/go/proto/sandboxv1/sandbox.pb.go b/sdk/go/proto/sandboxv1/sandbox.pb.go index 045e15fac5..410aa4f6db 100644 --- a/sdk/go/proto/sandboxv1/sandbox.pb.go +++ b/sdk/go/proto/sandboxv1/sandbox.pb.go @@ -27,6 +27,59 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type IngressScope int32 + +const ( + IngressScope_INGRESS_SCOPE_UNSPECIFIED IngressScope = 0 + IngressScope_INGRESS_SCOPE_UNSUPPORTED IngressScope = 1 + IngressScope_INGRESS_SCOPE_ISOLATED_LOOPBACK IngressScope = 2 + // The driver has admitted its operator-controlled shared-host opt-in. + IngressScope_INGRESS_SCOPE_SHARED_HOST_LOOPBACK IngressScope = 3 +) + +// Enum value maps for IngressScope. +var ( + IngressScope_name = map[int32]string{ + 0: "INGRESS_SCOPE_UNSPECIFIED", + 1: "INGRESS_SCOPE_UNSUPPORTED", + 2: "INGRESS_SCOPE_ISOLATED_LOOPBACK", + 3: "INGRESS_SCOPE_SHARED_HOST_LOOPBACK", + } + IngressScope_value = map[string]int32{ + "INGRESS_SCOPE_UNSPECIFIED": 0, + "INGRESS_SCOPE_UNSUPPORTED": 1, + "INGRESS_SCOPE_ISOLATED_LOOPBACK": 2, + "INGRESS_SCOPE_SHARED_HOST_LOOPBACK": 3, + } +) + +func (x IngressScope) Enum() *IngressScope { + p := new(IngressScope) + *p = x + return p +} + +func (x IngressScope) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (IngressScope) Descriptor() protoreflect.EnumDescriptor { + return file_sandbox_proto_enumTypes[0].Descriptor() +} + +func (IngressScope) Type() protoreflect.EnumType { + return &file_sandbox_proto_enumTypes[0] +} + +func (x IngressScope) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use IngressScope.Descriptor instead. +func (IngressScope) EnumDescriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{0} +} + // TLS handling for a network endpoint. type NetworkTlsMode int32 @@ -72,11 +125,11 @@ func (x NetworkTlsMode) String() string { } func (NetworkTlsMode) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[0].Descriptor() + return file_sandbox_proto_enumTypes[1].Descriptor() } func (NetworkTlsMode) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[0] + return &file_sandbox_proto_enumTypes[1] } func (x NetworkTlsMode) Number() protoreflect.EnumNumber { @@ -85,7 +138,7 @@ func (x NetworkTlsMode) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkTlsMode.Descriptor instead. func (NetworkTlsMode) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{0} + return file_sandbox_proto_rawDescGZIP(), []int{1} } // Enforcement behavior for inspected network traffic. @@ -125,11 +178,11 @@ func (x NetworkEnforcementMode) String() string { } func (NetworkEnforcementMode) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[1].Descriptor() + return file_sandbox_proto_enumTypes[2].Descriptor() } func (NetworkEnforcementMode) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[1] + return &file_sandbox_proto_enumTypes[2] } func (x NetworkEnforcementMode) Number() protoreflect.EnumNumber { @@ -138,7 +191,7 @@ func (x NetworkEnforcementMode) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkEnforcementMode.Descriptor instead. func (NetworkEnforcementMode) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{1} + return file_sandbox_proto_rawDescGZIP(), []int{2} } // Shorthand access policy for an inspected network endpoint. @@ -182,11 +235,11 @@ func (x NetworkAccessPreset) String() string { } func (NetworkAccessPreset) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[2].Descriptor() + return file_sandbox_proto_enumTypes[3].Descriptor() } func (NetworkAccessPreset) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[2] + return &file_sandbox_proto_enumTypes[3] } func (x NetworkAccessPreset) Number() protoreflect.EnumNumber { @@ -195,7 +248,7 @@ func (x NetworkAccessPreset) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkAccessPreset.Descriptor instead. func (NetworkAccessPreset) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{2} + return file_sandbox_proto_rawDescGZIP(), []int{3} } // Scope that currently controls a setting. @@ -232,11 +285,11 @@ func (x SettingScope) String() string { } func (SettingScope) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[3].Descriptor() + return file_sandbox_proto_enumTypes[4].Descriptor() } func (SettingScope) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[3] + return &file_sandbox_proto_enumTypes[4] } func (x SettingScope) Number() protoreflect.EnumNumber { @@ -245,7 +298,7 @@ func (x SettingScope) Number() protoreflect.EnumNumber { // Deprecated: Use SettingScope.Descriptor instead. func (SettingScope) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{3} + return file_sandbox_proto_rawDescGZIP(), []int{4} } // Source used for a sandbox configuration payload. @@ -282,11 +335,11 @@ func (x PolicySource) String() string { } func (PolicySource) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[4].Descriptor() + return file_sandbox_proto_enumTypes[5].Descriptor() } func (PolicySource) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[4] + return &file_sandbox_proto_enumTypes[5] } func (x PolicySource) Number() protoreflect.EnumNumber { @@ -295,7 +348,7 @@ func (x PolicySource) Number() protoreflect.EnumNumber { // Deprecated: Use PolicySource.Descriptor instead. func (PolicySource) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{4} + return file_sandbox_proto_rawDescGZIP(), []int{5} } // Operator authority over the bindings in a supervisor middleware manifest. @@ -339,11 +392,11 @@ func (x SupervisorMiddlewareBindingPolicy) String() string { } func (SupervisorMiddlewareBindingPolicy) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[5].Descriptor() + return file_sandbox_proto_enumTypes[6].Descriptor() } func (SupervisorMiddlewareBindingPolicy) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[5] + return &file_sandbox_proto_enumTypes[6] } func (x SupervisorMiddlewareBindingPolicy) Number() protoreflect.EnumNumber { @@ -352,7 +405,7 @@ func (x SupervisorMiddlewareBindingPolicy) Number() protoreflect.EnumNumber { // Deprecated: Use SupervisorMiddlewareBindingPolicy.Descriptor instead. func (SupervisorMiddlewareBindingPolicy) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{5} + return file_sandbox_proto_rawDescGZIP(), []int{6} } // An operation/phase pair that the platform can authorize. These identify @@ -393,11 +446,11 @@ func (x SupervisorMiddlewareBinding) String() string { } func (SupervisorMiddlewareBinding) Descriptor() protoreflect.EnumDescriptor { - return file_sandbox_proto_enumTypes[6].Descriptor() + return file_sandbox_proto_enumTypes[7].Descriptor() } func (SupervisorMiddlewareBinding) Type() protoreflect.EnumType { - return &file_sandbox_proto_enumTypes[6] + return &file_sandbox_proto_enumTypes[7] } func (x SupervisorMiddlewareBinding) Number() protoreflect.EnumNumber { @@ -406,7 +459,70 @@ func (x SupervisorMiddlewareBinding) Number() protoreflect.EnumNumber { // Deprecated: Use SupervisorMiddlewareBinding.Descriptor instead. func (SupervisorMiddlewareBinding) EnumDescriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{6} + return file_sandbox_proto_rawDescGZIP(), []int{7} +} + +// Immutable ingress envelope admitted from the compute driver's resolved inputs. +// Presence with an unspecified scope is invalid; it never means legacy support. +type SandboxIngressAdmission struct { + state protoimpl.MessageState `protogen:"open.v1"` + Scope IngressScope `protobuf:"varint,1,opt,name=scope,proto3,enum=openshell.sandbox.v1.IngressScope" json:"scope,omitempty"` + // Mutually exclusive with ports. False with an empty list admits no ports. + AllPorts bool `protobuf:"varint,2,opt,name=all_ports,json=allPorts,proto3" json:"all_ports,omitempty"` + Ports []uint32 `protobuf:"varint,3,rep,packed,name=ports,proto3" json:"ports,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxIngressAdmission) Reset() { + *x = SandboxIngressAdmission{} + mi := &file_sandbox_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxIngressAdmission) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxIngressAdmission) ProtoMessage() {} + +func (x *SandboxIngressAdmission) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[0] + 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 SandboxIngressAdmission.ProtoReflect.Descriptor instead. +func (*SandboxIngressAdmission) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{0} +} + +func (x *SandboxIngressAdmission) GetScope() IngressScope { + if x != nil { + return x.Scope + } + return IngressScope_INGRESS_SCOPE_UNSPECIFIED +} + +func (x *SandboxIngressAdmission) GetAllPorts() bool { + if x != nil { + return x.AllPorts + } + return false +} + +func (x *SandboxIngressAdmission) GetPorts() []uint32 { + if x != nil { + return x.Ports + } + return nil } // Sandbox security policy configuration. @@ -432,7 +548,7 @@ type SandboxPolicy struct { func (x *SandboxPolicy) Reset() { *x = SandboxPolicy{} - mi := &file_sandbox_proto_msgTypes[0] + mi := &file_sandbox_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -444,7 +560,7 @@ func (x *SandboxPolicy) String() string { func (*SandboxPolicy) ProtoMessage() {} func (x *SandboxPolicy) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[0] + mi := &file_sandbox_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -457,7 +573,7 @@ func (x *SandboxPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxPolicy.ProtoReflect.Descriptor instead. func (*SandboxPolicy) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{0} + return file_sandbox_proto_rawDescGZIP(), []int{1} } func (x *SandboxPolicy) GetVersion() uint32 { @@ -517,7 +633,7 @@ type FilesystemPolicy struct { func (x *FilesystemPolicy) Reset() { *x = FilesystemPolicy{} - mi := &file_sandbox_proto_msgTypes[1] + mi := &file_sandbox_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -529,7 +645,7 @@ func (x *FilesystemPolicy) String() string { func (*FilesystemPolicy) ProtoMessage() {} func (x *FilesystemPolicy) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[1] + mi := &file_sandbox_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -542,7 +658,7 @@ func (x *FilesystemPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use FilesystemPolicy.ProtoReflect.Descriptor instead. func (*FilesystemPolicy) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{1} + return file_sandbox_proto_rawDescGZIP(), []int{2} } func (x *FilesystemPolicy) GetIncludeWorkdir() bool { @@ -577,7 +693,7 @@ type LandlockPolicy struct { func (x *LandlockPolicy) Reset() { *x = LandlockPolicy{} - mi := &file_sandbox_proto_msgTypes[2] + mi := &file_sandbox_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -589,7 +705,7 @@ func (x *LandlockPolicy) String() string { func (*LandlockPolicy) ProtoMessage() {} func (x *LandlockPolicy) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[2] + mi := &file_sandbox_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -602,7 +718,7 @@ func (x *LandlockPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use LandlockPolicy.ProtoReflect.Descriptor instead. func (*LandlockPolicy) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{2} + return file_sandbox_proto_rawDescGZIP(), []int{3} } func (x *LandlockPolicy) GetCompatibility() string { @@ -625,7 +741,7 @@ type ProcessPolicy struct { func (x *ProcessPolicy) Reset() { *x = ProcessPolicy{} - mi := &file_sandbox_proto_msgTypes[3] + mi := &file_sandbox_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -637,7 +753,7 @@ func (x *ProcessPolicy) String() string { func (*ProcessPolicy) ProtoMessage() {} func (x *ProcessPolicy) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[3] + mi := &file_sandbox_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -650,7 +766,7 @@ func (x *ProcessPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use ProcessPolicy.ProtoReflect.Descriptor instead. func (*ProcessPolicy) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{3} + return file_sandbox_proto_rawDescGZIP(), []int{4} } func (x *ProcessPolicy) GetRunAsUser() string { @@ -682,7 +798,7 @@ type NetworkPolicyRule struct { func (x *NetworkPolicyRule) Reset() { *x = NetworkPolicyRule{} - mi := &file_sandbox_proto_msgTypes[4] + mi := &file_sandbox_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -694,7 +810,7 @@ func (x *NetworkPolicyRule) String() string { func (*NetworkPolicyRule) ProtoMessage() {} func (x *NetworkPolicyRule) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[4] + mi := &file_sandbox_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -707,7 +823,7 @@ func (x *NetworkPolicyRule) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkPolicyRule.ProtoReflect.Descriptor instead. func (*NetworkPolicyRule) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{4} + return file_sandbox_proto_rawDescGZIP(), []int{5} } func (x *NetworkPolicyRule) GetName() string { @@ -752,7 +868,7 @@ type NetworkMiddlewareConfig struct { func (x *NetworkMiddlewareConfig) Reset() { *x = NetworkMiddlewareConfig{} - mi := &file_sandbox_proto_msgTypes[5] + mi := &file_sandbox_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -764,7 +880,7 @@ func (x *NetworkMiddlewareConfig) String() string { func (*NetworkMiddlewareConfig) ProtoMessage() {} func (x *NetworkMiddlewareConfig) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[5] + mi := &file_sandbox_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -777,7 +893,7 @@ func (x *NetworkMiddlewareConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkMiddlewareConfig.ProtoReflect.Descriptor instead. func (*NetworkMiddlewareConfig) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{5} + return file_sandbox_proto_rawDescGZIP(), []int{6} } func (x *NetworkMiddlewareConfig) GetName() string { @@ -837,7 +953,7 @@ type MiddlewareEndpointSelector struct { func (x *MiddlewareEndpointSelector) Reset() { *x = MiddlewareEndpointSelector{} - mi := &file_sandbox_proto_msgTypes[6] + mi := &file_sandbox_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -849,7 +965,7 @@ func (x *MiddlewareEndpointSelector) String() string { func (*MiddlewareEndpointSelector) ProtoMessage() {} func (x *MiddlewareEndpointSelector) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[6] + mi := &file_sandbox_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -862,7 +978,7 @@ func (x *MiddlewareEndpointSelector) ProtoReflect() protoreflect.Message { // Deprecated: Use MiddlewareEndpointSelector.ProtoReflect.Descriptor instead. func (*MiddlewareEndpointSelector) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{6} + return file_sandbox_proto_rawDescGZIP(), []int{7} } func (x *MiddlewareEndpointSelector) GetInclude() []string { @@ -891,7 +1007,7 @@ type NetworkCredentialBinding struct { func (x *NetworkCredentialBinding) Reset() { *x = NetworkCredentialBinding{} - mi := &file_sandbox_proto_msgTypes[7] + mi := &file_sandbox_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -903,7 +1019,7 @@ func (x *NetworkCredentialBinding) String() string { func (*NetworkCredentialBinding) ProtoMessage() {} func (x *NetworkCredentialBinding) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[7] + mi := &file_sandbox_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -916,7 +1032,7 @@ func (x *NetworkCredentialBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkCredentialBinding.ProtoReflect.Descriptor instead. func (*NetworkCredentialBinding) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{7} + return file_sandbox_proto_rawDescGZIP(), []int{8} } func (x *NetworkCredentialBinding) GetProvider() string { @@ -1032,7 +1148,7 @@ type NetworkEndpoint struct { func (x *NetworkEndpoint) Reset() { *x = NetworkEndpoint{} - mi := &file_sandbox_proto_msgTypes[8] + mi := &file_sandbox_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1044,7 +1160,7 @@ func (x *NetworkEndpoint) String() string { func (*NetworkEndpoint) ProtoMessage() {} func (x *NetworkEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[8] + mi := &file_sandbox_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1057,7 +1173,7 @@ func (x *NetworkEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkEndpoint.ProtoReflect.Descriptor instead. func (*NetworkEndpoint) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{8} + return file_sandbox_proto_rawDescGZIP(), []int{9} } func (x *NetworkEndpoint) GetHost() string { @@ -1290,7 +1406,7 @@ type McpOptions struct { func (x *McpOptions) Reset() { *x = McpOptions{} - mi := &file_sandbox_proto_msgTypes[9] + mi := &file_sandbox_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1302,7 +1418,7 @@ func (x *McpOptions) String() string { func (*McpOptions) ProtoMessage() {} func (x *McpOptions) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[9] + mi := &file_sandbox_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1315,7 +1431,7 @@ func (x *McpOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use McpOptions.ProtoReflect.Descriptor instead. func (*McpOptions) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{9} + return file_sandbox_proto_rawDescGZIP(), []int{10} } func (x *McpOptions) GetStrictToolNames() bool { @@ -1354,7 +1470,7 @@ type GraphqlOperation struct { func (x *GraphqlOperation) Reset() { *x = GraphqlOperation{} - mi := &file_sandbox_proto_msgTypes[10] + mi := &file_sandbox_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1366,7 +1482,7 @@ func (x *GraphqlOperation) String() string { func (*GraphqlOperation) ProtoMessage() {} func (x *GraphqlOperation) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[10] + mi := &file_sandbox_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1379,7 +1495,7 @@ func (x *GraphqlOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use GraphqlOperation.ProtoReflect.Descriptor instead. func (*GraphqlOperation) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{10} + return file_sandbox_proto_rawDescGZIP(), []int{11} } func (x *GraphqlOperation) GetOperationType() string { @@ -1434,7 +1550,7 @@ type L7DenyRule struct { func (x *L7DenyRule) Reset() { *x = L7DenyRule{} - mi := &file_sandbox_proto_msgTypes[11] + mi := &file_sandbox_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1446,7 +1562,7 @@ func (x *L7DenyRule) String() string { func (*L7DenyRule) ProtoMessage() {} func (x *L7DenyRule) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[11] + mi := &file_sandbox_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1459,7 +1575,7 @@ func (x *L7DenyRule) ProtoReflect() protoreflect.Message { // Deprecated: Use L7DenyRule.ProtoReflect.Descriptor instead. func (*L7DenyRule) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{11} + return file_sandbox_proto_rawDescGZIP(), []int{12} } func (x *L7DenyRule) GetMethod() string { @@ -1528,7 +1644,7 @@ type L7Rule struct { func (x *L7Rule) Reset() { *x = L7Rule{} - mi := &file_sandbox_proto_msgTypes[12] + mi := &file_sandbox_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1540,7 +1656,7 @@ func (x *L7Rule) String() string { func (*L7Rule) ProtoMessage() {} func (x *L7Rule) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[12] + mi := &file_sandbox_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1553,7 +1669,7 @@ func (x *L7Rule) ProtoReflect() protoreflect.Message { // Deprecated: Use L7Rule.ProtoReflect.Descriptor instead. func (*L7Rule) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{12} + return file_sandbox_proto_rawDescGZIP(), []int{13} } func (x *L7Rule) GetAllow() *L7Allow { @@ -1593,7 +1709,7 @@ type L7Allow struct { func (x *L7Allow) Reset() { *x = L7Allow{} - mi := &file_sandbox_proto_msgTypes[13] + mi := &file_sandbox_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1605,7 +1721,7 @@ func (x *L7Allow) String() string { func (*L7Allow) ProtoMessage() {} func (x *L7Allow) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[13] + mi := &file_sandbox_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1618,7 +1734,7 @@ func (x *L7Allow) ProtoReflect() protoreflect.Message { // Deprecated: Use L7Allow.ProtoReflect.Descriptor instead. func (*L7Allow) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{13} + return file_sandbox_proto_rawDescGZIP(), []int{14} } func (x *L7Allow) GetMethod() string { @@ -1690,7 +1806,7 @@ type L7QueryMatcher struct { func (x *L7QueryMatcher) Reset() { *x = L7QueryMatcher{} - mi := &file_sandbox_proto_msgTypes[14] + mi := &file_sandbox_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1702,7 +1818,7 @@ func (x *L7QueryMatcher) String() string { func (*L7QueryMatcher) ProtoMessage() {} func (x *L7QueryMatcher) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[14] + mi := &file_sandbox_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1715,7 +1831,7 @@ func (x *L7QueryMatcher) ProtoReflect() protoreflect.Message { // Deprecated: Use L7QueryMatcher.ProtoReflect.Descriptor instead. func (*L7QueryMatcher) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{14} + return file_sandbox_proto_rawDescGZIP(), []int{15} } func (x *L7QueryMatcher) GetGlob() string { @@ -1742,7 +1858,7 @@ type NetworkBinary struct { func (x *NetworkBinary) Reset() { *x = NetworkBinary{} - mi := &file_sandbox_proto_msgTypes[15] + mi := &file_sandbox_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1754,7 +1870,7 @@ func (x *NetworkBinary) String() string { func (*NetworkBinary) ProtoMessage() {} func (x *NetworkBinary) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[15] + mi := &file_sandbox_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1767,7 +1883,7 @@ func (x *NetworkBinary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkBinary.ProtoReflect.Descriptor instead. func (*NetworkBinary) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{15} + return file_sandbox_proto_rawDescGZIP(), []int{16} } func (x *NetworkBinary) GetPath() string { @@ -1789,7 +1905,7 @@ type GetSandboxConfigRequest struct { func (x *GetSandboxConfigRequest) Reset() { *x = GetSandboxConfigRequest{} - mi := &file_sandbox_proto_msgTypes[16] + mi := &file_sandbox_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1801,7 +1917,7 @@ func (x *GetSandboxConfigRequest) String() string { func (*GetSandboxConfigRequest) ProtoMessage() {} func (x *GetSandboxConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[16] + mi := &file_sandbox_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1814,7 +1930,7 @@ func (x *GetSandboxConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxConfigRequest.ProtoReflect.Descriptor instead. func (*GetSandboxConfigRequest) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{16} + return file_sandbox_proto_rawDescGZIP(), []int{17} } func (x *GetSandboxConfigRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -1840,7 +1956,7 @@ type GetGatewayConfigRequest struct { func (x *GetGatewayConfigRequest) Reset() { *x = GetGatewayConfigRequest{} - mi := &file_sandbox_proto_msgTypes[17] + mi := &file_sandbox_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1852,7 +1968,7 @@ func (x *GetGatewayConfigRequest) String() string { func (*GetGatewayConfigRequest) ProtoMessage() {} func (x *GetGatewayConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[17] + mi := &file_sandbox_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1865,7 +1981,7 @@ func (x *GetGatewayConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGatewayConfigRequest.ProtoReflect.Descriptor instead. func (*GetGatewayConfigRequest) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{17} + return file_sandbox_proto_rawDescGZIP(), []int{18} } // Response containing gateway-global settings. @@ -1882,7 +1998,7 @@ type GetGatewayConfigResponse struct { func (x *GetGatewayConfigResponse) Reset() { *x = GetGatewayConfigResponse{} - mi := &file_sandbox_proto_msgTypes[18] + mi := &file_sandbox_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1894,7 +2010,7 @@ func (x *GetGatewayConfigResponse) String() string { func (*GetGatewayConfigResponse) ProtoMessage() {} func (x *GetGatewayConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[18] + mi := &file_sandbox_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1907,7 +2023,7 @@ func (x *GetGatewayConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGatewayConfigResponse.ProtoReflect.Descriptor instead. func (*GetGatewayConfigResponse) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{18} + return file_sandbox_proto_rawDescGZIP(), []int{19} } func (x *GetGatewayConfigResponse) GetSettings() map[string]*SettingValue { @@ -1940,7 +2056,7 @@ type SettingValue struct { func (x *SettingValue) Reset() { *x = SettingValue{} - mi := &file_sandbox_proto_msgTypes[19] + mi := &file_sandbox_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1952,7 +2068,7 @@ func (x *SettingValue) String() string { func (*SettingValue) ProtoMessage() {} func (x *SettingValue) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[19] + mi := &file_sandbox_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1965,7 +2081,7 @@ func (x *SettingValue) ProtoReflect() protoreflect.Message { // Deprecated: Use SettingValue.ProtoReflect.Descriptor instead. func (*SettingValue) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{19} + return file_sandbox_proto_rawDescGZIP(), []int{20} } func (x *SettingValue) GetValue() isSettingValue_Value { @@ -2050,7 +2166,7 @@ type EffectiveSetting struct { func (x *EffectiveSetting) Reset() { *x = EffectiveSetting{} - mi := &file_sandbox_proto_msgTypes[20] + mi := &file_sandbox_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2062,7 +2178,7 @@ func (x *EffectiveSetting) String() string { func (*EffectiveSetting) ProtoMessage() {} func (x *EffectiveSetting) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[20] + mi := &file_sandbox_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2075,7 +2191,7 @@ func (x *EffectiveSetting) ProtoReflect() protoreflect.Message { // Deprecated: Use EffectiveSetting.ProtoReflect.Descriptor instead. func (*EffectiveSetting) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{20} + return file_sandbox_proto_rawDescGZIP(), []int{21} } func (x *EffectiveSetting) GetValue() *SettingValue { @@ -2124,7 +2240,7 @@ type SandboxConfigSnapshot struct { func (x *SandboxConfigSnapshot) Reset() { *x = SandboxConfigSnapshot{} - mi := &file_sandbox_proto_msgTypes[21] + mi := &file_sandbox_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2136,7 +2252,7 @@ func (x *SandboxConfigSnapshot) String() string { func (*SandboxConfigSnapshot) ProtoMessage() {} func (x *SandboxConfigSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[21] + mi := &file_sandbox_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2149,7 +2265,7 @@ func (x *SandboxConfigSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfigSnapshot.ProtoReflect.Descriptor instead. func (*SandboxConfigSnapshot) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{21} + return file_sandbox_proto_rawDescGZIP(), []int{22} } func (x *SandboxConfigSnapshot) GetPolicy() *SandboxPolicy { @@ -2334,7 +2450,7 @@ type GetSandboxConfigResponse struct { func (x *GetSandboxConfigResponse) Reset() { *x = GetSandboxConfigResponse{} - mi := &file_sandbox_proto_msgTypes[22] + mi := &file_sandbox_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2346,7 +2462,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[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2359,7 +2475,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{23} } func (x *GetSandboxConfigResponse) GetPolicy() *SandboxPolicy { @@ -2503,7 +2619,7 @@ type SandboxServiceRoute struct { func (x *SandboxServiceRoute) Reset() { *x = SandboxServiceRoute{} - mi := &file_sandbox_proto_msgTypes[23] + mi := &file_sandbox_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2515,7 +2631,7 @@ func (x *SandboxServiceRoute) String() string { func (*SandboxServiceRoute) ProtoMessage() {} func (x *SandboxServiceRoute) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[23] + mi := &file_sandbox_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2528,7 +2644,7 @@ func (x *SandboxServiceRoute) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxServiceRoute.ProtoReflect.Descriptor instead. func (*SandboxServiceRoute) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{23} + return file_sandbox_proto_rawDescGZIP(), []int{24} } func (x *SandboxServiceRoute) GetEndpointId() string { @@ -2605,7 +2721,7 @@ type SupervisorMiddlewareService struct { func (x *SupervisorMiddlewareService) Reset() { *x = SupervisorMiddlewareService{} - mi := &file_sandbox_proto_msgTypes[24] + mi := &file_sandbox_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2617,7 +2733,7 @@ func (x *SupervisorMiddlewareService) String() string { func (*SupervisorMiddlewareService) ProtoMessage() {} func (x *SupervisorMiddlewareService) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[24] + mi := &file_sandbox_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2630,7 +2746,7 @@ func (x *SupervisorMiddlewareService) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMiddlewareService.ProtoReflect.Descriptor instead. func (*SupervisorMiddlewareService) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{24} + return file_sandbox_proto_rawDescGZIP(), []int{25} } func (x *SupervisorMiddlewareService) GetName() string { @@ -2700,7 +2816,11 @@ 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\"\xa8\x05\n" + + "\rsandbox.proto\x12\x14openshell.sandbox.v1\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x0fdatamodel.proto\"\x86\x01\n" + + "\x17SandboxIngressAdmission\x128\n" + + "\x05scope\x18\x01 \x01(\x0e2\".openshell.sandbox.v1.IngressScopeR\x05scope\x12\x1b\n" + + "\tall_ports\x18\x02 \x01(\bR\ballPorts\x12\x14\n" + + "\x05ports\x18\x03 \x03(\rR\x05ports\"\xa8\x05\n" + "\rSandboxPolicy\x12\x18\n" + "\aversion\x18\x01 \x01(\rR\aversion\x12F\n" + "\n" + @@ -2916,7 +3036,12 @@ const file_sandbox_proto_rawDesc = "" + "\baudience\x18\x06 \x01(\tR\baudience\x128\n" + "\x18allow_insecure_transport\x18\a \x01(\bR\x16allowInsecureTransport\x12^\n" + "\x0ebinding_policy\x18\b \x01(\x0e27.openshell.sandbox.v1.SupervisorMiddlewareBindingPolicyR\rbindingPolicy\x12M\n" + - "\bbindings\x18\t \x03(\x0e21.openshell.sandbox.v1.SupervisorMiddlewareBindingR\bbindingsJ\x04\b\x04\x10\x05R\atimeout*\x97\x01\n" + + "\bbindings\x18\t \x03(\x0e21.openshell.sandbox.v1.SupervisorMiddlewareBindingR\bbindingsJ\x04\b\x04\x10\x05R\atimeout*\x99\x01\n" + + "\fIngressScope\x12\x1d\n" + + "\x19INGRESS_SCOPE_UNSPECIFIED\x10\x00\x12\x1d\n" + + "\x19INGRESS_SCOPE_UNSUPPORTED\x10\x01\x12#\n" + + "\x1fINGRESS_SCOPE_ISOLATED_LOOPBACK\x10\x02\x12&\n" + + "\"INGRESS_SCOPE_SHARED_HOST_LOOPBACK\x10\x03*\x97\x01\n" + "\x0eNetworkTlsMode\x12 \n" + "\x1cNETWORK_TLS_MODE_UNSPECIFIED\x10\x00\x12\x19\n" + "\x15NETWORK_TLS_MODE_SKIP\x10\x01\x12\"\n" + @@ -2962,110 +3087,113 @@ func file_sandbox_proto_rawDescGZIP() []byte { return file_sandbox_proto_rawDescData } -var file_sandbox_proto_enumTypes = make([]protoimpl.EnumInfo, 7) -var file_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 35) +var file_sandbox_proto_enumTypes = make([]protoimpl.EnumInfo, 8) +var file_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 36) var file_sandbox_proto_goTypes = []any{ - (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 - (SupervisorMiddlewareBindingPolicy)(0), // 5: openshell.sandbox.v1.SupervisorMiddlewareBindingPolicy - (SupervisorMiddlewareBinding)(0), // 6: openshell.sandbox.v1.SupervisorMiddlewareBinding - (*SandboxPolicy)(nil), // 7: openshell.sandbox.v1.SandboxPolicy - (*FilesystemPolicy)(nil), // 8: openshell.sandbox.v1.FilesystemPolicy - (*LandlockPolicy)(nil), // 9: openshell.sandbox.v1.LandlockPolicy - (*ProcessPolicy)(nil), // 10: openshell.sandbox.v1.ProcessPolicy - (*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 - (*SandboxConfigSnapshot)(nil), // 28: openshell.sandbox.v1.SandboxConfigSnapshot - (*GetSandboxConfigResponse)(nil), // 29: openshell.sandbox.v1.GetSandboxConfigResponse - (*SandboxServiceRoute)(nil), // 30: openshell.sandbox.v1.SandboxServiceRoute - (*SupervisorMiddlewareService)(nil), // 31: openshell.sandbox.v1.SupervisorMiddlewareService - nil, // 32: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry - nil, // 33: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry - nil, // 34: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry - nil, // 35: openshell.sandbox.v1.L7DenyRule.QueryEntry - nil, // 36: openshell.sandbox.v1.L7DenyRule.ParamsEntry - nil, // 37: openshell.sandbox.v1.L7Allow.QueryEntry - nil, // 38: openshell.sandbox.v1.L7Allow.ParamsEntry - nil, // 39: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry - nil, // 40: openshell.sandbox.v1.SandboxConfigSnapshot.SettingsEntry - nil, // 41: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry - (*structpb.Struct)(nil), // 42: google.protobuf.Struct - (*datamodelv1.WorkspaceSelector)(nil), // 43: openshell.datamodel.v1.WorkspaceSelector - (*durationpb.Duration)(nil), // 44: google.protobuf.Duration + (IngressScope)(0), // 0: openshell.sandbox.v1.IngressScope + (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 + (SupervisorMiddlewareBindingPolicy)(0), // 6: openshell.sandbox.v1.SupervisorMiddlewareBindingPolicy + (SupervisorMiddlewareBinding)(0), // 7: openshell.sandbox.v1.SupervisorMiddlewareBinding + (*SandboxIngressAdmission)(nil), // 8: openshell.sandbox.v1.SandboxIngressAdmission + (*SandboxPolicy)(nil), // 9: openshell.sandbox.v1.SandboxPolicy + (*FilesystemPolicy)(nil), // 10: openshell.sandbox.v1.FilesystemPolicy + (*LandlockPolicy)(nil), // 11: openshell.sandbox.v1.LandlockPolicy + (*ProcessPolicy)(nil), // 12: openshell.sandbox.v1.ProcessPolicy + (*NetworkPolicyRule)(nil), // 13: openshell.sandbox.v1.NetworkPolicyRule + (*NetworkMiddlewareConfig)(nil), // 14: openshell.sandbox.v1.NetworkMiddlewareConfig + (*MiddlewareEndpointSelector)(nil), // 15: openshell.sandbox.v1.MiddlewareEndpointSelector + (*NetworkCredentialBinding)(nil), // 16: openshell.sandbox.v1.NetworkCredentialBinding + (*NetworkEndpoint)(nil), // 17: openshell.sandbox.v1.NetworkEndpoint + (*McpOptions)(nil), // 18: openshell.sandbox.v1.McpOptions + (*GraphqlOperation)(nil), // 19: openshell.sandbox.v1.GraphqlOperation + (*L7DenyRule)(nil), // 20: openshell.sandbox.v1.L7DenyRule + (*L7Rule)(nil), // 21: openshell.sandbox.v1.L7Rule + (*L7Allow)(nil), // 22: openshell.sandbox.v1.L7Allow + (*L7QueryMatcher)(nil), // 23: openshell.sandbox.v1.L7QueryMatcher + (*NetworkBinary)(nil), // 24: openshell.sandbox.v1.NetworkBinary + (*GetSandboxConfigRequest)(nil), // 25: openshell.sandbox.v1.GetSandboxConfigRequest + (*GetGatewayConfigRequest)(nil), // 26: openshell.sandbox.v1.GetGatewayConfigRequest + (*GetGatewayConfigResponse)(nil), // 27: openshell.sandbox.v1.GetGatewayConfigResponse + (*SettingValue)(nil), // 28: openshell.sandbox.v1.SettingValue + (*EffectiveSetting)(nil), // 29: openshell.sandbox.v1.EffectiveSetting + (*SandboxConfigSnapshot)(nil), // 30: openshell.sandbox.v1.SandboxConfigSnapshot + (*GetSandboxConfigResponse)(nil), // 31: openshell.sandbox.v1.GetSandboxConfigResponse + (*SandboxServiceRoute)(nil), // 32: openshell.sandbox.v1.SandboxServiceRoute + (*SupervisorMiddlewareService)(nil), // 33: openshell.sandbox.v1.SupervisorMiddlewareService + nil, // 34: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry + nil, // 35: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry + nil, // 36: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry + nil, // 37: openshell.sandbox.v1.L7DenyRule.QueryEntry + nil, // 38: openshell.sandbox.v1.L7DenyRule.ParamsEntry + nil, // 39: openshell.sandbox.v1.L7Allow.QueryEntry + nil, // 40: openshell.sandbox.v1.L7Allow.ParamsEntry + nil, // 41: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry + nil, // 42: openshell.sandbox.v1.SandboxConfigSnapshot.SettingsEntry + nil, // 43: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry + (*structpb.Struct)(nil), // 44: google.protobuf.Struct + (*datamodelv1.WorkspaceSelector)(nil), // 45: openshell.datamodel.v1.WorkspaceSelector + (*durationpb.Duration)(nil), // 46: google.protobuf.Duration } var file_sandbox_proto_depIdxs = []int32{ - 8, // 0: openshell.sandbox.v1.SandboxPolicy.filesystem:type_name -> openshell.sandbox.v1.FilesystemPolicy - 9, // 1: openshell.sandbox.v1.SandboxPolicy.landlock:type_name -> openshell.sandbox.v1.LandlockPolicy - 10, // 2: openshell.sandbox.v1.SandboxPolicy.process:type_name -> openshell.sandbox.v1.ProcessPolicy - 32, // 3: openshell.sandbox.v1.SandboxPolicy.network_policies:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry - 33, // 4: openshell.sandbox.v1.SandboxPolicy.network_middlewares:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry - 15, // 5: openshell.sandbox.v1.NetworkPolicyRule.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 22, // 6: openshell.sandbox.v1.NetworkPolicyRule.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 42, // 7: openshell.sandbox.v1.NetworkMiddlewareConfig.config:type_name -> google.protobuf.Struct - 13, // 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 - 19, // 12: openshell.sandbox.v1.NetworkEndpoint.rules:type_name -> openshell.sandbox.v1.L7Rule - 18, // 13: openshell.sandbox.v1.NetworkEndpoint.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 34, // 14: openshell.sandbox.v1.NetworkEndpoint.graphql_persisted_queries:type_name -> openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry - 16, // 15: openshell.sandbox.v1.NetworkEndpoint.mcp:type_name -> openshell.sandbox.v1.McpOptions - 14, // 16: openshell.sandbox.v1.NetworkEndpoint.credential_binding:type_name -> openshell.sandbox.v1.NetworkCredentialBinding - 35, // 17: openshell.sandbox.v1.L7DenyRule.query:type_name -> openshell.sandbox.v1.L7DenyRule.QueryEntry - 36, // 18: openshell.sandbox.v1.L7DenyRule.params:type_name -> openshell.sandbox.v1.L7DenyRule.ParamsEntry - 20, // 19: openshell.sandbox.v1.L7Rule.allow:type_name -> openshell.sandbox.v1.L7Allow - 37, // 20: openshell.sandbox.v1.L7Allow.query:type_name -> openshell.sandbox.v1.L7Allow.QueryEntry - 38, // 21: openshell.sandbox.v1.L7Allow.params:type_name -> openshell.sandbox.v1.L7Allow.ParamsEntry - 43, // 22: openshell.sandbox.v1.GetSandboxConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 39, // 23: openshell.sandbox.v1.GetGatewayConfigResponse.settings:type_name -> openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry - 26, // 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 - 7, // 26: openshell.sandbox.v1.SandboxConfigSnapshot.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 40, // 27: openshell.sandbox.v1.SandboxConfigSnapshot.settings:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot.SettingsEntry - 4, // 28: openshell.sandbox.v1.SandboxConfigSnapshot.policy_source:type_name -> openshell.sandbox.v1.PolicySource - 31, // 29: openshell.sandbox.v1.SandboxConfigSnapshot.supervisor_middleware_services:type_name -> openshell.sandbox.v1.SupervisorMiddlewareService - 30, // 30: openshell.sandbox.v1.SandboxConfigSnapshot.service_routes:type_name -> openshell.sandbox.v1.SandboxServiceRoute - 7, // 31: openshell.sandbox.v1.GetSandboxConfigResponse.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 41, // 32: openshell.sandbox.v1.GetSandboxConfigResponse.settings:type_name -> openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry - 4, // 33: openshell.sandbox.v1.GetSandboxConfigResponse.policy_source:type_name -> openshell.sandbox.v1.PolicySource - 31, // 34: openshell.sandbox.v1.GetSandboxConfigResponse.supervisor_middleware_services:type_name -> openshell.sandbox.v1.SupervisorMiddlewareService - 30, // 35: openshell.sandbox.v1.GetSandboxConfigResponse.service_routes:type_name -> openshell.sandbox.v1.SandboxServiceRoute - 44, // 36: openshell.sandbox.v1.SupervisorMiddlewareService.request_timeout:type_name -> google.protobuf.Duration - 5, // 37: openshell.sandbox.v1.SupervisorMiddlewareService.binding_policy:type_name -> openshell.sandbox.v1.SupervisorMiddlewareBindingPolicy - 6, // 38: openshell.sandbox.v1.SupervisorMiddlewareService.bindings:type_name -> openshell.sandbox.v1.SupervisorMiddlewareBinding - 11, // 39: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry.value:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 12, // 40: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry.value:type_name -> openshell.sandbox.v1.NetworkMiddlewareConfig - 17, // 41: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry.value:type_name -> openshell.sandbox.v1.GraphqlOperation - 21, // 42: openshell.sandbox.v1.L7DenyRule.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 21, // 43: openshell.sandbox.v1.L7DenyRule.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 21, // 44: openshell.sandbox.v1.L7Allow.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 21, // 45: openshell.sandbox.v1.L7Allow.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 26, // 46: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.SettingValue - 27, // 47: openshell.sandbox.v1.SandboxConfigSnapshot.SettingsEntry.value:type_name -> openshell.sandbox.v1.EffectiveSetting - 27, // 48: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.EffectiveSetting - 49, // [49:49] is the sub-list for method output_type - 49, // [49:49] is the sub-list for method input_type - 49, // [49:49] is the sub-list for extension type_name - 49, // [49:49] is the sub-list for extension extendee - 0, // [0:49] is the sub-list for field type_name + 0, // 0: openshell.sandbox.v1.SandboxIngressAdmission.scope:type_name -> openshell.sandbox.v1.IngressScope + 10, // 1: openshell.sandbox.v1.SandboxPolicy.filesystem:type_name -> openshell.sandbox.v1.FilesystemPolicy + 11, // 2: openshell.sandbox.v1.SandboxPolicy.landlock:type_name -> openshell.sandbox.v1.LandlockPolicy + 12, // 3: openshell.sandbox.v1.SandboxPolicy.process:type_name -> openshell.sandbox.v1.ProcessPolicy + 34, // 4: openshell.sandbox.v1.SandboxPolicy.network_policies:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry + 35, // 5: openshell.sandbox.v1.SandboxPolicy.network_middlewares:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry + 17, // 6: openshell.sandbox.v1.NetworkPolicyRule.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 24, // 7: openshell.sandbox.v1.NetworkPolicyRule.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 44, // 8: openshell.sandbox.v1.NetworkMiddlewareConfig.config:type_name -> google.protobuf.Struct + 15, // 9: openshell.sandbox.v1.NetworkMiddlewareConfig.endpoints:type_name -> openshell.sandbox.v1.MiddlewareEndpointSelector + 1, // 10: openshell.sandbox.v1.NetworkEndpoint.tls:type_name -> openshell.sandbox.v1.NetworkTlsMode + 2, // 11: openshell.sandbox.v1.NetworkEndpoint.enforcement:type_name -> openshell.sandbox.v1.NetworkEnforcementMode + 3, // 12: openshell.sandbox.v1.NetworkEndpoint.access:type_name -> openshell.sandbox.v1.NetworkAccessPreset + 21, // 13: openshell.sandbox.v1.NetworkEndpoint.rules:type_name -> openshell.sandbox.v1.L7Rule + 20, // 14: openshell.sandbox.v1.NetworkEndpoint.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 36, // 15: openshell.sandbox.v1.NetworkEndpoint.graphql_persisted_queries:type_name -> openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry + 18, // 16: openshell.sandbox.v1.NetworkEndpoint.mcp:type_name -> openshell.sandbox.v1.McpOptions + 16, // 17: openshell.sandbox.v1.NetworkEndpoint.credential_binding:type_name -> openshell.sandbox.v1.NetworkCredentialBinding + 37, // 18: openshell.sandbox.v1.L7DenyRule.query:type_name -> openshell.sandbox.v1.L7DenyRule.QueryEntry + 38, // 19: openshell.sandbox.v1.L7DenyRule.params:type_name -> openshell.sandbox.v1.L7DenyRule.ParamsEntry + 22, // 20: openshell.sandbox.v1.L7Rule.allow:type_name -> openshell.sandbox.v1.L7Allow + 39, // 21: openshell.sandbox.v1.L7Allow.query:type_name -> openshell.sandbox.v1.L7Allow.QueryEntry + 40, // 22: openshell.sandbox.v1.L7Allow.params:type_name -> openshell.sandbox.v1.L7Allow.ParamsEntry + 45, // 23: openshell.sandbox.v1.GetSandboxConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 41, // 24: openshell.sandbox.v1.GetGatewayConfigResponse.settings:type_name -> openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry + 28, // 25: openshell.sandbox.v1.EffectiveSetting.value:type_name -> openshell.sandbox.v1.SettingValue + 4, // 26: openshell.sandbox.v1.EffectiveSetting.scope:type_name -> openshell.sandbox.v1.SettingScope + 9, // 27: openshell.sandbox.v1.SandboxConfigSnapshot.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 42, // 28: openshell.sandbox.v1.SandboxConfigSnapshot.settings:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot.SettingsEntry + 5, // 29: openshell.sandbox.v1.SandboxConfigSnapshot.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 33, // 30: openshell.sandbox.v1.SandboxConfigSnapshot.supervisor_middleware_services:type_name -> openshell.sandbox.v1.SupervisorMiddlewareService + 32, // 31: openshell.sandbox.v1.SandboxConfigSnapshot.service_routes:type_name -> openshell.sandbox.v1.SandboxServiceRoute + 9, // 32: openshell.sandbox.v1.GetSandboxConfigResponse.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 43, // 33: openshell.sandbox.v1.GetSandboxConfigResponse.settings:type_name -> openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry + 5, // 34: openshell.sandbox.v1.GetSandboxConfigResponse.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 33, // 35: openshell.sandbox.v1.GetSandboxConfigResponse.supervisor_middleware_services:type_name -> openshell.sandbox.v1.SupervisorMiddlewareService + 32, // 36: openshell.sandbox.v1.GetSandboxConfigResponse.service_routes:type_name -> openshell.sandbox.v1.SandboxServiceRoute + 46, // 37: openshell.sandbox.v1.SupervisorMiddlewareService.request_timeout:type_name -> google.protobuf.Duration + 6, // 38: openshell.sandbox.v1.SupervisorMiddlewareService.binding_policy:type_name -> openshell.sandbox.v1.SupervisorMiddlewareBindingPolicy + 7, // 39: openshell.sandbox.v1.SupervisorMiddlewareService.bindings:type_name -> openshell.sandbox.v1.SupervisorMiddlewareBinding + 13, // 40: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry.value:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 14, // 41: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry.value:type_name -> openshell.sandbox.v1.NetworkMiddlewareConfig + 19, // 42: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry.value:type_name -> openshell.sandbox.v1.GraphqlOperation + 23, // 43: openshell.sandbox.v1.L7DenyRule.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 23, // 44: openshell.sandbox.v1.L7DenyRule.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 23, // 45: openshell.sandbox.v1.L7Allow.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 23, // 46: openshell.sandbox.v1.L7Allow.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 28, // 47: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.SettingValue + 29, // 48: openshell.sandbox.v1.SandboxConfigSnapshot.SettingsEntry.value:type_name -> openshell.sandbox.v1.EffectiveSetting + 29, // 49: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.EffectiveSetting + 50, // [50:50] is the sub-list for method output_type + 50, // [50:50] is the sub-list for method input_type + 50, // [50:50] is the sub-list for extension type_name + 50, // [50:50] is the sub-list for extension extendee + 0, // [0:50] is the sub-list for field type_name } func init() { file_sandbox_proto_init() } @@ -3073,8 +3201,8 @@ func file_sandbox_proto_init() { if File_sandbox_proto != nil { return } - file_sandbox_proto_msgTypes[9].OneofWrappers = []any{} - file_sandbox_proto_msgTypes[19].OneofWrappers = []any{ + file_sandbox_proto_msgTypes[10].OneofWrappers = []any{} + file_sandbox_proto_msgTypes[20].OneofWrappers = []any{ (*SettingValue_StringValue)(nil), (*SettingValue_BoolValue)(nil), (*SettingValue_IntValue)(nil), @@ -3085,8 +3213,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: 7, - NumMessages: 35, + NumEnums: 8, + NumMessages: 36, NumExtensions: 0, NumServices: 0, }, diff --git a/sdk/go/tests/compatibility/sandbox_updates_test.go b/sdk/go/tests/compatibility/sandbox_updates_test.go index 44bc7b023f..3df0792008 100644 --- a/sdk/go/tests/compatibility/sandbox_updates_test.go +++ b/sdk/go/tests/compatibility/sandbox_updates_test.go @@ -21,23 +21,48 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" ) -func TestSandboxStatusRetainsBaselinePublicShape(t *testing.T) { - // Freeze the pre-image-update fields and tags: private operation state must - // not enlarge the public Rust struct or leak into generated SDK messages. - fields := []string{ - "agent_pod", "agent_fd", "sandbox_fd", "conditions", "phase", - "current_policy_version", "main_process_instance_id", "exit_code", - "endpoint_statuses", "configuration_admission", "configuration_activated", - "provisioning", "restart_count", "next_restart_time", - "main_process_started_time", "last_token_grant_failure", +func TestSandboxStatusMatchesNextMinorPublicShape(t *testing.T) { + // This intentionally advances the source baseline for the documented next + // minor release. Private image-operation state remains outside public status. + // Explicit tags preserve legacy identities and independently allocated gaps. + fields := []struct { + name protoreflect.Name + number protoreflect.FieldNumber + }{ + {"agent_pod", 2}, + {"agent_fd", 3}, + {"sandbox_fd", 4}, + {"conditions", 5}, + {"phase", 6}, + {"current_policy_version", 7}, + {"main_process_instance_id", 8}, + {"exit_code", 9}, + {"endpoint_statuses", 10}, + {"configuration_admission", 11}, + {"configuration_activated", 12}, + {"provisioning", 13}, + {"restart_count", 14}, + {"next_restart_time", 15}, + {"main_process_started_time", 16}, + {"last_token_grant_failure", 17}, + {"ingress_admission", 19}, } descriptor := (&pb.SandboxStatus{}).ProtoReflect().Descriptor() require.Equal(t, len(fields), descriptor.Fields().Len()) - for i, name := range fields { - field := descriptor.Fields().ByName(protoreflect.Name(name)) - require.NotNil(t, field, name) - require.Equal(t, protoreflect.FieldNumber(i+2), field.Number(), name) + for _, expected := range fields { + field := descriptor.Fields().ByName(expected.name) + require.NotNil(t, field, expected.name) + require.Equal(t, expected.number, field.Number(), expected.name) } + + // v0.1.x status bytes: phase field6, policy-version field7. Absence of the + // new readback is retained; decoding does not invent admission evidence. + var old pb.SandboxStatus + require.NoError(t, proto.Unmarshal([]byte{0x30, 0x03, 0x38, 0x07}, &old)) + require.EqualValues(t, 3, old.GetPhase()) + require.Equal(t, uint32(7), old.GetCurrentPolicyVersion()) + require.Nil(t, old.IngressAdmission) + require.Nil(t, pb.File_openshell_proto.Messages().ByName("SandboxImageUpdate")) legacy := pb.File_openshell_proto.Services().ByName("OpenShell") require.Nil(t, legacy.Methods().ByName("UpdateSandbox")) diff --git a/sdk/typescript/src/client.test.ts b/sdk/typescript/src/client.test.ts index 86fdfa3972..f195059b01 100644 --- a/sdk/typescript/src/client.test.ts +++ b/sdk/typescript/src/client.test.ts @@ -702,6 +702,7 @@ describe('create', () => { it('sends create-time service exposures', async () => { let created: { serviceExposures?: Array<{ service?: string; targetPort?: number; authorizationMode?: number }>; + forwardPorts?: number[]; } = {}; const sandbox = client({ createSandbox: (req) => { @@ -718,6 +719,7 @@ describe('create', () => { const result = await sandbox.create({ image: 'img', + forwardPorts: [8080], serviceExposures: [ { targetPort: 4500 }, { @@ -728,6 +730,7 @@ describe('create', () => { ], }); + expect(created.forwardPorts).toEqual([8080]); expect( created.serviceExposures?.map(({ service, targetPort, authorizationMode }) => ({ service, @@ -2167,6 +2170,18 @@ describe('ssh sessions', () => { }); describe('forward', () => { + it('rejects an unadmitted target before creating a local forward handle', async () => { + const sandbox = client({ + getSandbox: () => ({ + sandbox: { + metadata: { id: 'sb-id', name: 'sb', workspace: 'default' }, + status: { phase: SandboxPhase.READY, ingressAdmission: { scope: 3, allPorts: false, ports: [8080] } }, + }, + }), + }); + await expect(sandbox.forward('sb', { targetPort: 9090 })).rejects.toMatchObject({ code: 'invalid_config' }); + }); + it('binds a local port and relays bytes both ways, minting + revoking a token', async () => { let sshReq: ScopedRequest = {}; let revokedToken: string | undefined; diff --git a/sdk/typescript/src/client.ts b/sdk/typescript/src/client.ts index 205796f1bd..b69f8112ef 100644 --- a/sdk/typescript/src/client.ts +++ b/sdk/typescript/src/client.ts @@ -38,7 +38,13 @@ import { type TcpForwardFrameSchema, } from './gen/openshell_pb.js'; import type { EffectiveSetting, GetSandboxConfigResponse, SandboxPolicy, SettingValue } from './gen/sandbox_pb.js'; -import { PolicySource, type SandboxPolicySchema, SettingScope, type SettingValueSchema } from './gen/sandbox_pb.js'; +import { + IngressScope, + PolicySource, + type SandboxPolicySchema, + SettingScope, + type SettingValueSchema, +} from './gen/sandbox_pb.js'; import { ProviderClient } from './providers.js'; import { heldUntilReady, OWNER_REPLICA_HEADER, OWNER_REQUEST_HEADER, routedStream } from './routing.js'; import { validateSshResponse } from './ssh-validate.js'; @@ -170,6 +176,8 @@ export interface SandboxSpec { tty?: boolean; /** Loopback HTTP services to expose when the sandbox is created. */ serviceExposures?: ServiceExposure[]; + /** Target ports to admit before provisioning; does not open listeners. */ + forwardPorts?: number[]; /** Restart behavior after the canonical main process exits. */ restartPolicy?: SandboxRestartPolicyName; /** @@ -191,7 +199,7 @@ export interface SandboxSpec { export interface ServiceExposure { /** Service name. Empty or omitted selects the unnamed endpoint. */ service?: string; - /** Loopback TCP port inside the sandbox. */ + /** TCP port in the compute-admitted loopback namespace. */ targetPort: number; /** Handling for an incoming application Authorization header. */ authorizationMode?: ServiceAuthorizationMode; @@ -225,6 +233,8 @@ export interface SandboxFromTemplateSpec { tty?: boolean; /** Loopback HTTP services to expose when the sandbox is created. */ serviceExposures?: ServiceExposure[]; + /** Target ports to admit before provisioning; does not open listeners. */ + forwardPorts?: number[]; /** * Create-time sandbox policy (the safety boundary). The named workload * template supplies runtime workload fields. @@ -232,7 +242,14 @@ export interface SandboxFromTemplateSpec { policy?: MessageInitShape; } +export interface SandboxIngressAdmission { + scope: 'unknown' | 'unsupported' | 'isolated_loopback' | 'shared_host_loopback'; + allPorts: boolean; + ports: number[]; +} + export interface SandboxRef { + ingressAdmission?: SandboxIngressAdmission; id: string; name: string; workspace: string; @@ -470,9 +487,9 @@ export interface WaitDeletedOptions extends WaitOptions { } export interface ForwardOptions extends SandboxWorkspaceOptions { - /** Loopback TCP port inside the sandbox to dial. */ + /** TCP port in the compute-admitted loopback namespace to dial. */ targetPort: number; - /** Target host inside the sandbox (loopback only). Default 127.0.0.1. */ + /** Target host in the admitted loopback namespace. Default 127.0.0.1. */ targetHost?: string; /** Local port to bind. Default 0 (ephemeral). */ localPort?: number; @@ -630,7 +647,22 @@ function sandboxRef(sandbox: Sandbox | undefined, serviceUrls: Record ({ service: exposure.service ?? '', @@ -1261,6 +1294,7 @@ export class SandboxClient { policy: spec.policy, }, workloadTemplate: spec.workloadTemplate, + forwardPorts: [...(spec.forwardPorts ?? [])], serviceExposures: spec.serviceExposures?.map((exposure) => ({ service: exposure.service ?? '', @@ -1736,6 +1770,9 @@ export class SandboxClient { // the `init` (TCP target + token), relay bytes both ways in ~64 KiB chunks, // and revoke the token on close. Process-lifetime only. async forward(name: string, opts: ForwardOptions): Promise { + if (!Number.isInteger(opts.targetPort) || opts.targetPort < 1 || opts.targetPort > 65535) { + throw new SdkError('invalid_config', 'target port must be between 1 and 65535'); + } const targetHost = opts.targetHost ?? '127.0.0.1'; const targetPort = opts.targetPort; const localHost = opts.localHost ?? '127.0.0.1'; @@ -1752,6 +1789,17 @@ export class SandboxClient { if (ref.phase !== 'ready') { throw new SdkError('connect', `sandbox '${name}' is not ready (phase: ${ref.phase})`); } + const ingress = ref.ingressAdmission; + if ( + ingress && + ((ingress.scope !== 'isolated_loopback' && ingress.scope !== 'shared_host_loopback') || + (ingress.allPorts && ingress.ports.length > 0) || + ingress.ports.some((port) => !Number.isInteger(port) || port < 1 || port > 65535) || + new Set(ingress.ports).size !== ingress.ports.length || + (!ingress.allPorts && !ingress.ports.includes(targetPort))) + ) { + throw new SdkError('invalid_config', 'target port was not admitted by the compute driver'); + } sandboxId = ref.id; owner = found.owner; } catch (e) { diff --git a/sdk/typescript/src/index.ts b/sdk/typescript/src/index.ts index 4948c13623..f967f3af66 100644 --- a/sdk/typescript/src/index.ts +++ b/sdk/typescript/src/index.ts @@ -31,6 +31,7 @@ export type { ProviderRef, SandboxConfig, SandboxFromTemplateSpec, + SandboxIngressAdmission, SandboxPhaseName, SandboxPolicy, SandboxRef, diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index 351d7e3b84..5d9e98e766 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -823,6 +823,9 @@ CLI forwards ignore SSH multiplexing and automatic backgrounding settings in the user's SSH config. Only background forwards are tracked by `forward list` and managed by `forward stop`; foreground forwards end when the command exits. +Declare required target ports at creation with `--forward`. For shared-host +loopback targets, choose a different local port if the target already uses it. + Manage or iterate on the sandbox: ```bash diff --git a/tests/tmachine/ansible/playbooks/k3s.yaml b/tests/tmachine/ansible/playbooks/k3s.yaml index 8666b2ac6f..d27c6c487b 100644 --- a/tests/tmachine/ansible/playbooks/k3s.yaml +++ b/tests/tmachine/ansible/playbooks/k3s.yaml @@ -21,10 +21,12 @@ state: present update_cache: true + # get.k3s.io serves the latest script, so pin the one from the k3s_version + # release tag. Update the checksum whenever k3s_version changes. - name: Download K3s installer ansible.builtin.get_url: - url: https://get.k3s.io - checksum: sha256:e5cc3b3d9dfc1662c2d9be6da5abc9a4cd317d6abc3a5ffc02e3dd3248207fee + url: "https://raw.githubusercontent.com/k3s-io/k3s/v{{ k3s_version | urlencode }}/install.sh" + checksum: sha256:3ce239d57d43b2d836d2b561043433e6decae8b9dc41f5d13908c0fafb0340cd dest: /tmp/install-k3s.sh mode: "0755"