From a8d2d7f3e84ada05ef8cc0c69166a92e4c265304 Mon Sep 17 00:00:00 2001 From: Shiju Date: Tue, 3 Nov 2026 17:11:02 +0530 Subject: [PATCH 1/3] feat(compute)!: admit service ports before provisioning A requested service port should be rejected before provisioning a sandbox or opening a local forwarding listener when the driver cannot admit it. This checks create, exposure and forwarding requests against a retained driver admission record, and shows whether the target uses isolated or operator-approved shared-host loopback. Signed-off-by: Shiju --- crates/openshell-cli/src/run.rs | 104 +- crates/openshell-cli/src/ssh.rs | 19 +- .../openshell-core/src/extension_protocol.rs | 3 + crates/openshell-core/src/ingress.rs | 61 + crates/openshell-core/src/lib.rs | 1 + crates/openshell-driver-docker/src/lib.rs | 10 +- .../openshell-driver-kubernetes/src/driver.rs | 1 + .../openshell-driver-kubernetes/src/grpc.rs | 8 +- crates/openshell-driver-mxc/src/driver.rs | 2 +- crates/openshell-driver-mxc/src/grpc.rs | 8 +- crates/openshell-driver-podman/src/driver.rs | 2 +- crates/openshell-driver-podman/src/grpc.rs | 8 +- crates/openshell-driver-vm/src/driver.rs | 10 +- .../src/proto_json.rs | 1 + .../src/runtime.rs | 1 + crates/openshell-sdk/README.md | 8 + crates/openshell-sdk/src/client.rs | 4 + crates/openshell-sdk/src/types.rs | 10 + crates/openshell-sdk/tests/client_mock.rs | 2 + .../tests/sandbox_status_compatibility.rs | 13 +- crates/openshell-server/src/compute/mod.rs | 337 ++++-- crates/openshell-server/src/grpc/mod.rs | 36 +- crates/openshell-server/src/grpc/sandbox.rs | 462 ++++++- .../src/grpc/sandbox/image_update_tests.rs | 19 +- crates/openshell-server/src/grpc/service.rs | 1 + .../openshell-server/src/service_routing.rs | 64 + crates/openshell-server/src/storage_proto.rs | 13 +- crates/openshell-server/src/test_support.rs | 33 +- crates/openshell-tui/src/lib.rs | 24 +- docs/extensibility/isolation-backends.mdx | 18 + docs/how-it-works/sandboxes/overview.mdx | 9 + examples/isolation-backend-v8/src/driver.rs | 2 +- proto/compute_driver.proto | 7 +- proto/openshell.proto | 6 + proto/sandbox.proto | 17 + python/openshell/__init__.py | 2 + python/openshell/sandbox.py | 25 + python/openshell/sandbox_test.py | 17 +- sdk/go/openshell/v1/exec_client_test.go | 5 +- sdk/go/openshell/v1/fake/fake_test.go | 5 + sdk/go/openshell/v1/fake/sandbox.go | 5 + .../v1/internal/converter/coverage_test.go | 5 + .../v1/internal/converter/sandbox.go | 13 + .../v1/internal/converter/sandbox_test.go | 15 + sdk/go/openshell/v1/options.go | 3 + sdk/go/openshell/v1/sandbox_client.go | 2 + sdk/go/openshell/v1/sandbox_client_test.go | 2 + sdk/go/openshell/v1/tcp_client.go | 41 +- sdk/go/openshell/v1/tcp_client_test.go | 25 +- sdk/go/openshell/v1/types.go | 14 + sdk/go/openshell/v1/types/options.go | 11 + sdk/go/openshell/v1/types/sandbox.go | 20 + sdk/go/proto/openshellv1/openshell.pb.go | 1069 +++++++++-------- sdk/go/proto/sandboxv1/sandbox.pb.go | 534 ++++---- .../compatibility/sandbox_updates_test.go | 51 +- sdk/typescript/src/client.test.ts | 15 + sdk/typescript/src/client.ts | 56 +- sdk/typescript/src/index.ts | 1 + skills/openshell-cli/SKILL.md | 6 + 59 files changed, 2352 insertions(+), 914 deletions(-) create mode 100644 crates/openshell-core/src/ingress.rs 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..a22b5f39ef 100644 --- a/crates/openshell-sdk/README.md +++ b/crates/openshell-sdk/README.md @@ -212,3 +212,11 @@ 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 + +This source-breaking API change targets the next minor release and must not be backported into the `0.1.x` patch series. + +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()`. + +Legacy wire payloads retain their field identities and decode the new fields as absent or empty. Upgrade gateway writers together because older writers can drop the admitted record. With a driver that negotiates ingress admission, the gateway rejects forwarding without that record until the sandbox is recreated with admitted ports. Legacy drivers that do not negotiate admission can still omit it. 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..b256a79f93 100644 --- a/docs/extensibility/isolation-backends.mdx +++ b/docs/extensibility/isolation-backends.mdx @@ -39,6 +39,16 @@ 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 +an immutable ingress envelope from `ValidateSandboxCreate`: unsupported, +isolated loopback, or explicitly admitted shared-host loopback, with all ports +or an exact port set. The gateway checks create-time forwarding and exposure +requests before provisioning and retains the envelope in sandbox status. +Forwarding clients check it before opening local listeners; the gateway also +checks live TCP relays and HTTP service routing before reusing connections. +The isolation backend remains responsible for enforcing the target connection. +Legacy absence is distinct from missing evidence under the negotiated contract. + ## Who Owns What | Component | Owns | @@ -50,3 +60,11 @@ 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 + +These API changes target the next minor release and must not be backported into the `0.1.x` patch series. Upgrade gateway replicas together because older writers can drop the admitted ingress record. + +If a driver negotiated ingress admission but an existing sandbox has no retained record, recreate the sandbox with its required ports. A legacy driver that does not negotiate admission can still omit the record. + +For raw message 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..a28e817091 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -826,6 +826,15 @@ Press `c` in the Sandboxes panel to create a sandbox. In the optional Command fi ## Port Forwarding +Compute drivers can restrict forwarding to an admitted set of ports. Declare +forward ports when creating the sandbox; unadmitted targets are rejected before +provisioning or opening a local listener. `openshell sandbox get -o json` +shows `ingress_admission` with its scope, port list and `all_ports` flag. A +`shared_host_loopback` scope refers to an operator-approved host service, rather +than a service isolated inside the sandbox. If an upgraded driver reports +unknown or missing admission for an existing sandbox, recreate it with the +required ports. A legacy driver leaves admission absent. + 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..32ee319ba9 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -823,6 +823,12 @@ 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. +Forwarding and service exposure respect the compute driver's admitted target +ports. Modern drivers reject unsupported or unadmitted ports before create +provisioning or a local listener starts. Shared-host loopback scope means the +target shares the compute host's network namespace; choose a different local +port when the target already occupies that host port. + Manage or iterate on the sandbox: ```bash From ce59971fbcb318067e4955dcb050c1fcefbdf2c0 Mon Sep 17 00:00:00 2001 From: Shiju Date: Wed, 4 Nov 2026 12:39:57 +0530 Subject: [PATCH 2/3] docs: focus service forwarding guidance on user actions Signed-off-by: Shiju --- crates/openshell-sdk/README.md | 4 +--- docs/extensibility/isolation-backends.mdx | 17 ++++------------- docs/how-it-works/sandboxes/overview.mdx | 13 +++++-------- skills/openshell-cli/SKILL.md | 7 ++----- 4 files changed, 12 insertions(+), 29 deletions(-) diff --git a/crates/openshell-sdk/README.md b/crates/openshell-sdk/README.md index a22b5f39ef..da180b8ce2 100644 --- a/crates/openshell-sdk/README.md +++ b/crates/openshell-sdk/README.md @@ -215,8 +215,6 @@ These helpers use the raw client's authentication slot. They do not perform OIDC ## Next minor API migration -This source-breaking API change targets the next minor release and must not be backported into the `0.1.x` patch series. - 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()`. -Legacy wire payloads retain their field identities and decode the new fields as absent or empty. Upgrade gateway writers together because older writers can drop the admitted record. With a driver that negotiates ingress admission, the gateway rejects forwarding without that record until the sandbox is recreated with admitted ports. Legacy drivers that do not negotiate admission can still omit it. +Upgrade gateway replicas together. If forwarding reports missing admission after an upgrade, recreate the sandbox with the required service ports. diff --git a/docs/extensibility/isolation-backends.mdx b/docs/extensibility/isolation-backends.mdx index b256a79f93..c8743a6555 100644 --- a/docs/extensibility/isolation-backends.mdx +++ b/docs/extensibility/isolation-backends.mdx @@ -40,14 +40,8 @@ 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 -an immutable ingress envelope from `ValidateSandboxCreate`: unsupported, -isolated loopback, or explicitly admitted shared-host loopback, with all ports -or an exact port set. The gateway checks create-time forwarding and exposure -requests before provisioning and retains the envelope in sandbox status. -Forwarding clients check it before opening local listeners; the gateway also -checks live TCP relays and HTTP service routing before reusing connections. -The isolation backend remains responsible for enforcing the target connection. -Legacy absence is distinct from missing evidence under the negotiated contract. +the supported forwarding scope and allowed ports from `ValidateSandboxCreate`. +The isolation backend must enforce those limits when connecting to a service. ## Who Owns What @@ -63,8 +57,5 @@ workload behavior, refer to [Runtimes](/how-it-works/sandboxes/runtimes). ## Release compatibility -These API changes target the next minor release and must not be backported into the `0.1.x` patch series. Upgrade gateway replicas together because older writers can drop the admitted ingress record. - -If a driver negotiated ingress admission but an existing sandbox has no retained record, recreate the sandbox with its required ports. A legacy driver that does not negotiate admission can still omit the record. - -For raw message changes, see the [SDK migration notes](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-sdk/README.md#next-minor-api-migration). +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 a28e817091..37abfcfa22 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -826,14 +826,11 @@ Press `c` in the Sandboxes panel to create a sandbox. In the optional Command fi ## Port Forwarding -Compute drivers can restrict forwarding to an admitted set of ports. Declare -forward ports when creating the sandbox; unadmitted targets are rejected before -provisioning or opening a local listener. `openshell sandbox get -o json` -shows `ingress_admission` with its scope, port list and `all_ports` flag. A -`shared_host_loopback` scope refers to an operator-approved host service, rather -than a service isolated inside the sandbox. If an upgraded driver reports -unknown or missing admission for an existing sandbox, recreate it with the -required ports. A legacy driver leaves admission absent. +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: diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index 32ee319ba9..5d9e98e766 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -823,11 +823,8 @@ 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. -Forwarding and service exposure respect the compute driver's admitted target -ports. Modern drivers reject unsupported or unadmitted ports before create -provisioning or a local listener starts. Shared-host loopback scope means the -target shares the compute host's network namespace; choose a different local -port when the target already occupies that host port. +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: From 2f477fac2fbabedfae8c77e1c1acf4c714d78164 Mon Sep 17 00:00:00 2001 From: Matthew Grossman Date: Tue, 3 Nov 2026 23:14:00 +0000 Subject: [PATCH 3/3] fix(tests): pin the k3s installer to a release (#5223) get.k3s.io serves the latest install.sh from k3s master, so the pinned checksum broke when upstream changed the script. Download install.sh from the release tag matching k3s_version instead and pin its checksum. Signed-off-by: Matthew Grossman Signed-off-by: Shiju --- tests/tmachine/ansible/playbooks/k3s.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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"