From 0a26bcc5506e799b18c8fa1c586deada7578591a Mon Sep 17 00:00:00 2001 From: sjenning <493891+sjenning@users.noreply.github.com> Date: Thu, 15 Oct 2026 15:18:42 -0500 Subject: [PATCH 01/23] feat(gateway): add storage-preserving sandbox image updates Add image-only UpdateSandbox with conditional versions, durable replay, fenced pending intent, and Kubernetes storage retention. Enable non-destructive image repair after completed timeout cleanup and exercise both Kubernetes controller API lanes. Closes #4623 Signed-off-by: sjenning <493891+sjenning@users.noreply.github.com> --- .agents/skills/helm-dev-environment/SKILL.md | 4 + Cargo.lock | 2 + .../tests/ensure_providers_integration.rs | 7 + .../openshell-cli/tests/mtls_integration.rs | 7 + .../tests/provider_commands_integration.rs | 7 + .../sandbox_create_lifecycle_integration.rs | 7 + .../sandbox_exec_streaming_integration.rs | 7 + .../sandbox_name_fallback_integration.rs | 7 + .../openshell-core/src/extension_protocol.rs | 3 + crates/openshell-driver-docker/src/lib.rs | 20 + crates/openshell-driver-kubernetes/Cargo.toml | 2 + crates/openshell-driver-kubernetes/README.md | 17 + .../openshell-driver-kubernetes/src/driver.rs | 5 +- .../openshell-driver-kubernetes/src/grpc.rs | 20 + .../src/image_update.rs | 455 +++ .../src/image_update_tests.rs | 658 ++++ crates/openshell-driver-mxc/src/grpc.rs | 10 + crates/openshell-driver-podman/src/grpc.rs | 10 + crates/openshell-driver-vm/src/driver.rs | 10 + .../src/routes.rs | 1 + crates/openshell-otel/src/grpc.rs | 6 + crates/openshell-sdk/src/raw.rs | 12 +- crates/openshell-sdk/tests/client_mock.rs | 7 + .../src/compute/image_update.rs | 802 +++++ crates/openshell-server/src/compute/mod.rs | 127 +- .../src/compute/tests/error_recovery.rs | 68 +- crates/openshell-server/src/grpc/mod.rs | 7 + .../src/grpc/mutation_replay/ordinary.rs | 5 + crates/openshell-server/src/grpc/sandbox.rs | 72 + .../src/grpc/sandbox/image_update_tests.rs | 224 ++ crates/openshell-server/src/storage_proto.rs | 35 +- .../openshell-server/src/supervisor_pool.rs | 6 +- crates/openshell-server/src/test_support.rs | 39 + crates/openshell-server/tests/common/mod.rs | 7 + .../tests/supervisor_relay_integration.rs | 7 + docs/how-it-works/sandboxes/overview.mdx | 48 + docs/sdk/api-errors.mdx | 33 +- e2e/rust/Cargo.lock | 792 ++++- e2e/rust/Cargo.toml | 9 +- e2e/rust/tests/kubernetes_image_update.rs | 424 +++ examples/isolation-backend-v8/src/driver.rs | 9 + proto/compute_driver.proto | 28 + proto/openshell.proto | 40 + .../v1/internal/converter/coverage_test.go | 4 +- sdk/go/proto/openshellv1/openshell.pb.go | 3131 +++++++++-------- sdk/go/proto/openshellv1/openshell_grpc.pb.go | 42 + skills/openshell-cli/SKILL.md | 26 + tasks/test.toml | 5 +- 48 files changed, 5703 insertions(+), 1571 deletions(-) create mode 100644 crates/openshell-driver-kubernetes/src/image_update.rs create mode 100644 crates/openshell-driver-kubernetes/src/image_update_tests.rs create mode 100644 crates/openshell-server/src/compute/image_update.rs create mode 100644 crates/openshell-server/src/grpc/sandbox/image_update_tests.rs create mode 100644 e2e/rust/tests/kubernetes_image_update.rs diff --git a/.agents/skills/helm-dev-environment/SKILL.md b/.agents/skills/helm-dev-environment/SKILL.md index 47df909f32..52b1d0bd48 100644 --- a/.agents/skills/helm-dev-environment/SKILL.md +++ b/.agents/skills/helm-dev-environment/SKILL.md @@ -421,6 +421,10 @@ above) instead of relying only on `OPENSHELL_GATEWAY_ENDPOINT`; some tests call ### Kubernetes E2E Notes Use `mise run e2e:kubernetes` for the standard Helm-backed Kubernetes suite. +Set `OPENSHELL_E2E_KUBE_TEST=kubernetes_image_update` to scope the Rust suite to +image replacement with retained sandbox, SSH, and PVC identities. This target is +included in both existing Agent Sandbox API-version lanes; unlike the Python +Docker suite, it exercises the driver that supports image updates. The kube e2e wrapper creates only one port-forward, to `svc/openshell`; it no longer forwards the unauthenticated health listener or runs a `/readyz` e2e target. `/readyz` remains covered by server unit/integration tests. diff --git a/Cargo.lock b/Cargo.lock index 781481d94e..97aa0f6cf5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4546,7 +4546,9 @@ dependencies = [ "opentelemetry_sdk", "prost", "prost-types", + "rand 0.9.4", "rcgen", + "regex", "rustls", "serde", "serde_json", diff --git a/crates/openshell-cli/tests/ensure_providers_integration.rs b/crates/openshell-cli/tests/ensure_providers_integration.rs index be3e4f2e49..c74d95b03d 100644 --- a/crates/openshell-cli/tests/ensure_providers_integration.rs +++ b/crates/openshell-cli/tests/ensure_providers_integration.rs @@ -87,6 +87,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } + async fn update_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented by test service")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/mtls_integration.rs b/crates/openshell-cli/tests/mtls_integration.rs index 1017712035..3b130be446 100644 --- a/crates/openshell-cli/tests/mtls_integration.rs +++ b/crates/openshell-cli/tests/mtls_integration.rs @@ -39,6 +39,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } + async fn update_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented by test service")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/provider_commands_integration.rs b/crates/openshell-cli/tests/provider_commands_integration.rs index 89247ba718..124ac62fab 100644 --- a/crates/openshell-cli/tests/provider_commands_integration.rs +++ b/crates/openshell-cli/tests/provider_commands_integration.rs @@ -242,6 +242,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } + async fn update_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented by test service")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs index db9c02ffaf..29dd638d70 100644 --- a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs +++ b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs @@ -108,6 +108,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } + async fn update_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented by test service")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs b/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs index 31e67baf0f..2c463f2466 100644 --- a/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs +++ b/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs @@ -163,6 +163,13 @@ macro_rules! mock_gateway { ) => { #[tonic::async_trait] impl OpenShell for MockGateway { + async fn update_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented by test service")) + } + $(async fn $method(&self, _: Request<$request>) -> Result, Status> { Err(Status::unimplemented("unused test RPC")) })* diff --git a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs index 497f3ce778..e6f38ec7af 100644 --- a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs +++ b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs @@ -54,6 +54,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } + async fn update_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented by test service")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-core/src/extension_protocol.rs b/crates/openshell-core/src/extension_protocol.rs index 0776cd0f2c..370c642bce 100644 --- a/crates/openshell-core/src/extension_protocol.rs +++ b/crates/openshell-core/src/extension_protocol.rs @@ -25,6 +25,9 @@ pub const COMPUTE_ISOLATION_BACKEND: &str = "openshell.compute.isolation-backend /// Driver implements `SuspendSandbox` and resuming through `StartSandbox`. pub const COMPUTE_SUSPEND_RESUME: &str = "openshell.compute.suspend-resume"; +/// Optional stopped-state image updates retaining the resource and its storage. +pub const COMPUTE_UPDATE_SANDBOX_IMAGE: &str = "openshell.compute.update-sandbox-image"; + const MAX_IMPLEMENTATION_NAME_BYTES: usize = 128; const MAX_IMPLEMENTATION_VERSION_BYTES: usize = 128; const MAX_CAPABILITY_BYTES: usize = 128; diff --git a/crates/openshell-driver-docker/src/lib.rs b/crates/openshell-driver-docker/src/lib.rs index 453c5c3afa..803f7e537f 100644 --- a/crates/openshell-driver-docker/src/lib.rs +++ b/crates/openshell-driver-docker/src/lib.rs @@ -3158,6 +3158,16 @@ fn validate_docker_outer_fence( } #[tonic::async_trait] impl ComputeDriver for ComputeDriverService { + async fn update_sandbox_image( + &self, + _request: Request, + ) -> Result, Status> + { + Err(Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } + type WatchSandboxesStream = WatchStream; async fn authenticate_sandbox( @@ -3320,6 +3330,16 @@ impl ComputeDriver for ComputeDriverService { #[tonic::async_trait] impl ComputeDriver for DockerComputeDriver { + async fn update_sandbox_image( + &self, + _request: Request, + ) -> Result, Status> + { + Err(Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } + async fn authenticate_sandbox( &self, _request: Request, diff --git a/crates/openshell-driver-kubernetes/Cargo.toml b/crates/openshell-driver-kubernetes/Cargo.toml index 1fc7c7d00a..37df72f614 100644 --- a/crates/openshell-driver-kubernetes/Cargo.toml +++ b/crates/openshell-driver-kubernetes/Cargo.toml @@ -43,6 +43,8 @@ tracing-subscriber = { workspace = true } thiserror = { workspace = true } miette = { workspace = true } notify = "8" +rand = { workspace = true } +regex = { workspace = true } rcgen = { workspace = true } bytes = { workspace = true } http = { workspace = true } diff --git a/crates/openshell-driver-kubernetes/README.md b/crates/openshell-driver-kubernetes/README.md index dc5abcaf48..59d3f709ca 100644 --- a/crates/openshell-driver-kubernetes/README.md +++ b/crates/openshell-driver-kubernetes/README.md @@ -302,6 +302,23 @@ storage. The driver confirms the stop from both the published `Suspended` condition and deletion of the backing pod. Legacy `v1alpha1` controllers omit a usable stopped condition, so pod deletion alone confirms their stop. +The optional `openshell.compute.update-sandbox-image` capability supports +image-only updates while the sandbox is stopped. `UpdateSandboxImage` requires +the persisted Kubernetes runtime identity, current image, sandbox name, and a +stable operation ID with a monotonic image revision. The driver verifies that +the same Sandbox resource is suspended, runtime bootstrap has completed, and +no workload or supervisor Pods +remain, then revalidates stored external-resource admission. It patches only +the agent image, the workspace seed image, and dedicated operation evidence, +using the resource UID and `resourceVersion` as concurrency guards. A repeat of +the same completed operation succeeds without a second patch; a different +current image, stale revision, or reused operation ID with different parameters +fails closed. A stale operation cannot reapply an image after a later update +returns to an earlier tag. Image updates do not delete or recreate the Sandbox resource, PVCs, mounts, +trusted runtime images, or bootstrap annotations. They leave the sandbox +stopped. Existing workspace contents and the seed sentinel remain unchanged, +so an image update does not replace files already stored under `/sandbox`. + The workspace PVC size defaults to `workspace_default_storage_size`. Set `workspace_storage_class` to pin the PVC to a specific `StorageClass`; an empty value omits `storageClassName` so the cluster's default `StorageClass` applies. diff --git a/crates/openshell-driver-kubernetes/src/driver.rs b/crates/openshell-driver-kubernetes/src/driver.rs index 65be627dc9..f5a717abfc 100644 --- a/crates/openshell-driver-kubernetes/src/driver.rs +++ b/crates/openshell-driver-kubernetes/src/driver.rs @@ -90,6 +90,9 @@ use tokio::sync::{OnceCell, mpsc}; use tokio_stream::wrappers::ReceiverStream; use tracing::{debug, info, warn}; +#[path = "image_update.rs"] +mod image_update; + pub type WatchStream = Pin> + Send>>; @@ -1341,7 +1344,7 @@ impl KubernetesComputeDriver { openshell_core::extension_protocol::ExtensionFamily::Compute, "openshell/kubernetes", openshell_core::VERSION, - [], + [openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.to_string()], )), }) } diff --git a/crates/openshell-driver-kubernetes/src/grpc.rs b/crates/openshell-driver-kubernetes/src/grpc.rs index ddfaac8b10..108c9ffbd5 100644 --- a/crates/openshell-driver-kubernetes/src/grpc.rs +++ b/crates/openshell-driver-kubernetes/src/grpc.rs @@ -224,6 +224,26 @@ impl ComputeDriver for ComputeDriverService { .await } + async fn update_sandbox_image( + &self, + request: Request, + ) -> Result, Status> + { + self.rpc_tracer + .trace(openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, async { + self.driver + .update_sandbox_image(&request.into_inner()) + .await + .map_err(|error| { + Status::from(openshell_core::ComputeDriverError::from(error)) + })?; + Ok(Response::new( + openshell_core::proto::compute::v1::UpdateSandboxImageResponse {}, + )) + }) + .await + } + async fn delete_sandbox( &self, request: Request, diff --git a/crates/openshell-driver-kubernetes/src/image_update.rs b/crates/openshell-driver-kubernetes/src/image_update.rs new file mode 100644 index 0000000000..fe7f805fc6 --- /dev/null +++ b/crates/openshell-driver-kubernetes/src/image_update.rs @@ -0,0 +1,455 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Storage-preserving, stopped-only workload image mutation. + +use super::{ + KUBE_API_TIMEOUT, KubernetesComputeDriver, KubernetesDriverError, LABEL_SANDBOX_ID, + LABEL_SANDBOX_NAME, SANDBOX_POD_NAME_ANNOTATION, SANDBOX_VERSION_V1BETA1, + WORKSPACE_INIT_CONTAINER_NAME, accepts_auth_namespace, admission_error, annotation_or_label, + is_kube_resource_version_conflict, parse_kubernetes_runtime_identity, sandbox_id_from_object, + sandbox_runtime_bootstrap_in_progress, select_expected_sandbox_runtime, +}; +use k8s_openapi::api::core::v1::Pod; +use kube::Api; +use kube::api::{DynamicObject, ListParams, Patch, PatchParams}; +use openshell_core::proto::compute::v1::UpdateSandboxImageRequest; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use std::sync::LazyLock; + +// Deliberately separate from the runtime bootstrap operation annotations. Those +// annotations drive reconciliation and only describe create/start/stop. +const IMAGE_UPDATE_ANNOTATION: &str = "openshell.ai/sandbox-image-update"; + +#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] +struct ImageUpdateRecord { + operation_id: String, + expected_image: String, + image: String, + revision: u64, +} + +impl KubernetesComputeDriver { + /// Update only a suspended Sandbox's workload and workspace seed images. + /// The resource, claim templates, existing claims, and runtime bootstrap + /// annotations are never replaced. A retry is recognized from durable + /// operation evidence on the same immutable Sandbox resource. + #[tracing::instrument( + name = "kubernetes.update_sandbox_image", + skip_all, + fields( + otel.name = "kubernetes.update_sandbox_image", + otel.status_code = tracing::field::Empty, + sandbox.id = %request.sandbox_id, + ) + )] + pub async fn update_sandbox_image( + &self, + request: &UpdateSandboxImageRequest, + ) -> Result<(), KubernetesDriverError> { + let span_status = openshell_otel::ErrorStatusGuard::current(); + validate_image_update_request(request)?; + let _guard = self + .lifecycle_gates + .gate_for(&request.sandbox_id) + .lock_owned() + .await; + // Include discovery, admission and Pod pagination in a single bound. + let result = + tokio::time::timeout(KUBE_API_TIMEOUT, self.update_sandbox_image_inner(request)) + .await + .unwrap_or_else(|_| { + Err(KubernetesDriverError::Message( + "timed out updating Kubernetes sandbox image; retry the same operation" + .into(), + )) + }); + span_status.finish(result) + } + + async fn update_sandbox_image_inner( + &self, + request: &UpdateSandboxImageRequest, + ) -> Result<(), KubernetesDriverError> { + let expected = parse_kubernetes_runtime_identity(&request.expected_runtime_identity)?; + self.wait_for_operator_allowlist() + .await + .map_err(admission_error)?; + if !accepts_auth_namespace( + &self.config, + self.operator_allowlist.as_ref(), + &expected.namespace, + ) { + return Err(KubernetesDriverError::Precondition( + "persisted runtime namespace is outside the driver's configured scope".into(), + )); + } + let lookup = self + .supported_sandbox_api_for_lookup(self.client.clone()) + .await + .map_err(KubernetesDriverError::Message)?; + let objects = lookup + .api + .list(&ListParams::default().labels(&self.sandbox_lookup_selector(&request.sandbox_id))) + .await + .map_err(KubernetesDriverError::from_kube)? + .items; + let selected = select_expected_sandbox_runtime(objects, &expected)?; + let name = selected.metadata.name.as_deref().ok_or_else(|| { + KubernetesDriverError::Precondition("Sandbox resource has no name".into()) + })?; + let api = Self::agent_sandbox_api( + self.client.clone(), + &lookup.resource.version, + &expected.namespace, + ); + // Refresh after selection, then use exactly this snapshot's version in + // the patch. Never retry a resourceVersion conflict with a stale image, + // attachment inventory or operating-state decision. + let object = api + .api + .get(name) + .await + .map_err(KubernetesDriverError::from_kube)?; + let object = select_expected_sandbox_runtime(vec![object], &expected)?; + if sandbox_id_from_object(&object).as_deref() != Ok(request.sandbox_id.as_str()) + || annotation_or_label(&object, LABEL_SANDBOX_NAME).as_deref() + != Some(request.name.as_str()) + { + return Err(KubernetesDriverError::Precondition( + "Sandbox resource does not match the requested sandbox identity".into(), + )); + } + require_stopped_for_image_update(&object, &lookup.resource.version)?; + let mut candidate = object.clone(); + let repeat = prepare_image_update(&mut candidate, request)?; + // Revalidate the saved provenance and attachment UIDs against current + // operator policy, even for retries. Do not manufacture new provenance + // or re-render driver_config from a caller's request. + self.admit_stored_resources(&candidate) + .await + .map_err(admission_error)?; + self.require_image_update_pods_absent(&object, &request.sandbox_id, &expected.namespace) + .await?; + if request.validate_only || repeat { + return Ok(()); + } + let version = object + .metadata + .resource_version + .as_deref() + .filter(|version| !version.is_empty()) + .ok_or_else(|| { + KubernetesDriverError::Precondition( + "Sandbox resource has no resourceVersion".into(), + ) + })?; + let record = candidate + .metadata + .annotations + .as_ref() + .and_then(|annotations| annotations.get(IMAGE_UPDATE_ANNOTATION)) + .expect("prepared image update has operation evidence"); + let mut patch = serde_json::json!({ + "metadata": { + "uid": expected.resource_uid, + "resourceVersion": version, + "annotations": {IMAGE_UPDATE_ANNOTATION: record} + }, + "spec": {"podTemplate": {"spec": { + "containers": candidate.data["spec"]["podTemplate"]["spec"]["containers"] + }}} + }); + if let Some(init) = candidate + .data + .pointer("/spec/podTemplate/spec/initContainers") + { + patch["spec"]["podTemplate"]["spec"]["initContainers"] = init.clone(); + } + api.api + .patch(name, &PatchParams::default(), &Patch::Merge(&patch)) + .await + .map_err(|error| { + if is_kube_resource_version_conflict(&error) { + KubernetesDriverError::Precondition( + "Sandbox changed during image update; retry the same operation".into(), + ) + } else { + KubernetesDriverError::from_kube(error) + } + })?; + Ok(()) + } + + async fn require_image_update_pods_absent( + &self, + object: &DynamicObject, + sandbox_id: &str, + namespace: &str, + ) -> Result<(), KubernetesDriverError> { + let pods = Api::::namespaced(self.client.clone(), namespace); + // The controller's workload Pod need not carry the OpenShell sandbox + // label. Inspect owner UIDs and recorded names as well as labels and + // annotations, and reject terminating Pods too. Listing the namespace + // also catches supervisors from earlier runtime generations. + let mut params = ListParams::default().limit(500); + loop { + let page = pods + .list(¶ms) + .await + .map_err(KubernetesDriverError::from_kube)?; + if page + .items + .iter() + .any(|pod| image_update_pod_matches(pod, object, sandbox_id)) + { + return Err(KubernetesDriverError::Precondition( + "cannot update image while sandbox workload or supervisor Pods still exist" + .into(), + )); + } + match page.metadata.continue_.filter(|token| !token.is_empty()) { + Some(token) => params = params.continue_token(&token), + None => return Ok(()), + } + } + } +} + +fn validate_image_update_request( + request: &UpdateSandboxImageRequest, +) -> Result<(), KubernetesDriverError> { + for (field, value) in [ + ("sandbox_id", request.sandbox_id.as_str()), + ("name", request.name.as_str()), + ("operation_id", request.operation_id.as_str()), + ] { + if value.is_empty() + || value.len() > 1024 + || value.trim() != value + || value.chars().any(char::is_control) + { + return Err(KubernetesDriverError::InvalidArgument(format!( + "{field} must be a nonempty bounded identifier" + ))); + } + } + if request.revision == 0 { + return Err(KubernetesDriverError::InvalidArgument( + "image update revision must be nonzero".into(), + )); + } + validate_workload_image(&request.image)?; + // The old reference is only a compare-and-swap precondition, not a new + // launch input. Legacy create accepted references that kubelet cannot pull; + // validating their syntax here would prevent repairing those sandboxes. + if request.expected_image.is_empty() || request.expected_image.len() > 2048 { + return Err(KubernetesDriverError::InvalidArgument( + "expected_image must be a nonempty bounded reference".into(), + )); + } + Ok(()) +} + +fn validate_workload_image(image: &str) -> Result<(), KubernetesDriverError> { + // Distribution reference grammar: registry (including a port or bracketed + // IPv6), lowercase repository path, optional tag and/or algorithm:digest. + // Validation is syntax only: resolving/pulling the image remains kubelet's + // job, using the existing operator-selected image-pull Secret inventory. + static REFERENCE: LazyLock = LazyLock::new(|| { + let host_component = r"[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?"; + let host = format!(r"(?:{host_component}(?:\.{host_component})*|\[[a-fA-F0-9:]+\])"); + let path = r"[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*"; + regex::Regex::new(&format!( + r"^(?:{host}(?::[0-9]+)?/)?{path}(?:/{path})*(?::[a-zA-Z0-9_][a-zA-Z0-9_.-]{{0,127}})?(?:@[a-zA-Z][a-zA-Z0-9]*(?:[-_+.][a-zA-Z][a-zA-Z0-9]*)*:[a-fA-F0-9]{{32,}})?$" + )).expect("valid distribution reference grammar") + }); + let named = image.split('@').next().unwrap_or_default(); + let repository = + named.rsplit_once(':').map_or( + named, + |(prefix, suffix)| { + if suffix.contains('/') { named } else { prefix } + }, + ); + let digest_length_valid = image.rsplit_once('@').is_none_or(|(_, digest)| { + digest + .split_once(':') + .is_some_and(|(algorithm, encoded)| match algorithm { + "sha256" => encoded.len() == 64, + "sha384" => encoded.len() == 96, + "sha512" => encoded.len() == 128, + _ => true, + }) + }); + if image.len() > 2048 + || repository.len() > 255 + || !digest_length_valid + || !REFERENCE.is_match(image) + { + return Err(KubernetesDriverError::InvalidArgument( + "image must be a valid container image reference of at most 2048 bytes".into(), + )); + } + Ok(()) +} + +fn require_stopped_for_image_update( + object: &DynamicObject, + version: &str, +) -> Result<(), KubernetesDriverError> { + let suspended = if version == SANDBOX_VERSION_V1BETA1 { + object + .data + .pointer("/spec/operatingMode") + .and_then(serde_json::Value::as_str) + == Some("Suspended") + } else { + object + .data + .pointer("/spec/replicas") + .and_then(serde_json::Value::as_i64) + == Some(0) + }; + if !suspended + || object.metadata.deletion_timestamp.is_some() + || sandbox_runtime_bootstrap_in_progress(object) + { + return Err(KubernetesDriverError::Precondition( + "image updates require a stopped, suspended sandbox with no runtime bootstrap in progress".into(), + )); + } + Ok(()) +} + +/// Apply the image-only mutation in memory; return true for an exact retry. +fn prepare_image_update( + object: &mut DynamicObject, + request: &UpdateSandboxImageRequest, +) -> Result { + let evidence = object + .metadata + .annotations + .as_ref() + .and_then(|annotations| annotations.get(IMAGE_UPDATE_ANNOTATION)) + .map(|value| serde_json::from_str::(value)) + .transpose() + .map_err(|_| { + KubernetesDriverError::Precondition("invalid stored image update evidence".into()) + })?; + let record = ImageUpdateRecord { + operation_id: request.operation_id.clone(), + expected_image: request.expected_image.clone(), + image: request.image.clone(), + revision: request.revision, + }; + if let Some(saved) = &evidence { + if request.revision < saved.revision { + return Err(KubernetesDriverError::Precondition( + "image update revision is older than the stored image revision".into(), + )); + } + if request.revision == saved.revision && saved != &record { + return Err(KubernetesDriverError::Precondition( + "image update revision was already used with different operation parameters".into(), + )); + } + if saved.operation_id == request.operation_id && saved != &record { + return Err(KubernetesDriverError::Precondition( + "image update operation_id was already used with different parameters".into(), + )); + } + } + let repeat = evidence.as_ref() == Some(&record); + let containers = object + .data + .pointer_mut("/spec/podTemplate/spec/containers") + .and_then(serde_json::Value::as_array_mut) + .ok_or_else(|| { + KubernetesDriverError::Precondition("Sandbox has no workload containers".into()) + })?; + let mut agents = containers + .iter_mut() + .filter(|container| container["name"] == "agent"); + let agent = agents.next().ok_or_else(|| { + KubernetesDriverError::Precondition("Sandbox has no agent container".into()) + })?; + if agents.next().is_some() { + return Err(KubernetesDriverError::Precondition( + "Sandbox has multiple agent containers".into(), + )); + } + let expected: &str = if repeat { + &request.image + } else { + &request.expected_image + }; + if agent["image"].as_str() != Some(expected) { + return Err(KubernetesDriverError::Precondition( + "Sandbox workload image does not match expected_image or the recorded operation target" + .into(), + )); + } + agent["image"] = serde_json::json!(request.image); + if let Some(init) = object + .data + .pointer_mut("/spec/podTemplate/spec/initContainers") + .and_then(serde_json::Value::as_array_mut) + { + for container in init + .iter_mut() + .filter(|container| container["name"] == WORKSPACE_INIT_CONTAINER_NAME) + { + if container["image"].as_str() != Some(expected) { + return Err(KubernetesDriverError::Precondition( + "Sandbox workspace seed image does not match its workload image".into(), + )); + } + container["image"] = serde_json::json!(request.image); + } + } + object + .metadata + .annotations + .get_or_insert_with(BTreeMap::new) + .insert( + IMAGE_UPDATE_ANNOTATION.into(), + serde_json::to_string(&record).expect("image update record serializes"), + ); + Ok(repeat) +} + +fn image_update_pod_matches(pod: &Pod, object: &DynamicObject, sandbox_id: &str) -> bool { + let metadata = &pod.metadata; + metadata.owner_references.as_ref().is_some_and(|owners| { + owners + .iter() + .any(|owner| Some(owner.uid.as_str()) == object.metadata.uid.as_deref()) + }) || metadata + .labels + .as_ref() + .and_then(|labels| labels.get(LABEL_SANDBOX_ID)) + .map(String::as_str) + == Some(sandbox_id) + || metadata + .annotations + .as_ref() + .and_then(|annotations| annotations.get(LABEL_SANDBOX_ID)) + .map(String::as_str) + == Some(sandbox_id) + || metadata.name.as_deref().is_some_and(|name| { + Some(name) == object.metadata.name.as_deref() + || object + .metadata + .annotations + .as_ref() + .and_then(|annotations| annotations.get(SANDBOX_POD_NAME_ANNOTATION)) + .map(String::as_str) + == Some(name) + }) +} + +#[cfg(test)] +#[path = "image_update_tests.rs"] +mod tests; diff --git a/crates/openshell-driver-kubernetes/src/image_update_tests.rs b/crates/openshell-driver-kubernetes/src/image_update_tests.rs new file mode 100644 index 0000000000..ba1fa44185 --- /dev/null +++ b/crates/openshell-driver-kubernetes/src/image_update_tests.rs @@ -0,0 +1,658 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use super::super::{ + ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_OPERATION, ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_PHASE, + ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAPPING, ANNOTATION_SANDBOX_RUNTIME_LOG_LEVEL, + ANNOTATION_SANDBOX_RUNTIME_MAIN_PROCESS_SPEC, ANNOTATION_SANDBOX_RUNTIME_READINESS, + KubernetesComputeConfig, LABEL_SANDBOX_WORKSPACE, OperatorNamespaceAllowlist, + SANDBOX_BOOTSTRAP_CONTAINER_NAME, SANDBOX_BOOTSTRAP_VOLUME_NAME, SANDBOX_GROUP, + SANDBOX_VERSION_V1ALPHA1, WORKSPACE_INIT_MOUNT_PATH, WorkspaceMode, +}; +use super::*; +use http_body_util::BodyExt as _; +use kube::Client; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use tokio::sync::OnceCell; + +struct ApiState { + sandbox: serde_json::Value, + pvc: serde_json::Value, + pods: Vec, + calls: Vec<(http::Method, String)>, + patches: Vec, + conflict: bool, + pods_continue: bool, +} + +fn response( + status: http::StatusCode, + value: serde_json::Value, +) -> http::Response { + http::Response::builder() + .status(status) + .header(http::header::CONTENT_TYPE, "application/json") + .body(kube::client::Body::from(value.to_string().into_bytes())) + .unwrap() +} + +fn merge(target: &mut serde_json::Value, patch: &serde_json::Value) { + if let Some(patch) = patch.as_object() { + for (key, value) in patch { + if value.is_null() { + target.as_object_mut().unwrap().remove(key); + } else { + if target.get(key).is_none() { + target[key] = serde_json::Value::Null; + } + if value.is_object() && !target[key].is_object() { + target[key] = serde_json::json!({}); + } + merge(&mut target[key], value); + } + } + } else { + *target = patch.clone(); + } +} + +fn snapshot(version: &str) -> serde_json::Value { + let mut value = serde_json::json!({ + "apiVersion": format!("{SANDBOX_GROUP}/{version}"), + "kind": "Sandbox", + "metadata": { + "name": "sandbox-cr", "namespace": "openshell", "uid": "resource-uid", + "resourceVersion": "42", "generation": 7, + "labels": {LABEL_SANDBOX_ID: "sandbox-1", LABEL_SANDBOX_NAME: "sandbox-name", LABEL_SANDBOX_WORKSPACE: "team-a"}, + "annotations": { + LABEL_SANDBOX_ID: "sandbox-1", LABEL_SANDBOX_NAME: "sandbox-name", + crate::resource_admission::CONFIG_USED: "true", + crate::resource_admission::IDENTITIES: "{\"PersistentVolumeClaim/openshell/team-data\":\"data-pvc-uid\"}", + "operator.example/bootstrap-provenance": "preserve-me", + ANNOTATION_SANDBOX_RUNTIME_MAIN_PROCESS_SPEC: "stored-launch-spec", + ANNOTATION_SANDBOX_RUNTIME_LOG_LEVEL: "info", + ANNOTATION_SANDBOX_RUNTIME_READINESS: "unavailable", + ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAPPING: "false", + ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_OPERATION: "restart", + ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_PHASE: "released", + SANDBOX_POD_NAME_ANNOTATION: "recorded-workload" + }, + "ownerReferences": [{"apiVersion":"v1", "kind":"Namespace", "name":"openshell", "uid":"namespace-uid"}] + }, + "spec": { + "volumeClaimTemplates": [{"metadata":{"name":"workspace"}, "spec":{"accessModes":["ReadWriteOnce"], "resources":{"requests":{"storage":"10Gi"}}}}], + "podTemplate": { + "metadata": {"annotations": {"operator.example/pod-injection": "preserved"}}, + "spec": { + "automountServiceAccountToken": false, + "serviceAccountName": "openshell-sandbox", + "imagePullSecrets": [{"name":"operator-registry"}], + "volumes": [ + {"name": SANDBOX_BOOTSTRAP_VOLUME_NAME, "secret":{"secretName":"old-bootstrap-secret"}}, + {"name":"data", "persistentVolumeClaim":{"claimName":"team-data", "readOnly":false}} + ], + "containers": [ + {"name":"agent", "image":"registry.example/agent:v1", "command":["/.openshell/runtime/openshell-sandbox"], "env":[{"name":"UNCHANGED","value":"yes"}], "volumeMounts":[{"name":"workspace", "mountPath":"/sandbox"}, {"name":"data", "mountPath":"/data", "subPath":"agent"}]}, + {"name":"operator-sidecar", "image":"registry.example/agent:v1"} + ], + "initContainers": [ + {"name":SANDBOX_BOOTSTRAP_CONTAINER_NAME, "image":"trusted-runtime:v3"}, + {"name":WORKSPACE_INIT_CONTAINER_NAME, "image":"registry.example/agent:v1", "command":["seed-workspace"], "volumeMounts":[{"name":"workspace", "mountPath":WORKSPACE_INIT_MOUNT_PATH}]}, + {"name":"operator-init", "image":"registry.example/agent:v1"} + ] + } + } + }, + "status":{"conditions":[{"type":"Suspended", "status":"True", "observedGeneration":7}]} + }); + if version == SANDBOX_VERSION_V1BETA1 { + value["spec"]["operatingMode"] = serde_json::json!("Suspended"); + } else { + value["spec"]["replicas"] = serde_json::json!(0); + } + value +} + +fn fixture( + version: &'static str, + operator: bool, +) -> (KubernetesComputeDriver, Arc>) { + let state = Arc::new(Mutex::new(ApiState { + sandbox: snapshot(version), + pvc: serde_json::json!({ + "apiVersion":"meta.k8s.io/v1", "kind":"PartialObjectMetadata", + "metadata": {"name":"team-data", "namespace":"openshell", "uid":"data-pvc-uid", + "labels": {"openshell.ai/sandbox-attachable":"true", "openshell.ai/sandbox-attachable-workspace":"team-a"}} + }), + pods: Vec::new(), + calls: Vec::new(), + patches: Vec::new(), + conflict: false, + pods_continue: false, + })); + let service_state = state.clone(); + let service = tower::service_fn(move |request: http::Request| { + let state = service_state.clone(); + async move { + let path = request.uri().path().to_string(); + let query = request.uri().query().unwrap_or_default().to_string(); + let method = request.method().clone(); + let body = request.into_body().collect().await.unwrap().to_bytes(); + let mut state = state.lock().unwrap(); + state.calls.push((method.clone(), path.clone())); + let value = match (method, path.as_str()) { + (http::Method::GET, path) if path.ends_with("/sandboxes") => { + serde_json::json!({"apiVersion":format!("{SANDBOX_GROUP}/{version}"), "kind":"SandboxList", "metadata":{}, "items":[state.sandbox]}) + } + (http::Method::GET, path) if path.ends_with("/sandboxes/sandbox-cr") => { + state.sandbox.clone() + } + ( + http::Method::GET, + "/api/v1/namespaces/openshell/persistentvolumeclaims/team-data", + ) => state.pvc.clone(), + (http::Method::GET, "/api/v1/namespaces/openshell/pods") => { + if state.pods_continue && !query.contains("continue=") { + serde_json::json!({"apiVersion":"v1", "kind":"PodList", "metadata":{"continue":"page-two"}, "items":[]}) + } else { + serde_json::json!({"apiVersion":"v1", "kind":"PodList", "metadata":{}, "items":state.pods}) + } + } + (http::Method::PATCH, path) if path.ends_with("/sandboxes/sandbox-cr") => { + let mutation: serde_json::Value = serde_json::from_slice(&body).unwrap(); + assert_eq!( + mutation["metadata"]["uid"], + state.sandbox["metadata"]["uid"] + ); + assert_eq!( + mutation["metadata"]["resourceVersion"], + state.sandbox["metadata"]["resourceVersion"] + ); + state.patches.push(mutation.clone()); + if state.conflict { + return Ok::<_, std::convert::Infallible>(response( + http::StatusCode::CONFLICT, + serde_json::json!({"apiVersion":"v1", "kind":"Status", "status":"Failure", "reason":"Conflict", "message":"concurrent start or edit", "code":409}), + )); + } + let next_version = state.sandbox["metadata"]["resourceVersion"] + .as_str() + .unwrap() + .parse::() + .unwrap() + + 1; + let next_generation = + state.sandbox["metadata"]["generation"].as_u64().unwrap() + 1; + merge(&mut state.sandbox, &mutation); + state.sandbox["metadata"]["resourceVersion"] = + serde_json::json!(next_version.to_string()); + state.sandbox["metadata"]["generation"] = serde_json::json!(next_generation); + state.sandbox.clone() + } + (method, path) => { + panic!("unexpected image update Kubernetes request {method} {path}") + } + }; + Ok::<_, std::convert::Infallible>(response(http::StatusCode::OK, value)) + } + }); + let client = Client::new(service, "openshell"); + let api_version = OnceCell::new(); + api_version.set(version).unwrap(); + let driver = KubernetesComputeDriver { + client: client.clone(), + watch_client: client, + sandbox_api_version: Arc::new(api_version), + lifecycle_gates: Arc::default(), + shared_supervisor: None, + config: KubernetesComputeConfig { + allow_driver_config: true, + workspace_mode: if operator { + WorkspaceMode::Operator + } else { + WorkspaceMode::Shared + }, + ..Default::default() + }, + operator_allowlist: operator.then(|| { + OperatorNamespaceAllowlist::from_set(std::iter::once("openshell".to_string()).collect()) + }), + }; + (driver, state) +} + +fn request() -> UpdateSandboxImageRequest { + UpdateSandboxImageRequest { + sandbox_id: "sandbox-1".into(), + name: "sandbox-name".into(), + image: "registry.example/agent:v2".into(), + expected_image: "registry.example/agent:v1".into(), + expected_runtime_identity: "kubernetes://openshell/resource-uid/old-supervisor-uid".into(), + operation_id: "stable-operation-1".into(), + validate_only: false, + revision: 1, + } +} + +#[tokio::test] +async fn image_update_preflight_validates_without_writes_and_apply_rechecks() { + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + let before = state.lock().unwrap().sandbox.clone(); + let mut preflight = request(); + preflight.validate_only = true; + driver.update_sandbox_image(&preflight).await.unwrap(); + { + let state = state.lock().unwrap(); + assert!(state.patches.is_empty()); + assert_eq!(state.sandbox, before); + assert!( + state + .calls + .iter() + .any(|(_, path)| path.ends_with("/persistentvolumeclaims/team-data")) + ); + assert!(state.calls.iter().any(|(_, path)| path.ends_with("/pods"))); + } + // Operator approval can change between preflight and apply. Both requests + // independently enforce the entire stopped/admission check. + state.lock().unwrap().pvc["metadata"]["labels"] = serde_json::json!({}); + assert!(matches!( + driver.update_sandbox_image(&request()).await, + Err(KubernetesDriverError::Precondition(_)) + )); + assert!(matches!( + driver.update_sandbox_image(&preflight).await, + Err(KubernetesDriverError::Precondition(_)) + )); + assert!(state.lock().unwrap().patches.is_empty()); +} + +#[tokio::test] +async fn image_update_capability_is_optional() { + let (driver, _) = fixture(SANDBOX_VERSION_V1BETA1, false); + let metadata = driver.capabilities().unwrap().extension.unwrap(); + let capability = openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE; + assert!( + metadata + .supported_capabilities + .iter() + .any(|value| value == capability) + ); + assert!( + !metadata + .required_capabilities + .iter() + .any(|value| value == capability) + ); +} + +#[tokio::test] +async fn image_update_preserves_resource_storage_and_operator_bootstrap_annotations() { + for version in [SANDBOX_VERSION_V1BETA1, SANDBOX_VERSION_V1ALPHA1] { + for operator in [false, true] { + let (driver, state) = fixture(version, operator); + if operator { + // Operator-mode identity can live in bootstrap annotations + // rather than a caller-visible workload-name label. + state.lock().unwrap().sandbox["metadata"]["labels"] + .as_object_mut() + .unwrap() + .remove(LABEL_SANDBOX_NAME); + } + let before = state.lock().unwrap().sandbox.clone(); + let pvc_before = state.lock().unwrap().pvc.clone(); + driver.update_sandbox_image(&request()).await.unwrap(); + let state = state.lock().unwrap(); + let mut expected = before; + expected["metadata"]["resourceVersion"] = serde_json::json!("43"); + expected["metadata"]["generation"] = serde_json::json!(8); + expected["metadata"]["annotations"][IMAGE_UPDATE_ANNOTATION] = serde_json::json!( + serde_json::to_string(&ImageUpdateRecord { + operation_id: request().operation_id, + expected_image: request().expected_image, + image: request().image, + revision: request().revision, + }) + .unwrap() + ); + expected["spec"]["podTemplate"]["spec"]["containers"][0]["image"] = + serde_json::json!(request().image); + expected["spec"]["podTemplate"]["spec"]["initContainers"][1]["image"] = + serde_json::json!(request().image); + // Whole-object equality proves claim templates, mounts, owner UID, + // launch state, operator annotations, and trusted/sidecar images + // were preserved. The API rejects any unexpected DELETE/POST. + assert_eq!(state.sandbox, expected); + assert_eq!(state.pvc, pvc_before); + assert_eq!(state.patches.len(), 1); + assert_eq!( + state.patches[0]["metadata"]["annotations"] + .as_object() + .unwrap() + .len(), + 1 + ); + assert!( + state.patches[0]["spec"] + .get("volumeClaimTemplates") + .is_none() + ); + assert!( + state.patches[0]["spec"]["podTemplate"]["spec"] + .get("volumes") + .is_none() + ); + } + } +} + +#[tokio::test] +async fn image_update_retry_is_durable_and_does_not_patch_twice() { + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + driver.update_sandbox_image(&request()).await.unwrap(); + // Simulate a process restart by dropping the original in-memory gate state. + let mut restarted = driver.clone(); + restarted.lifecycle_gates = Arc::default(); + restarted.update_sandbox_image(&request()).await.unwrap(); + assert_eq!(state.lock().unwrap().patches.len(), 1); + let mut other_operation = request(); + other_operation.operation_id = "other-operation".into(); + other_operation.revision += 1; + assert!(matches!( + driver.update_sandbox_image(&other_operation).await, + Err(KubernetesDriverError::Precondition(_)) + )); + let mut reused_operation = request(); + reused_operation.image = "registry.example/agent:v3".into(); + assert!(matches!( + driver.update_sandbox_image(&reused_operation).await, + Err(KubernetesDriverError::Precondition(_)) + )); + assert_eq!(state.lock().unwrap().patches.len(), 1); +} + +#[tokio::test] +async fn image_update_monotonic_revision_rejects_late_replay_after_a_tag_round_trip() { + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + let a = request(); + driver.update_sandbox_image(&a).await.unwrap(); + let mut b = a.clone(); + b.expected_image = a.image.clone(); + b.image = a.expected_image.clone(); + b.operation_id = "operation-b".into(); + b.revision = 2; + driver.update_sandbox_image(&b).await.unwrap(); + let before = state.lock().unwrap().sandbox.clone(); + // The current tag again matches A's expected image, but its revision is + // stale. The latest evidence must reject A rather than reapply it. + assert!(matches!(driver.update_sandbox_image(&a).await, + Err(KubernetesDriverError::Precondition(message)) if message.contains("older"))); + let mut conflicting = a.clone(); + conflicting.operation_id = "different-operation-at-revision-2".into(); + conflicting.revision = b.revision; + assert!(matches!(driver.update_sandbox_image(&conflicting).await, + Err(KubernetesDriverError::Precondition(message)) if message.contains("revision was already used"))); + assert_eq!(state.lock().unwrap().patches.len(), 2); + assert_eq!(state.lock().unwrap().sandbox, before); + driver.update_sandbox_image(&b).await.unwrap(); + assert_eq!(state.lock().unwrap().patches.len(), 2); + conflicting.revision = 3; + driver.update_sandbox_image(&conflicting).await.unwrap(); + assert_eq!(state.lock().unwrap().patches.len(), 3); +} + +#[tokio::test] +async fn image_update_rejects_zero_revision_before_kubernetes_io() { + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + let mut request = request(); + request.revision = 0; + assert!(matches!( + driver.update_sandbox_image(&request).await, + Err(KubernetesDriverError::InvalidArgument(_)) + )); + assert!(state.lock().unwrap().calls.is_empty()); +} + +#[tokio::test] +async fn image_update_rejects_running_bootstrapping_and_unspecified_operating_state() { + for version in [SANDBOX_VERSION_V1BETA1, SANDBOX_VERSION_V1ALPHA1] { + for scenario in ["running", "bootstrap", "missing", "deleting"] { + let (driver, state) = fixture(version, false); + { + let mut state = state.lock().unwrap(); + match scenario { + "running" if version == SANDBOX_VERSION_V1BETA1 => { + state.sandbox["spec"]["operatingMode"] = serde_json::json!("Running"); + } + "running" => state.sandbox["spec"]["replicas"] = serde_json::json!(1), + "bootstrap" => { + state.sandbox["metadata"]["annotations"] + [ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAPPING] = serde_json::json!("true"); + } + "missing" => { + state.sandbox["spec"].as_object_mut().unwrap().remove( + if version == SANDBOX_VERSION_V1BETA1 { + "operatingMode" + } else { + "replicas" + }, + ); + } + "deleting" => { + state.sandbox["metadata"]["deletionTimestamp"] = + serde_json::json!("2026-10-15T18:00:00Z"); + } + _ => unreachable!(), + } + } + assert!( + matches!( + driver.update_sandbox_image(&request()).await, + Err(KubernetesDriverError::Precondition(_)) + ), + "{scenario} {version}" + ); + assert!(state.lock().unwrap().patches.is_empty()); + } + } +} + +#[tokio::test] +async fn image_update_checks_actual_workload_and_supervisor_pods_including_later_pages() { + for metadata in [ + serde_json::json!({"name":"controller-workload", "ownerReferences":[{"apiVersion":"agents.x-k8s.io/v1beta1", "kind":"Sandbox", "name":"sandbox-cr", "uid":"resource-uid"}]}), + serde_json::json!({"name":"supervisor", "labels":{LABEL_SANDBOX_ID:"sandbox-1"}}), + serde_json::json!({"name":"recorded-workload", "deletionTimestamp":"2026-10-15T18:00:00Z"}), + serde_json::json!({"name":"workload-with-annotation", "annotations":{LABEL_SANDBOX_ID:"sandbox-1"}}), + ] { + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + { + let mut state = state.lock().unwrap(); + state + .pods + .push(serde_json::json!({"apiVersion":"v1", "kind":"Pod", "metadata":metadata})); + state.pods_continue = true; + } + let result = driver.update_sandbox_image(&request()).await; + assert!( + matches!(result, Err(KubernetesDriverError::Precondition(message)) if message.contains("Pods still exist")) + ); + assert!(state.lock().unwrap().patches.is_empty()); + } +} + +#[tokio::test] +async fn image_update_rejects_image_name_and_runtime_identity_conflicts() { + for scenario in ["image", "name", "runtime", "seed", "missing-provenance"] { + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + let mut request = request(); + match scenario { + "image" => request.expected_image = "registry.example/agent:other".into(), + "name" => request.name = "different-name".into(), + "runtime" => { + request.expected_runtime_identity = + "kubernetes://openshell/replacement-uid/old-supervisor".into(); + } + "seed" => { + state.lock().unwrap().sandbox["spec"]["podTemplate"]["spec"]["initContainers"][1] + ["image"] = serde_json::json!("different-seed:v1"); + } + "missing-provenance" => { + state.lock().unwrap().sandbox["metadata"]["annotations"] + .as_object_mut() + .unwrap() + .remove(crate::resource_admission::CONFIG_USED); + } + _ => unreachable!(), + } + assert!( + matches!( + driver.update_sandbox_image(&request).await, + Err(KubernetesDriverError::Precondition(_)) + ), + "{scenario}" + ); + assert!(state.lock().unwrap().patches.is_empty()); + } +} + +#[tokio::test] +async fn image_update_revalidates_attachment_admission_and_uid_even_on_retry() { + for retry in [false, true] { + for scenario in ["labels", "uid", "config-disabled"] { + let (mut driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + if retry { + driver.update_sandbox_image(&request()).await.unwrap(); + } + match scenario { + "labels" => state.lock().unwrap().pvc["metadata"]["labels"] = serde_json::json!({}), + "uid" => { + state.lock().unwrap().pvc["metadata"]["uid"] = + serde_json::json!("replacement-pvc-uid"); + } + "config-disabled" => driver.config.allow_driver_config = false, + _ => unreachable!(), + } + assert!( + matches!( + driver.update_sandbox_image(&request()).await, + Err(KubernetesDriverError::Precondition(_)) + ), + "{scenario} retry={retry}" + ); + assert_eq!(state.lock().unwrap().patches.len(), usize::from(retry)); + } + } +} + +#[tokio::test] +async fn image_update_conflict_does_not_blindly_retry_or_recreate() { + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + state.lock().unwrap().conflict = true; + let before = state.lock().unwrap().sandbox.clone(); + assert!( + matches!(driver.update_sandbox_image(&request()).await, Err(KubernetesDriverError::Precondition(message)) if message.contains("changed during image update")) + ); + let state = state.lock().unwrap(); + assert_eq!(state.patches.len(), 1); + assert_eq!(state.sandbox, before); +} + +#[tokio::test] +async fn image_update_grpc_maps_validation_and_precondition_errors() { + use openshell_core::proto::compute::v1::compute_driver_server::ComputeDriver; + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + let service = crate::ComputeDriverService::new(driver); + let mut invalid = request(); + invalid.image = "https://registry.example/image:v2".into(); + let error = service + .update_sandbox_image(tonic::Request::new(invalid)) + .await + .unwrap_err(); + assert_eq!(error.code(), tonic::Code::InvalidArgument); + assert!(state.lock().unwrap().calls.is_empty()); + let mut conflict = request(); + conflict.expected_image = "other:v1".into(); + let error = service + .update_sandbox_image(tonic::Request::new(conflict)) + .await + .unwrap_err(); + assert_eq!(error.code(), tonic::Code::FailedPrecondition); +} + +#[tokio::test] +async fn image_update_can_repair_a_legacy_invalid_image_reference() { + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + let invalid_image = "UpperCaseRepository"; + { + let mut state = state.lock().unwrap(); + state.sandbox["spec"]["podTemplate"]["spec"]["containers"][0]["image"] = + serde_json::json!(invalid_image); + state.sandbox["spec"]["podTemplate"]["spec"]["initContainers"][1]["image"] = + serde_json::json!(invalid_image); + } + let mut update = request(); + update.expected_image = invalid_image.into(); + driver.update_sandbox_image(&update).await.unwrap(); + let state = state.lock().unwrap(); + assert_eq!(state.patches.len(), 1); + assert_eq!( + state.sandbox["spec"]["podTemplate"]["spec"]["containers"][0]["image"], + update.image + ); + assert_eq!(state.sandbox["metadata"]["uid"], "resource-uid"); +} + +#[test] +fn image_update_validates_container_references() { + for image in [ + "agent", + "registry.example:5000/team/agent:v2", + "localhost/agent:Tag_1", + "[::1]:5000/team/agent", + "team/image__name:v2", + &format!("registry.example/agent@sha256:{}", "a".repeat(64)), + ] { + validate_workload_image(image).unwrap(); + } + for image in [ + "", + " image:v2", + "image:v2\n", + "https://host/image", + "host//image", + "UpperCaseRepository", + "agent:", + "agent@sha256:invalid", + "agent@sha256:abc", + &format!("agent@sha256:{}", "a".repeat(32)), + &format!("agent@sha256:{}", "a".repeat(65)), + &format!("{}:v1", "a".repeat(256)), + "../agent", + &"a".repeat(2049), + ] { + assert!(validate_workload_image(image).is_err(), "{image:?}"); + } +} + +#[tokio::test] +async fn image_update_serializes_with_other_lifecycle_operations() { + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + let guard = driver + .lifecycle_gates + .gate_for("sandbox-1") + .lock_owned() + .await; + let request = request(); + let pending = driver.update_sandbox_image(&request); + tokio::pin!(pending); + assert!( + tokio::time::timeout(Duration::from_millis(10), &mut pending) + .await + .is_err() + ); + assert!(state.lock().unwrap().calls.is_empty()); + drop(guard); + pending.await.unwrap(); +} diff --git a/crates/openshell-driver-mxc/src/grpc.rs b/crates/openshell-driver-mxc/src/grpc.rs index 91c61d2088..ac4206276c 100644 --- a/crates/openshell-driver-mxc/src/grpc.rs +++ b/crates/openshell-driver-mxc/src/grpc.rs @@ -34,6 +34,16 @@ impl ComputeDriverService { #[tonic::async_trait] impl ComputeDriver for ComputeDriverService { + async fn update_sandbox_image( + &self, + _request: Request, + ) -> Result, Status> + { + Err(Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } + async fn get_capabilities( &self, request: Request, diff --git a/crates/openshell-driver-podman/src/grpc.rs b/crates/openshell-driver-podman/src/grpc.rs index 59b2fe1f60..c9be5b4409 100644 --- a/crates/openshell-driver-podman/src/grpc.rs +++ b/crates/openshell-driver-podman/src/grpc.rs @@ -50,6 +50,16 @@ impl ComputeDriverService { #[tonic::async_trait] impl ComputeDriver for ComputeDriverService { + async fn update_sandbox_image( + &self, + _request: Request, + ) -> Result, Status> + { + Err(Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } + async fn authenticate_sandbox( &self, _request: Request, diff --git a/crates/openshell-driver-vm/src/driver.rs b/crates/openshell-driver-vm/src/driver.rs index 304c95bc32..f60d7f8bb1 100644 --- a/crates/openshell-driver-vm/src/driver.rs +++ b/crates/openshell-driver-vm/src/driver.rs @@ -5325,6 +5325,16 @@ fn configure_main_exit_marker(command: &mut Command, state_dir: &Path) { #[tonic::async_trait] impl ComputeDriver for VmDriver { + async fn update_sandbox_image( + &self, + _request: Request, + ) -> Result, Status> + { + Err(Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } + async fn authenticate_sandbox( &self, _request: Request, diff --git a/crates/openshell-gateway-interceptors/src/routes.rs b/crates/openshell-gateway-interceptors/src/routes.rs index c47f42e40d..c436563ef2 100644 --- a/crates/openshell-gateway-interceptors/src/routes.rs +++ b/crates/openshell-gateway-interceptors/src/routes.rs @@ -16,6 +16,7 @@ const SERVICE_OPEN_SHELL: &str = "openshell.v1.OpenShell"; /// here. pub const INTERCEPTABLE_METHODS: &[&str] = &[ "CreateSandbox", + "UpdateSandbox", "AttachSandboxProvider", "DetachSandboxProvider", "DeleteSandbox", diff --git a/crates/openshell-otel/src/grpc.rs b/crates/openshell-otel/src/grpc.rs index 8184caae35..9dbb83c85b 100644 --- a/crates/openshell-otel/src/grpc.rs +++ b/crates/openshell-otel/src/grpc.rs @@ -102,6 +102,10 @@ pub mod rpc { "CreateSandbox", "openshell.compute.v1.ComputeDriver/CreateSandbox", ); + pub const UPDATE_SANDBOX_IMAGE: ComputeDriverRpc = ComputeDriverRpc::new( + "UpdateSandboxImage", + "openshell.compute.v1.ComputeDriver/UpdateSandboxImage", + ); pub const GET_SANDBOX: ComputeDriverRpc = ComputeDriverRpc::new( "GetSandbox", "openshell.compute.v1.ComputeDriver/GetSandbox", @@ -194,6 +198,7 @@ pub fn compute_driver_rpc_operation(path: &str) -> Option { Some("GetCapabilities") => Some(rpc::GET_CAPABILITIES), Some("ValidateSandboxCreate") => Some(rpc::VALIDATE_SANDBOX_CREATE), Some("CreateSandbox") => Some(rpc::CREATE_SANDBOX), + Some("UpdateSandboxImage") => Some(rpc::UPDATE_SANDBOX_IMAGE), Some("GetSandbox") => Some(rpc::GET_SANDBOX), Some("ListSandboxes") => Some(rpc::LIST_SANDBOXES), Some("StopSandbox") => Some(rpc::STOP_SANDBOX), @@ -317,6 +322,7 @@ mod tests { rpc::GET_CAPABILITIES, rpc::VALIDATE_SANDBOX_CREATE, rpc::CREATE_SANDBOX, + rpc::UPDATE_SANDBOX_IMAGE, rpc::GET_SANDBOX, rpc::LIST_SANDBOXES, rpc::STOP_SANDBOX, diff --git a/crates/openshell-sdk/src/raw.rs b/crates/openshell-sdk/src/raw.rs index faca71fb59..cbdf1d2b4a 100644 --- a/crates/openshell-sdk/src/raw.rs +++ b/crates/openshell-sdk/src/raw.rs @@ -28,12 +28,12 @@ pub use openshell_core::proto::{ ListSandboxTemplatesRequest, ListSandboxesRequest, ListWorkspacesRequest, ProviderDesiredIdentity, ProviderMutationKind, ProviderMutationReceipt, ProviderReadinessObservation, ProviderReadinessReason, ProviderReadinessState, - ProviderReadinessStatus, ResumeSandboxRequest, Sandbox, SandboxPhase as ProtoSandboxPhase, - SandboxResources, SandboxServiceLevel, SandboxSpec as ProtoSandboxSpec, SandboxStartup, - SandboxTemplate, SandboxTemplateResponse, SandboxWorkloadConfig, SandboxWorkloadTemplate, - SandboxWorkloadTemplateProvenance, SandboxWorkloadTemplateSpec, - ServiceStatus as ProtoServiceStatus, StartSandboxRequest, StopSandboxRequest, - SuspendSandboxRequest, Workspace, + ProviderReadinessStatus, ResumeSandboxRequest, Sandbox, SandboxImageUpdate, + SandboxPhase as ProtoSandboxPhase, SandboxResources, SandboxServiceLevel, + SandboxSpec as ProtoSandboxSpec, SandboxStartup, SandboxTemplate, SandboxTemplateResponse, + SandboxWorkloadConfig, SandboxWorkloadTemplate, SandboxWorkloadTemplateProvenance, + SandboxWorkloadTemplateSpec, ServiceStatus as ProtoServiceStatus, StartSandboxRequest, + StopSandboxRequest, SuspendSandboxRequest, UpdateSandboxRequest, Workspace, }; /// Type alias for the gRPC client wrapped in the SDK's auth interceptor. diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index b730c41d16..21d524458a 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -249,6 +249,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } + async fn update_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented by test service")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs new file mode 100644 index 0000000000..5b48e93b87 --- /dev/null +++ b/crates/openshell-server/src/compute/image_update.rs @@ -0,0 +1,802 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Stopped-only image changes. Persist intent before touching the driver so a +//! lost response cannot allow Start to run a different image than the gateway. + +use super::{ + ComputeRuntime, START_PHASE_CAS_RETRY_LIMIT, provisioning_operation, + sandbox_compute_runtime_identity, +}; +use openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE; +use openshell_core::proto::compute::v1::UpdateSandboxImageRequest; +use openshell_core::proto::{Sandbox, SandboxImageUpdate, SandboxPhase}; +use openshell_core::{GetResourceVersion, ObjectId, ObjectName}; +use tonic::{Request, Status}; +use tracing::info; + +impl ComputeRuntime { + pub(crate) async fn update_sandbox_image( + &self, + sandbox_id: &str, + image: String, + expected_resource_version: u64, + ) -> Result { + if !self + .driver_info + .negotiated_extension + .supported_capabilities + .iter() + .any(|capability| capability == COMPUTE_UPDATE_SANDBOX_IMAGE) + { + return Err(Status::unimplemented( + "compute driver does not support storage-preserving sandbox image updates", + )); + } + let lifecycle_guard = self.lifecycle_gates.lock_for(sandbox_id).await; + let sandbox_guard = self.lock_sandbox_for_lifecycle(&lifecycle_guard).await; + let current = self + .store + .get_message::(sandbox_id) + .await + .map_err(|error| Status::internal(format!("fetch sandbox failed: {error}")))? + .ok_or_else(|| Status::not_found("sandbox not found"))?; + ensure_image_update_stopped(¤t)?; + if current.get_resource_version() != expected_resource_version { + return Err(crate::grpc::persistence_error_to_status( + crate::persistence::PersistenceError::Conflict { + current_resource_version: Some(current.get_resource_version()), + }, + "update sandbox image", + )); + } + let old_image = current + .spec + .as_ref() + .and_then(|spec| spec.template.as_ref()) + .map(|template| template.image.clone()) + .filter(|image| !image.is_empty()) + .ok_or_else(|| Status::failed_precondition("sandbox has no workload image"))?; + let pending = current + .status + .as_ref() + .and_then(|status| status.image_update.clone()); + if pending + .as_ref() + .is_some_and(|pending| pending.image != image) + { + return Err(Status::failed_precondition( + "another image update is pending; retry that image before selecting a different image", + )); + } + if pending.is_none() && old_image == image { + return Ok(current); + } + let intent = if let Some(intent) = pending { + intent + } else { + let revision = current + .status + .as_ref() + .map_or(0, |status| status.image_revision) + .checked_add(1) + .ok_or_else(|| Status::resource_exhausted("sandbox image revision exhausted"))?; + SandboxImageUpdate { + operation_id: uuid::Uuid::new_v4().to_string(), + previous_image: old_image, + image: image.clone(), + revision, + } + }; + if current + .status + .as_ref() + .is_none_or(|status| status.image_update.is_none()) + { + let request = image_update_driver_request(¤t, &intent, true); + self.driver + .call_owned( + openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, + Some(sandbox_id), + move |driver| async move { + driver.update_sandbox_image(Request::new(request)).await + }, + ) + .await?; + } + let pending = if current + .status + .as_ref() + .is_some_and(|status| status.image_update.is_some()) + { + current + } else { + let intent_for_write = intent.clone(); + self.store + .update_message_cas::( + sandbox_id, + expected_resource_version, + move |sandbox| { + sandbox + .spec + .as_mut() + .expect("validated spec") + .template + .as_mut() + .expect("validated template") + .image + .clone_from(&image); + let status = sandbox.status.get_or_insert_with(Default::default); + status.image_revision = intent_for_write.revision; + status.image_update = Some(intent_for_write.clone()); + }, + ) + .await + .map_err(|error| { + crate::grpc::persistence_error_to_status(error, "record sandbox image update") + })? + }; + self.sandbox_index.update_from_sandbox(&pending); + self.sandbox_watch_bus.notify(sandbox_id); + drop(sandbox_guard); + + // The durable intent commits ownership. Cancellation of the public RPC + // must not release the lifecycle gate while the driver can still apply. + let runtime = self.clone(); + tokio::spawn(async move { + let _lifecycle_guard = lifecycle_guard; + runtime.complete_image_update(pending, intent).await + }) + .await + .map_err(|error| Status::internal(format!("sandbox image update worker failed: {error}")))? + } + + async fn complete_image_update( + &self, + pending: Sandbox, + intent: SandboxImageUpdate, + ) -> Result { + let request = image_update_driver_request(&pending, &intent, false); + self.driver + .call_owned(openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, Some(pending.object_id()), move |driver| async move { + driver.update_sandbox_image(Request::new(request)).await + }) + .await?; + + // Watchers may have advanced the resource version. Never restore an old + // record or overwrite a concurrent deletion to acknowledge the driver. + let _guard = self.lock_sandbox_local(pending.object_id()).await; + for _ in 0..START_PHASE_CAS_RETRY_LIMIT { + let current = self + .store + .get_message::(pending.object_id()) + .await + .map_err(|error| Status::internal(format!("reload image update failed: {error}")))? + .ok_or_else(|| Status::not_found("sandbox was deleted"))?; + ensure_image_update_stopped(¤t)?; + if current + .status + .as_ref() + .and_then(|status| status.image_update.as_ref()) + != Some(&intent) + { + return Err(Status::aborted("sandbox image update intent changed")); + } + match self + .store + .update_message_cas::( + pending.object_id(), + current.get_resource_version(), + |sandbox| { + sandbox + .status + .as_mut() + .expect("pending status") + .image_update = None; + }, + ) + .await + { + Ok(updated) => { + self.sandbox_index.update_from_sandbox(&updated); + self.sandbox_watch_bus.notify(updated.object_id()); + info!(sandbox_id = %updated.object_id(), operation_id = %intent.operation_id, "Sandbox workload image updated; sandbox remains stopped"); + return Ok(updated); + } + Err(crate::persistence::PersistenceError::Conflict { .. }) => {} + Err(error) => { + return Err(crate::grpc::persistence_error_to_status( + error, + "complete sandbox image update", + )); + } + } + } + Err(Status::aborted( + "sandbox changed while acknowledging image update; read and retry the pending image", + )) + } +} + +fn image_update_driver_request( + sandbox: &Sandbox, + intent: &SandboxImageUpdate, + validate_only: bool, +) -> UpdateSandboxImageRequest { + UpdateSandboxImageRequest { + sandbox_id: sandbox.object_id().to_string(), + name: sandbox.object_name().to_string(), + image: intent.image.clone(), + expected_image: intent.previous_image.clone(), + expected_runtime_identity: sandbox_compute_runtime_identity(sandbox), + operation_id: intent.operation_id.clone(), + validate_only, + revision: intent.revision, + } +} + +fn ensure_image_update_stopped(sandbox: &Sandbox) -> Result<(), Status> { + provisioning_operation::ensure_operation_settled(sandbox)?; + if sandbox.phase() != SandboxPhase::Stopped as i32 + || sandbox + .metadata + .as_ref() + .is_some_and(|metadata| metadata.deletion_time.is_some()) + { + return Err(Status::failed_precondition( + "sandbox must be Stopped before updating its image", + )); + } + Ok(()) +} + +/// Checked both before and after lifecycle locking by Start. A failed driver +/// response does not prove it had no effects, so only a successful retry clears +/// the durable intent. Ordinary stop and deletion never clear it. +pub(super) fn ensure_no_pending_image_update(sandbox: &Sandbox) -> Result<(), Status> { + if sandbox + .status + .as_ref() + .is_some_and(|status| status.image_update.is_some()) + { + return Err(Status::failed_precondition( + "sandbox image update is pending; read the current resource version and retry UpdateSandbox with the same image before starting", + )); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::compute::{ + COMPUTE_RUNTIME_IDENTITY_ANNOTATION, apply_driver_snapshot, provisioning_deadline, + }; + use crate::sandbox_index::SandboxIndex; + use crate::sandbox_watch::SandboxWatchBus; + use crate::supervisor_session::SupervisorSessionRegistry; + use crate::test_support::{FakeComputeDriver, FakeComputeDriverCall}; + use crate::tracing_bus::TracingLogBus; + use openshell_core::proto::compute::v1::{DriverSandbox, DriverSandboxStatus}; + use openshell_core::proto::datamodel::v1::ObjectMeta; + use openshell_core::proto::{SandboxSpec, SandboxTemplate}; + use std::collections::HashMap; + use std::sync::Arc; + use tonic::Code; + + async fn fixture(supported: bool) -> (ComputeRuntime, Arc, Sandbox) { + let store = Arc::new(crate::persistence::test_store().await); + crate::ensure_default_workspace(&store).await.unwrap(); + let driver = Arc::new(FakeComputeDriver::new()); + let mut runtime = ComputeRuntime::from_driver( + "test".into(), + driver.clone(), + None, + store.clone(), + SandboxIndex::new(), + SandboxWatchBus::new(), + TracingLogBus::new(), + Arc::new(SupervisorSessionRegistry::new()), + ) + .await + .unwrap(); + if supported { + runtime + .driver_info + .negotiated_extension + .supported_capabilities + .push(COMPUTE_UPDATE_SANDBOX_IMAGE.into()); + } + let mut sandbox = Sandbox { + metadata: Some(ObjectMeta { + id: "image-sandbox-id".into(), + name: "image-sandbox".into(), + workspace: "default".into(), + labels: HashMap::from([("app".into(), "retained".into())]), + annotations: HashMap::from([( + COMPUTE_RUNTIME_IDENTITY_ANNOTATION.into(), + "stable-runtime".into(), + )]), + ..Default::default() + }), + spec: Some(SandboxSpec { + template: Some(SandboxTemplate { + image: "example/workload:old".into(), + ..Default::default() + }), + environment: HashMap::from([("KEEP".into(), "value".into())]), + command: vec!["/bin/sh".into()], + ..Default::default() + }), + host_key_fingerprint: "SHA256:stable-key".into(), + ..Default::default() + }; + sandbox.set_phase(SandboxPhase::Stopped as i32); + store.put_message(&sandbox).await.unwrap(); + let sandbox = store + .get_message::(sandbox.object_id()) + .await + .unwrap() + .unwrap(); + (runtime, driver, sandbox) + } + + fn image_calls(driver: &FakeComputeDriver) -> Vec { + driver + .calls() + .into_iter() + .filter_map(|call| match call { + FakeComputeDriverCall::UpdateSandboxImage { request } if !request.validate_only => { + Some(request) + } + _ => None, + }) + .collect() + } + + #[tokio::test] + async fn image_update_preserves_identity_and_every_other_spec_field() { + let (runtime, driver, original) = fixture(true).await; + let updated = runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + original.get_resource_version(), + ) + .await + .unwrap(); + let mut expected = original.spec.clone().unwrap(); + expected.template.as_mut().unwrap().image = "example/workload:new".into(); + assert_eq!(updated.spec, Some(expected)); + assert_eq!(updated.object_id(), original.object_id()); + assert_eq!(updated.object_name(), original.object_name()); + assert_eq!(updated.host_key_fingerprint, original.host_key_fingerprint); + assert_eq!( + updated.metadata.as_ref().unwrap().annotations, + original.metadata.as_ref().unwrap().annotations + ); + assert_eq!( + updated.metadata.as_ref().unwrap().labels, + original.metadata.as_ref().unwrap().labels + ); + assert_eq!(updated.phase(), SandboxPhase::Stopped as i32); + assert!(updated.status.as_ref().unwrap().image_update.is_none()); + assert_eq!(updated.status.as_ref().unwrap().image_revision, 1); + let calls = image_calls(&driver); + assert_eq!(calls.len(), 1); + assert_eq!(calls[0].expected_image, "example/workload:old"); + assert_eq!(calls[0].image, "example/workload:new"); + assert_eq!(calls[0].revision, 1); + assert_eq!(calls[0].expected_runtime_identity, "stable-runtime"); + assert!(uuid::Uuid::parse_str(&calls[0].operation_id).is_ok()); + assert!(!driver.calls().iter().any(|call| matches!( + call, + FakeComputeDriverCall::CreateSandbox { .. } + | FakeComputeDriverCall::DeleteSandbox { .. } + | FakeComputeDriverCall::StartSandbox { .. } + ))); + let unchanged = runtime + .update_sandbox_image( + updated.object_id(), + "example/workload:new".into(), + updated.get_resource_version(), + ) + .await + .unwrap(); + assert_eq!( + unchanged.get_resource_version(), + updated.get_resource_version() + ); + assert_eq!(image_calls(&driver).len(), 1); + let back = runtime + .update_sandbox_image( + updated.object_id(), + "example/workload:old".into(), + updated.get_resource_version(), + ) + .await + .unwrap(); + assert_eq!(back.status.as_ref().unwrap().image_revision, 2); + assert_eq!(image_calls(&driver)[1].revision, 2); + } + + #[tokio::test] + async fn image_update_rejects_unsupported_driver_and_stale_version_without_writes() { + let (runtime, driver, original) = fixture(false).await; + assert_eq!( + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + original.get_resource_version() + ) + .await + .unwrap_err() + .code(), + Code::Unimplemented + ); + assert!(image_calls(&driver).is_empty()); + let (runtime, driver, original) = fixture(true).await; + assert_eq!( + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + original.get_resource_version() + 1 + ) + .await + .unwrap_err() + .code(), + Code::Aborted + ); + assert!(image_calls(&driver).is_empty()); + assert_eq!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(), + original + ); + } + + #[tokio::test] + async fn failed_image_preflight_has_no_durable_effects() { + let (runtime, driver, original) = fixture(true).await; + driver.set_image_validation_error(Some(Code::InvalidArgument)); + assert_eq!( + runtime + .update_sandbox_image( + original.object_id(), + "invalid:image".into(), + original.get_resource_version() + ) + .await + .unwrap_err() + .code(), + Code::InvalidArgument + ); + assert!(image_calls(&driver).is_empty()); + assert_eq!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(), + original + ); + } + + #[tokio::test] + async fn concurrent_image_updates_cannot_overwrite_each_other() { + let (runtime, driver, original) = fixture(true).await; + // Real RPCs are separate tasks. Polling both futures with join! in one + // task would share the debug task-local lock-order tracker. + let spawn_update = |image: &str| { + let runtime = runtime.clone(); + let sandbox_id = original.object_id().to_string(); + let version = original.get_resource_version(); + let image = image.to_string(); + tokio::spawn(async move { + runtime + .update_sandbox_image(&sandbox_id, image, version) + .await + }) + }; + let first = spawn_update("example/workload:first"); + let second = spawn_update("example/workload:second"); + let (first, second) = tokio::join!(first, second); + let (first, second) = (first.unwrap(), second.unwrap()); + assert_ne!(first.is_ok(), second.is_ok()); + assert_eq!( + first.err().or_else(|| second.err()).unwrap().code(), + Code::Aborted + ); + assert_eq!(image_calls(&driver).len(), 1); + } + + #[tokio::test] + async fn image_update_rejects_non_stopped_states() { + for phase in [ + SandboxPhase::Ready, + SandboxPhase::Provisioning, + SandboxPhase::Starting, + SandboxPhase::Stopping, + SandboxPhase::Completed, + SandboxPhase::Error, + SandboxPhase::Deleting, + ] { + let (runtime, driver, mut sandbox) = fixture(true).await; + sandbox.set_phase(phase as i32); + runtime.store.put_message(&sandbox).await.unwrap(); + let sandbox = runtime + .store + .get_message::(sandbox.object_id()) + .await + .unwrap() + .unwrap(); + assert_eq!( + runtime + .update_sandbox_image( + sandbox.object_id(), + "example/workload:new".into(), + sandbox.get_resource_version() + ) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition, + "{phase:?}" + ); + assert!(image_calls(&driver).is_empty()); + } + } + + #[tokio::test] + async fn image_update_can_roll_back_after_start_timeout_cleanup() { + let (runtime, driver, mut original) = fixture(true).await; + crate::auth::sandbox_session::PersistedSandboxIdentity::new() + .unwrap() + .write(&mut original.metadata.as_mut().unwrap().annotations); + runtime.store.put_message(&original).await.unwrap(); + let original = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + let upgraded = runtime + .update_sandbox_image( + original.object_id(), + "example/workload:missing".into(), + original.get_resource_version(), + ) + .await + .unwrap(); + let starting = runtime + .start_sandbox("default", original.object_name()) + .await + .unwrap(); + assert_eq!(starting.phase(), SandboxPhase::Starting as i32); + // Backdate the owned preparation clock rather than waiting for the + // production budget. Keep its attempt and settled operation identities. + let overdue = runtime + .store + .update_message_cas::( + starting.object_id(), + starting.get_resource_version(), + |sandbox| { + let record = sandbox + .status + .as_mut() + .unwrap() + .provisioning + .as_mut() + .unwrap(); + record.preparation_deadline = + openshell_core::time::timestamp_from_millis(1).ok(); + record.deadline = record.preparation_deadline; + }, + ) + .await + .unwrap(); + let expired = { + let _guard = runtime.lock_sandbox_local(overdue.object_id()).await; + runtime + .claim_provisioning_timeout(&overdue, openshell_core::time::now_ms()) + .await + .unwrap() + .unwrap() + }; + assert_eq!(expired.phase(), SandboxPhase::Error as i32); + assert!( + runtime + .stop_sandbox("default", original.object_name()) + .await + .is_err() + ); + assert!( + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:old".into(), + expired.get_resource_version() + ) + .await + .is_err() + ); + { + let gate = runtime.lifecycle_gates.lock_for(expired.object_id()).await; + runtime + .reclaim_provisioning_timeout(&expired, &gate) + .await + .unwrap(); + } + let reclaimed = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + assert!( + reclaimed + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .unwrap() + .cleanup_completed_time + .is_some() + ); + let stopped = runtime + .stop_sandbox("default", original.object_name()) + .await + .unwrap(); + assert_eq!(stopped.phase(), SandboxPhase::Stopped as i32); + assert_eq!( + stopped.status.as_ref().unwrap().provisioning, + reclaimed.status.as_ref().unwrap().provisioning + ); + let corrected = runtime + .update_sandbox_image( + original.object_id(), + "example/workload:old".into(), + stopped.get_resource_version(), + ) + .await + .unwrap(); + assert_eq!( + corrected.status.as_ref().unwrap().image_revision, + upgraded.status.as_ref().unwrap().image_revision + 1 + ); + assert_eq!(corrected.object_id(), original.object_id()); + assert_eq!( + corrected.host_key_fingerprint, + original.host_key_fingerprint + ); + assert_eq!(corrected.spec, original.spec); + let retried = runtime + .start_sandbox("default", original.object_name()) + .await + .unwrap(); + assert_eq!(retried.phase(), SandboxPhase::Starting as i32); + assert!(!provisioning_deadline::timed_out(&retried)); + let calls = driver.calls(); + assert_eq!( + calls + .iter() + .filter(|call| matches!(call, FakeComputeDriverCall::StopSandbox { .. })) + .count(), + 1, + "only timeout reclamation stops the driver" + ); + assert_eq!( + calls + .iter() + .filter(|call| matches!(call, FakeComputeDriverCall::StartSandbox { .. })) + .count(), + 2 + ); + assert!(!calls.iter().any(|call| matches!( + call, + FakeComputeDriverCall::CreateSandbox { .. } + | FakeComputeDriverCall::DeleteSandbox { .. } + ))); + } + + #[tokio::test] + async fn interrupted_image_update_blocks_start_and_retries_the_same_operation() { + let (runtime, driver, original) = fixture(true).await; + driver.set_image_update_error(Some(Code::Unavailable)); + assert_eq!( + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + original.get_resource_version() + ) + .await + .unwrap_err() + .code(), + Code::Unavailable + ); + let pending = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + assert!(pending.status.as_ref().unwrap().image_update.is_some()); + assert_eq!( + runtime + .start_sandbox("default", original.object_name()) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + assert_eq!( + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:other".into(), + pending.get_resource_version() + ) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + driver.set_image_update_error(None); + let complete = runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + pending.get_resource_version(), + ) + .await + .unwrap(); + assert!(complete.status.as_ref().unwrap().image_update.is_none()); + let calls = image_calls(&driver); + assert_eq!(calls.len(), 2); + assert_eq!(calls[0], calls[1]); + } + + #[test] + fn image_update_intent_survives_driver_status_replacement() { + let intent = SandboxImageUpdate { + operation_id: "operation".into(), + previous_image: "old".into(), + image: "new".into(), + revision: 1, + }; + let grant_failure = Box::new(openshell_core::proto::TokenGrantFailureObservation { + destination_host: "api.example.com".into(), + ..Default::default() + }); + let mut sandbox = Sandbox::default(); + sandbox.set_phase(SandboxPhase::Stopped as i32); + let status = sandbox.status.as_mut().unwrap(); + status.image_update = Some(intent.clone()); + status.image_revision = 1; + status.last_token_grant_failure = Some(grant_failure.clone()); + let incoming = DriverSandbox { + name: "test".into(), + status: Some(DriverSandboxStatus::default()), + ..Default::default() + }; + apply_driver_snapshot(&mut sandbox, &incoming, false, false); + assert_eq!( + sandbox.status.as_ref().unwrap().image_update.as_ref(), + Some(&intent) + ); + assert_eq!(sandbox.status.as_ref().unwrap().image_revision, 1); + assert_eq!( + sandbox.status.as_ref().unwrap().last_token_grant_failure, + Some(grant_failure) + ); + } +} diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index 215b864e4b..32bfd0b064 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -4,6 +4,7 @@ //! Gateway-owned compute orchestration over a pluggable compute backend. pub mod driver_config; +mod image_update; pub mod lease; mod mutation_guard; pub mod provisioning_deadline; @@ -434,13 +435,19 @@ impl QuiesceOperation { { return Ok(QuiesceAdmission::Settled); } - // Timeout cleanup owns reclamation while the record remains - // Error. Its later start may recreate missing compute; an - // ordinary stop must not replace that recovery state with - // Stopping or Stopped. - if phase == SandboxPhase::Error && provisioning_deadline::timed_out(sandbox) { + // Timeout cleanup owns reclamation until it completes. Once + // reclaimed, explicit stop can expose Stopped for image repair + // while preserving the timeout record for a later start. + if phase == SandboxPhase::Error + && provisioning_deadline::timed_out(sandbox) + && sandbox + .status + .as_ref() + .and_then(|status| status.provisioning.as_ref()) + .is_none_or(|record| record.cleanup_completed_time.is_none()) + { return Err(Status::failed_precondition( - "sandbox provisioning timed out; retry start after timeout cleanup completes", + "sandbox provisioning timed out; wait for timeout cleanup before stop or start", )); } // Error does not prove compute has stopped. Use the normal @@ -723,6 +730,17 @@ impl RemoteComputeDriver { #[tonic::async_trait] impl ComputeDriver for RemoteComputeDriver { + async fn update_sandbox_image( + &self, + request: Request, + ) -> Result< + tonic::Response, + Status, + > { + self.verify_admission_policy(false).await?; + self.client().update_sandbox_image(request).await + } + type WatchSandboxesStream = DriverWatchStream; async fn get_capabilities( @@ -1808,14 +1826,15 @@ impl ComputeRuntime { Some(guard) => guard, None => runtime.lock_sandbox_for_lifecycle(&lifecycle_guard).await, }; - runtime - .compensate_failed_create_inner( - &created, - lifecycle_guard, - sandbox_guard, - original, - ) - .await + // Keep compensation's future bounded as the persisted sandbox + // status grows (including image-update reconciliation state). + Box::pin(runtime.compensate_failed_create_inner( + &created, + lifecycle_guard, + sandbox_guard, + original, + )) + .await } .instrument(request_span), ) @@ -2042,14 +2061,32 @@ impl ComputeRuntime { QuiesceAdmission::Begin => {} } - let (reason, message) = operation.requested_condition(); + let reclaimed_timeout = operation == QuiesceOperation::Stop + && current.phase() == SandboxPhase::Error as i32 + && provisioning_deadline::timed_out(¤t); + let (next_phase, reason, message) = if reclaimed_timeout { + ( + SandboxPhase::Stopped, + "StoppedAfterProvisioningTimeout", + "Timed-out compute has been reclaimed; sandbox stopped for repair", + ) + } else { + let (reason, message) = operation.requested_condition(); + (operation.in_flight_phase(), reason, message) + }; match self - .write_lifecycle_phase(¤t, operation.in_flight_phase(), reason, message) + .write_lifecycle_phase(¤t, next_phase, reason, message) .await { Ok(transition) => { self.sandbox_index.update_from_sandbox(&transition); self.sandbox_watch_bus.notify(&sandbox_id); + if reclaimed_timeout { + self.cleanup_stopped_sandbox_sessions(&transition) + .await + .map_err(Status::internal)?; + return Ok(transition); + } break (current, transition); } Err(crate::persistence::PersistenceError::Conflict { .. }) @@ -2264,6 +2301,7 @@ impl ComputeRuntime { self.validate_launch_signer_configured(authority.is_some())?; } provisioning_operation::ensure_operation_settled(&candidate)?; + image_update::ensure_no_pending_image_update(&candidate)?; if provisioning_deadline::timed_out(&candidate) && candidate .status @@ -2301,6 +2339,7 @@ impl ComputeRuntime { let mut attempts = 0; let (previous, starting, launch_authentication) = loop { provisioning_operation::ensure_operation_settled(¤t)?; + image_update::ensure_no_pending_image_update(¤t)?; let phase = SandboxPhase::try_from(current.phase()).unwrap_or(SandboxPhase::Unknown); if let StartIntent::Resume { .. } = intent { // Resume restores only retained state. A Starting record may @@ -5314,7 +5353,7 @@ impl ComputeRuntime { continue; } - self.prune_missing_sandbox(record, sweep_started_at_ms, grace_ms) + Box::pin(self.prune_missing_sandbox(record, sweep_started_at_ms, grace_ms)) .await .inspect_err(|_| crate::otel_tracing::mark_error(&tracing::Span::current()))?; } @@ -7351,6 +7390,8 @@ fn public_status_from_driver( next_restart_time: None, main_process_started_time: None, last_token_grant_failure: None, + image_update: None, + image_revision: 0, } } @@ -7437,6 +7478,8 @@ fn apply_driver_snapshot( new_status.restart_count = old_status.restart_count; new_status.next_restart_time = old_status.next_restart_time; new_status.main_process_started_time = old_status.main_process_started_time; + new_status.image_update.clone_from(&old_status.image_update); + new_status.image_revision = old_status.image_revision; } phase = match old_phase { @@ -8162,6 +8205,18 @@ impl Default for NoopTestDriver { #[cfg(any(test, feature = "test-support"))] #[tonic::async_trait] impl ComputeDriver for NoopTestDriver { + async fn update_sandbox_image( + &self, + _request: Request, + ) -> Result< + tonic::Response, + Status, + > { + Err(Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } + async fn authenticate_sandbox( &self, _request: Request, @@ -8801,6 +8856,18 @@ mod tests { #[tonic::async_trait] impl ComputeDriver for TestDriver { + async fn update_sandbox_image( + &self, + _request: Request, + ) -> Result< + tonic::Response, + Status, + > { + Err(Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } + async fn authenticate_sandbox( &self, _request: Request, @@ -9264,6 +9331,18 @@ mod tests { #[tonic::async_trait] impl ComputeDriver for ControlledDriver { + async fn update_sandbox_image( + &self, + _request: Request, + ) -> Result< + tonic::Response, + Status, + > { + Err(Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } + async fn authenticate_sandbox( &self, _request: Request, @@ -12557,6 +12636,18 @@ mod tests { #[tonic::async_trait] impl ComputeDriver for FailingDriver { + async fn update_sandbox_image( + &self, + _request: Request, + ) -> Result< + tonic::Response, + Status, + > { + Err(Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } + async fn authenticate_sandbox( &self, _request: Request, @@ -15120,7 +15211,7 @@ mod tests { tokio::time::timeout( Duration::from_secs(1), - runtime.reconcile_store_with_backend(Duration::ZERO), + Box::pin(runtime.reconcile_store_with_backend(Duration::ZERO)), ) .await .expect("prune sweep blocked on the stuck driver delete call") diff --git a/crates/openshell-server/src/compute/tests/error_recovery.rs b/crates/openshell-server/src/compute/tests/error_recovery.rs index c6c2d45aee..48d16fcc25 100644 --- a/crates/openshell-server/src/compute/tests/error_recovery.rs +++ b/crates/openshell-server/src/compute/tests/error_recovery.rs @@ -152,6 +152,10 @@ async fn pending_driver_operation_blocks_error_recovery_without_mutation() { let runtime = test_runtime(driver.clone()).await; let mut sandbox = error_sandbox_record("pending-id", "pending", "StartFailed"); let mut operation = provisioning_deadline::new_record(openshell_core::time::now_ms()); + // Even a completion timestamp cannot override an unsettled original driver + // operation. This also fences malformed/stale timeout cleanup evidence. + operation.timeout_time = openshell_core::time::timestamp_from_millis(300_000).ok(); + operation.cleanup_completed_time = openshell_core::time::timestamp_from_millis(320_000).ok(); operation.driver_operation_pending = true; operation.driver_operation_id = "owned-operation".into(); sandbox.status.as_mut().unwrap().provisioning = Some(operation); @@ -188,14 +192,33 @@ async fn timeout_stop_preserves_cleanup_and_direct_start_recovery() { runtime.store.put_message(&sandbox).await.unwrap(); let before = stored(&runtime, sandbox.object_id()).await; - let error = runtime - .stop_sandbox("default", "timeout") - .await - .unwrap_err(); - assert_eq!(error.code(), Code::FailedPrecondition); - assert!(error.message().contains("start")); - assert_eq!(stored(&runtime, sandbox.object_id()).await, before); - assert_eq!(driver.stop_calls(), 0, "timeout cleanup owns reclamation"); + let stop = runtime.stop_sandbox("default", "timeout").await; + if cleanup_complete { + let stopped = stop.expect( + "completed timeout cleanup permits an explicit stopped state for image repair", + ); + assert_eq!(stopped.phase(), SandboxPhase::Stopped as i32); + assert_eq!(stopped.object_id(), before.object_id()); + assert_eq!(stopped.spec, before.spec); + assert_eq!( + stopped.status.as_ref().unwrap().provisioning, + before.status.as_ref().unwrap().provisioning + ); + let repeated = runtime.stop_sandbox("default", "timeout").await.unwrap(); + assert_eq!( + repeated, stopped, + "the retained stopped transition is idempotent" + ); + } else { + let error = stop.unwrap_err(); + assert_eq!(error.code(), Code::FailedPrecondition); + assert_eq!(stored(&runtime, sandbox.object_id()).await, before); + } + assert_eq!( + driver.stop_calls(), + 0, + "timeout cleanup already owns reclamation" + ); let result = runtime.start_sandbox("default", "timeout").await; if cleanup_complete { @@ -214,6 +237,35 @@ async fn timeout_stop_preserves_cleanup_and_direct_start_recovery() { } } +#[tokio::test] +async fn reclaimed_timeout_can_still_start_directly_without_stop() { + let driver = ControlledDriver::new(); + driver.set_start_outcome(ControlledLifecycleOutcome::NotFound); + driver.track_compute.store(true, Ordering::SeqCst); + let runtime = test_runtime(driver.clone()).await; + let mut sandbox = error_sandbox_record( + "direct-timeout-id", + "direct-timeout", + "ImagePreparationTimedOut", + ); + let mut operation = provisioning_deadline::new_record(0); + operation.timeout_time = openshell_core::time::timestamp_from_millis(300_000).ok(); + operation.cleanup_completed_time = openshell_core::time::timestamp_from_millis(320_000).ok(); + sandbox.status.as_mut().unwrap().provisioning = Some(operation); + runtime.store.put_message(&sandbox).await.unwrap(); + + let starting = runtime + .start_sandbox("default", "direct-timeout") + .await + .unwrap(); + assert_eq!(starting.phase(), SandboxPhase::Starting as i32); + assert_eq!(starting.object_id(), sandbox.object_id()); + assert!(driver.compute_exists.load(Ordering::SeqCst)); + assert_eq!(driver.start_calls(), 1); + assert_eq!(driver.stop_calls(), 0); + assert_eq!(driver.delete_calls(), 0); +} + #[tokio::test] async fn failed_error_stop_retains_retryable_state_without_claiming_success() { for observed_error in [false, true] { diff --git a/crates/openshell-server/src/grpc/mod.rs b/crates/openshell-server/src/grpc/mod.rs index 8af2709134..84b2406fb8 100644 --- a/crates/openshell-server/src/grpc/mod.rs +++ b/crates/openshell-server/src/grpc/mod.rs @@ -322,6 +322,13 @@ impl OpenShell for OpenShellService { mutation_replay::run(&self.state, request).await } + async fn update_sandbox( + &self, + request: Request, + ) -> Result, Status> { + mutation_replay::run(&self.state, request).await + } + async fn begin_rootfs_tar_staging( &self, request: Request, diff --git a/crates/openshell-server/src/grpc/mutation_replay/ordinary.rs b/crates/openshell-server/src/grpc/mutation_replay/ordinary.rs index 25410043f6..c0a5887728 100644 --- a/crates/openshell-server/src/grpc/mutation_replay/ordinary.rs +++ b/crates/openshell-server/src/grpc/mutation_replay/ordinary.rs @@ -471,6 +471,11 @@ scoped_mutation!( }) } ); +sandbox_mutation!( + openshell_core::proto::UpdateSandboxRequest, + "UpdateSandbox", + sandbox::handle_update_sandbox +); sandbox_mutation!( StartSandboxRequest, "StartSandbox", diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index 77a54a2bc8..5b2ed1905c 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -315,6 +315,75 @@ pub(super) async fn handle_create_sandbox( result } +/// Only the workload image is mutable in the first update contract. Runtime +/// replacement is an explicit Stop/Update/Start workflow, never Delete/Create. +pub(super) async fn handle_update_sandbox( + state: &Arc, + request: Request, +) -> Result, Status> { + let principal = super::extract_principal(&request)?; + let request = request.into_inner(); + validate_image_update_request(&request)?; + let sandbox = resolve_and_authorize_sandbox_name( + state, + &principal, + &request.name, + crate::auth::workspace_authz::selected_workspace_name(request.workspace_scope.as_ref())?, + MinWorkspaceRole::User, + ) + .await?; + super::workspace::resolve_workspace(state.store.as_ref(), sandbox.object_workspace()) + .await? + .ensure_active()?; + let mut candidate = sandbox + .spec + .clone() + .ok_or_else(|| Status::failed_precondition("sandbox has no spec"))?; + candidate + .template + .get_or_insert_with(Default::default) + .image + .clone_from(&request.image); + validate_sandbox_spec(&request.name, &candidate)?; + let sandbox = state + .compute + .update_sandbox_image( + sandbox.object_id(), + request.image, + request.expected_resource_version, + ) + .await?; + Ok(Response::new(SandboxResponse { + sandbox: Some(sandbox), + service_urls: HashMap::new(), + })) +} + +fn validate_image_update_request( + request: &openshell_core::proto::UpdateSandboxRequest, +) -> Result<(), Status> { + if request.name.is_empty() { + return Err(Status::invalid_argument("name is required")); + } + if request.expected_resource_version == 0 { + return Err(Status::invalid_argument( + "expected_resource_version must be nonzero", + )); + } + if request.image.is_empty() + || request.image.len() > super::MAX_TEMPLATE_STRING_LEN + || request + .image + .chars() + .any(|character| character.is_whitespace() || character.is_control()) + { + return Err(Status::invalid_argument( + "image must be a nonempty bounded OCI reference without whitespace or control characters", + )); + } + Ok(()) +} + /// Allocate a gateway-owned staging slot for a local rootfs tar archive. /// /// The caller writes the archive to the returned path and then names the token @@ -10470,3 +10539,6 @@ mod tests { )); } } + +#[cfg(test)] +mod image_update_tests; diff --git a/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs b/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs new file mode 100644 index 0000000000..b45259c88b --- /dev/null +++ b/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs @@ -0,0 +1,224 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use super::*; +use crate::grpc::test_support::{authed_request, test_server_state}; +use crate::test_support::{FakeComputeDriver, FakeComputeDriverCall}; +use openshell_core::proto::UpdateSandboxRequest; +use openshell_core::proto::compute::v1::GetCapabilitiesResponse; +use openshell_core::proto::datamodel::v1::ObjectMeta; +use tonic::Code; + +fn request() -> UpdateSandboxRequest { + UpdateSandboxRequest { + workspace_scope: Some(openshell_core::proto::workspace_selector("default")), + name: "image-update".into(), + image: "example/workload:new".into(), + expected_resource_version: 1, + request_id: String::new(), + } +} + +#[test] +fn image_only_request_requires_target_image_and_conditional_version() { + let valid = request(); + validate_image_update_request(&valid).unwrap(); + for image in ["", " ", "example/workload:tag\n", "bad image", "a\0b"] { + assert_eq!( + validate_image_update_request(&UpdateSandboxRequest { + image: image.into(), + ..valid.clone() + }) + .unwrap_err() + .code(), + Code::InvalidArgument + ); + } + assert!( + validate_image_update_request(&UpdateSandboxRequest { + image: "a".repeat(super::super::MAX_TEMPLATE_STRING_LEN + 1), + ..valid.clone() + }) + .is_err() + ); + assert!( + validate_image_update_request(&UpdateSandboxRequest { + name: String::new(), + ..valid.clone() + }) + .is_err() + ); + assert!( + validate_image_update_request(&UpdateSandboxRequest { + expected_resource_version: 0, + ..valid + }) + .is_err() + ); +} + +async fn state() -> (Arc, Arc, Sandbox) { + let mut state = test_server_state().await; + let driver = Arc::new( + FakeComputeDriver::new().with_capabilities(GetCapabilitiesResponse { + driver_name: "image-test".into(), + default_image: "example/workload:old".into(), + extension: Some(openshell_core::extension_protocol::extension_metadata( + openshell_core::extension_protocol::ExtensionFamily::Compute, + "openshell/image-test", + "test", + [openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.into()], + )), + ..Default::default() + }), + ); + let compute = crate::compute::ComputeRuntime::from_driver( + "image-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 mut sandbox = Sandbox { + metadata: Some(ObjectMeta { + id: "stable-sandbox-id".into(), + name: "image-update".into(), + workspace: "default".into(), + ..Default::default() + }), + spec: Some(SandboxSpec { + template: Some(SandboxTemplate { + image: "example/workload:old".into(), + ..Default::default() + }), + ..Default::default() + }), + ..Default::default() + }; + sandbox.set_phase(SandboxPhase::Stopped as i32); + state.store.put_message(&sandbox).await.unwrap(); + let sandbox = state + .store + .get_message::(sandbox.object_id()) + .await + .unwrap() + .unwrap(); + (state, driver, sandbox) +} + +#[tokio::test] +async fn public_image_update_checks_workspace_and_missing_resource() { + let (state, driver, sandbox) = state().await; + let mut req = request(); + req.expected_resource_version = sandbox.get_resource_version(); + req.workspace_scope = None; + assert_eq!( + handle_update_sandbox(&state, authed_request(req.clone())) + .await + .unwrap_err() + .code(), + Code::InvalidArgument + ); + req.workspace_scope = Some(openshell_core::proto::workspace_selector("default")); + req.name = "missing-sandbox".into(); + assert_eq!( + handle_update_sandbox(&state, authed_request(req)) + .await + .unwrap_err() + .code(), + Code::NotFound + ); + assert!( + !driver + .calls() + .iter() + .any(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxImage { .. })) + ); +} + +#[tokio::test] +async fn public_image_update_replays_without_reapplying_or_touching_same_name_replacement() { + let (mut state, driver, sandbox) = state().await; + let directory = tempfile::tempdir().unwrap(); + let key = directory.path().join("private-key"); + std::fs::write(&key, b"test-only stable private fingerprint material").unwrap(); + Arc::get_mut(&mut state).unwrap().config.gateway_jwt = + Some(openshell_core::config::GatewayJwtConfig { + signing_key_path: key, + public_key_path: directory.path().join("public"), + kid_path: directory.path().join("kid"), + gateway_id: "test".into(), + ttl_secs: None, + }); + let req = UpdateSandboxRequest { + expected_resource_version: sandbox.get_resource_version(), + request_id: uuid::Uuid::new_v4().to_string(), + ..request() + }; + let updated = super::super::mutation_replay::run(&state, authed_request(req.clone())) + .await + .unwrap() + .into_inner() + .sandbox + .unwrap(); + assert_eq!(updated.object_id(), sandbox.object_id()); + assert_eq!( + updated + .spec + .as_ref() + .unwrap() + .template + .as_ref() + .unwrap() + .image, + req.image + ); + let replay = super::super::mutation_replay::run(&state, authed_request(req.clone())) + .await + .unwrap(); + assert_eq!(replay.metadata().get("openshell-replayed").unwrap(), "true"); + assert_eq!(replay.get_ref().sandbox.as_ref().unwrap(), &updated); + assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxImage { request } if !request.validate_only)).count(), 1); + let changed = UpdateSandboxRequest { + image: "example/workload:other".into(), + ..req.clone() + }; + assert_eq!( + super::super::mutation_replay::run(&state, authed_request(changed)) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + state + .store + .delete(Sandbox::object_type(), sandbox.object_id()) + .await + .unwrap(); + let mut replacement = sandbox.clone(); + let metadata = replacement.metadata.as_mut().unwrap(); + metadata.id = "replacement-sandbox-id".into(); + metadata.resource_version = 0; + state.store.put_message(&replacement).await.unwrap(); + assert_eq!( + super::super::mutation_replay::run(&state, authed_request(req)) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + let replacement = state + .store + .get_message::(replacement.object_id()) + .await + .unwrap() + .unwrap(); + assert_eq!(replacement.spec, sandbox.spec); + assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxImage { request } if !request.validate_only)).count(), 1); +} diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index 49d158637a..360c2dd2fa 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -163,12 +163,18 @@ mod tests { // and SUSPENDED values to the shared // SandboxPhase enum. Stored rows never carried those values, so prior // payloads decode unchanged. + + // Image updates add UpdateSandboxRequest to the public inventory and + // SandboxImageUpdate to both the public and durable inventories through + // SandboxStatus. The pending intent and monotonic image revision follow the + // existing token-grant observation without reusing its wire tag. Legacy + // sandboxes decode absent/zero; revisions fence delayed driver retries. const PUBLIC_RPC_SCHEMA_SHA256: &str = - "f24c9b77a85f59ae9ab60f783d45654d78bf566fcf260f9131f1aba39fa4b59b"; + "ad55008e162f4c0c759a047b12d4a8b30ffc04d02899edb2a5d7be44fa79fba5"; const DURABLE_SCHEMA_SHA256: &str = - "ffb20595e36032a9476d1c6956e2dcdc814f85286fc4735751e5ec6f499ea9ed"; + "36eace7a0236872f5167913e53c5be19805b837f18d85b7f6a7dee05c25a896a"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = - "ac1ffc4b5b81467de27270a4e33f6db1e31eeb2c52f79750dbaaf19515eadbb2"; + "9997e51420f29542cefd99d394e211a8e5a21967f4f0fb9ac94aaf598a821b11"; // 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"; @@ -631,7 +637,7 @@ mod tests { } assert_eq!( compiled_method_count, - 106 + PROVIDER_READINESS_RPC_SIGNATURES.len() + 108 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len() + PEER_CONFIG_RPC_SIGNATURES.len() + isolation_methods.len() @@ -641,7 +647,7 @@ mod tests { ); assert_eq!( methods.len(), - 80 + PROVIDER_READINESS_RPC_SIGNATURES.len() + 81 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len() + PEER_CONFIG_RPC_SIGNATURES.len(), "inventory every public gateway RPC" @@ -651,7 +657,7 @@ mod tests { .iter() .filter(|method| method.starts_with("openshell.v1.OpenShell/")) .count(), - 80 + PROVIDER_READINESS_RPC_SIGNATURES.len() + 81 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len() + PEER_CONFIG_RPC_SIGNATURES.len() ); @@ -702,9 +708,9 @@ mod tests { overlap_hash.as_str(), ), ( - (330, 31), - (95, 22), - (83, 22), + (332, 31), + (96, 22), + (84, 22), PUBLIC_RPC_SCHEMA_SHA256, DURABLE_SCHEMA_SHA256, PUBLIC_DURABLE_OVERLAP_SHA256 @@ -713,6 +719,17 @@ mod tests { ); } + #[test] + fn pre_image_update_sandbox_has_no_pending_image_intent() { + let sandbox = openshell_core::proto::Sandbox::decode( + legacy_bytes(SANDBOX_WITHOUT_ENDPOINT_STATUS).as_slice(), + ) + .expect("legacy sandbox must remain decodable"); + let status = sandbox.status.unwrap(); + assert!(status.image_update.is_none()); + assert_eq!(status.image_revision, 0); + } + #[test] fn service_endpoint_without_authorization_mode_decodes_as_strip() { use openshell_core::proto::{ServiceAuthorizationMode, ServiceEndpoint}; diff --git a/crates/openshell-server/src/supervisor_pool.rs b/crates/openshell-server/src/supervisor_pool.rs index 459deb0d08..cd2dc478bc 100644 --- a/crates/openshell-server/src/supervisor_pool.rs +++ b/crates/openshell-server/src/supervisor_pool.rs @@ -4810,7 +4810,11 @@ mod tests { let launching = fixture.replica("gw-b"); let (pass, launched) = tokio::join!( pool.reconcile_once(), - launching.place_launch(launch("rt-route-new0", "sandbox-new", "generation-1")), + Box::pin(launching.place_launch(launch( + "rt-route-new0", + "sandbox-new", + "generation-1" + ))), ); pass.unwrap(); // Every route is re-adopted by the new process at the next term, diff --git a/crates/openshell-server/src/test_support.rs b/crates/openshell-server/src/test_support.rs index 454af49d8c..43d39be7ee 100644 --- a/crates/openshell-server/src/test_support.rs +++ b/crates/openshell-server/src/test_support.rs @@ -105,6 +105,9 @@ pub enum FakeComputeDriverCall { CreateSandbox { sandbox: Option, }, + UpdateSandboxImage { + request: openshell_core::proto::compute::v1::UpdateSandboxImageRequest, + }, StopSandbox { sandbox_id: String, sandbox_name: String, @@ -140,6 +143,8 @@ struct FakeComputeDriverState { sandboxes: HashMap, calls: Vec, traceparents: Vec, + image_update_error: Option, + image_validation_error: Option, } impl Default for FakeComputeDriver { @@ -183,6 +188,8 @@ impl FakeComputeDriver { sandboxes: HashMap::new(), calls: Vec::new(), traceparents: Vec::new(), + image_update_error: None, + image_validation_error: None, })), } } @@ -260,6 +267,14 @@ impl FakeComputeDriver { Ok(FakeComputeDriverServerHandle { socket_path, task }) } + pub fn set_image_update_error(&self, code: Option) { + self.with_state(|state| state.image_update_error = code); + } + + pub fn set_image_validation_error(&self, code: Option) { + self.with_state(|state| state.image_validation_error = code); + } + fn with_state(&self, f: impl FnOnce(&mut FakeComputeDriverState) -> R) -> R { let mut state = self .state @@ -312,6 +327,30 @@ impl Stream for UnixIncoming { #[tonic::async_trait] impl ComputeDriver for FakeComputeDriver { + async fn update_sandbox_image( + &self, + request: Request, + ) -> Result, Status> + { + self.record_traceparent(request.metadata()); + self.with_state(|state| { + let request = request.into_inner(); + let validate_only = request.validate_only; + state + .calls + .push(FakeComputeDriverCall::UpdateSandboxImage { request }); + if let Some(code) = state.image_validation_error.filter(|_| validate_only) { + return Err(Status::new(code, "injected image validation error")); + } + if let Some(code) = state.image_update_error.filter(|_| !validate_only) { + return Err(Status::new(code, "injected image update error")); + } + Ok(Response::new( + openshell_core::proto::compute::v1::UpdateSandboxImageResponse {}, + )) + }) + } + async fn authenticate_sandbox( &self, _request: Request, diff --git a/crates/openshell-server/tests/common/mod.rs b/crates/openshell-server/tests/common/mod.rs index dd91664d39..6296034d6b 100644 --- a/crates/openshell-server/tests/common/mod.rs +++ b/crates/openshell-server/tests/common/mod.rs @@ -59,6 +59,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } + async fn update_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented by test service")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-server/tests/supervisor_relay_integration.rs b/crates/openshell-server/tests/supervisor_relay_integration.rs index ceb2fa6bf8..283bbca2b7 100644 --- a/crates/openshell-server/tests/supervisor_relay_integration.rs +++ b/crates/openshell-server/tests/supervisor_relay_integration.rs @@ -57,6 +57,13 @@ impl OpenShell for RelayGateway { Err(Status::unimplemented("not used by this test server")) } + async fn update_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented by test service")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index aadfdbe281..bfe19d6f27 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -1010,6 +1010,54 @@ If an infrastructure failure leaves a sandbox in `Error`, fix the reported cause For a provisioning timeout, wait for cleanup to finish, then run `sandbox start` directly. +### Update the Image of a Stopped Sandbox + +Use the raw `UpdateSandbox` RPC to change only a stopped sandbox's workload +image. This operation initially supports the Kubernetes compute driver only; +other drivers return `UNIMPLEMENTED`. There is no `sandbox update` CLI command +or curated SDK update method. + +The update preserves the sandbox ID, Kubernetes custom resource, and persistent +volume claim. It does not delete and recreate the sandbox, reseed its existing +workspace from the new image, or change the trusted supervisor and sandbox +runtime images. Other create-time configuration remains unchanged. Submitting the +same image reference is a no-op; use a different tag or an immutable digest to +select new image content. + +Follow this sequence through the CLI and a generated/raw RPC client. + +1. Run `openshell sandbox stop my-sandbox` and wait for `Stopped`. +2. Call `GetSandbox` with the named `workspace_scope` and sandbox `name`. Read + `sandbox.metadata.resource_version` after stop completes. +3. Call `UpdateSandbox` with the same scope and name, the nonempty OCI workload + `image`, and `expected_resource_version` set to that current, nonzero + version. The response is a `SandboxResponse`; the sandbox remains stopped. +4. After the update succeeds, run `openshell sandbox start my-sandbox` to launch + the new image. + +If the new image fails to start and provisioning times out, wait until +`provisioning.cleanup_completed_time` is present and +`provisioning.driver_operation_pending` is false. Run `sandbox stop` to move the +reclaimed sandbox from `Error` to `Stopped`, then repeat the update sequence with +a working image. Stop retains the timeout record and storage; it does not stop +compute again. Cleanup that is still pending cannot be bypassed. + +An `ABORTED` version conflict requires another read before you construct a new +conditional request. An update failure or disconnected response can leave a +persistent `sandbox.status.image_update` intent, even when +`sandbox.spec.template.image` already names the target image. While that intent +exists, start is blocked. Read the current version and retry `UpdateSandbox` +with the intent's same `image`; do not select a different image or delete the +sandbox to bypass reconciliation. Only a successful retry clears the intent. + +The optional `request_id` uses [durable request admission](/sdk/api-errors#durable-request-admission). +A retry with the same ID must keep the original payload, including its expected +version. An unresolved admission returns `REQUEST_OUTCOME_UNCERTAIN` rather than +executing again. Reconcile the sandbox and pending target first, then submit a +new conditional same-image request with a fresh version and a new ID, or no ID. +Do not change the expected version under the original ID or blindly switch IDs +after a timeout. + ## Delete Sandboxes Deleting a sandbox stops all processes, releases resources, and purges injected credentials. diff --git a/docs/sdk/api-errors.mdx b/docs/sdk/api-errors.mdx index 23a34c3b96..592cebbe2f 100644 --- a/docs/sdk/api-errors.mdx +++ b/docs/sdk/api-errors.mdx @@ -56,7 +56,7 @@ guarantee. | `ABORTED` | Read fresh state before retrying a conditional operation. | | `UNAVAILABLE`, `RESOURCE_EXHAUSTED` | A transient condition may recover. Apply backoff and any minimum retry delay only to a retry-safe operation. | | `DEADLINE_EXCEEDED`, `CANCELLED` | A mutation's outcome can be unknown. Cancellation does not imply rollback. | -| `UNIMPLEMENTED` | Check gateway and SDK version compatibility. | +| `UNIMPLEMENTED` | Check gateway and SDK version compatibility and whether the compute driver supports the operation. | | `INTERNAL`, `UNKNOWN`, `DATA_LOSS` | Preserve the status and correlation metadata for diagnosis. Do not blindly retry mutations. | ## SDK access @@ -92,14 +92,14 @@ No SDK automatically retries a mutation as a result of decoding these details. ## Durable request admission -Thirty user-callable unary RPCs accept an optional `request_id` in their protobuf requests. +Thirty-one user-callable unary RPCs accept an optional `request_id` in their protobuf requests. | Resource | RPCs | |---|---| | Workspace | `CreateWorkspace`, `DeleteWorkspace` | | Workspace member | `AddWorkspaceMember`, `RemoveWorkspaceMember` | | Sandbox template | `CreateSandboxTemplate`, `DeleteSandboxTemplate` | -| Sandbox | `CreateSandbox`, `DeleteSandbox`, `StartSandbox`, `StopSandbox`, `AttachSandboxProvider`, `DetachSandboxProvider` | +| Sandbox | `CreateSandbox`, `UpdateSandbox`, `DeleteSandbox`, `StartSandbox`, `StopSandbox`, `AttachSandboxProvider`, `DetachSandboxProvider` | | Service | `ExposeService`, `DeleteService` | | Provider | `CreateProvider`, `UpdateProvider`, `DeleteProvider`, `ConfigureProviderRefresh`, `DeleteProviderRefresh`, `RotateProviderCredential` | | Provider profile | `ImportProviderProfiles`, `UpdateProviderProfiles`, `DeleteProviderProfile` | @@ -192,6 +192,33 @@ from this feature. Sandbox principals cannot opt into `UpdateConfig` admission. Check gateway compatibility before relying on IDs; older protobuf servers can silently ignore unknown fields. +### Sandbox image update recovery + +`UpdateSandbox` is an image-only conditional mutation for stopped Kubernetes +sandboxes. Other compute drivers return `UNIMPLEMENTED`. Supply a named +`workspace_scope`, sandbox `name`, nonempty OCI `image`, and a required nonzero +`expected_resource_version` read from `sandbox.metadata.resource_version`. +A stale version returns `ABORTED`; read fresh state before constructing another +conditional request. The operation does not start compute. + +A failed or interrupted update can leave durable `sandbox.status.image_update` +state. The desired spec image alone does not prove driver reconciliation +completed. Start returns `FAILED_PRECONDITION` until you successfully retry the +same pending image using the current resource version. A different target image +cannot replace a pending update. + +If the original request supplied `request_id`, an error leaves its admission +unresolved. Reusing that ID with the original payload returns +`REQUEST_OUTCOME_UNCERTAIN`; changing its expected version returns +`REQUEST_ID_PAYLOAD_MISMATCH`. Inspect and reconcile the pending image first, +then make a new conditional same-image request with the fresh version and a new +ID, or without an ID. This is explicit recovery, not permission to blindly +repeat uncertain mutations. A replay of a confirmed success returns the +sandbox's current state without applying the image again. + +See [Update the Image of a Stopped Sandbox](/how-it-works/sandboxes/overview#update-the-image-of-a-stopped-sandbox) +for the stop, update, and start workflow and storage guarantees. + ## Exec launch admission `ExecSandbox` and `ExecSandboxInteractive` accept an optional `request_id` in diff --git a/e2e/rust/Cargo.lock b/e2e/rust/Cargo.lock index 9f585578ce..a6e8d591ba 100644 --- a/e2e/rust/Cargo.lock +++ b/e2e/rust/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e567177890eb1617b1f774005b66b26b2377afd138a2ca37aae7d8f0c81429d4" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" version = "2.0.1" @@ -64,7 +73,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror", + "thiserror 2.0.19", "time", ] @@ -77,7 +86,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.119", - "synstructure", + "synstructure 0.13.2", ] [[package]] @@ -235,6 +244,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "backtrace" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f4220217f3288537b83684130f42fad43320b1c3b805f1910d683d52ded24f" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + [[package]] name = "base64" version = "0.22.1" @@ -322,7 +355,7 @@ dependencies = [ "serde_derive", "serde_json", "serde_urlencoded", - "thiserror", + "thiserror 2.0.19", "tokio", "tokio-util", "tower-service", @@ -766,6 +799,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flate2" version = "1.1.10" @@ -958,8 +997,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -988,6 +1029,18 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "gimli" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1033caf0b349c518623b5396bfb2cf0bddf44f0306d543a250e5743297aafd10" + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + [[package]] name = "gloo-timers" version = "0.3.0" @@ -1280,13 +1333,16 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", "futures-util", "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", @@ -1335,9 +1391,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "fe090a42a0d3140fed8c63263ed1fecc02422cb2f4bfe55cd8de2de1b8e105dd" dependencies = [ "displaydoc", "potential_utf", @@ -1349,22 +1405,43 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" dependencies = [ "displaydoc", "litemap", + "serde", "tinystr", "writeable", "zerovec", ] +[[package]] +name = "icu_locale_fallback" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406e9ae5b95d8aa37db6293405931b766a6172d1848daee22d70eb44aa78a43c" +dependencies = [ + "icu_locale_core", + "icu_locale_fallback_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_fallback_data" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3632ebbd0c5c3637ba1a40bdf8288f2cb9d2268e73441a69d5fc73d7cfbaa87c" + [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "404a3b8c486f205c87fe7f23ab6894d84a4ad76d6e4671ae1981ba7def87c599" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1376,16 +1453,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "20f0088bfb7441f7a37fa0c9e20cb1e9cba1cac6b9ce8cd2a6dc44294f8e8cbc" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "2ea83d991c56158f7cf898bf86436c1dfe7c07ee82fe88951f2695c9f37a379f" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -1396,18 +1474,20 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "b98f29af82d02b163fe50161388350e743bb3107cc8e8c2f7314cb505faddfcf" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514" dependencies = [ "displaydoc", "icu_locale_core", + "serde", + "stable_deref_trait", "writeable", "yoke", "zerofrom", @@ -1415,6 +1495,29 @@ dependencies = [ "zerovec", ] +[[package]] +name = "icu_segmenter" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b195dc605f81aa181bec9b3bd14e26cc71b903e4644f6af578ca9772c7a710" +dependencies = [ + "icu_collections", + "icu_locale_fallback", + "icu_provider", + "icu_segmenter_data", + "potential_utf", + "smallvec", + "utf8_iter", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_segmenter_data" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913a7d294ad056474749152107309fdee3ec17d2482d1ab70fdc61a81c64b9a3" + [[package]] name = "ident_case" version = "1.0.1" @@ -1454,6 +1557,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "ipnet" +version = "2.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" + +[[package]] +name = "is_ci" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + [[package]] name = "itertools" version = "0.14.0" @@ -1499,7 +1614,7 @@ dependencies = [ "jsonptr", "serde", "serde_json", - "thiserror", + "thiserror 2.0.19", ] [[package]] @@ -1512,7 +1627,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror", + "thiserror 2.0.19", ] [[package]] @@ -1651,7 +1766,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "thiserror", + "thiserror 2.0.19", "tokio", "tokio-util", "tower", @@ -1674,7 +1789,7 @@ dependencies = [ "serde", "serde-value", "serde_json", - "thiserror", + "thiserror 2.0.19", ] [[package]] @@ -1713,7 +1828,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror", + "thiserror 2.0.19", "tokio", "tokio-util", "tracing", @@ -1822,6 +1937,36 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a86d3146ed3995b5913c414f6664344b9617457320782e64f0bb44afd49d74" +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "backtrace", + "backtrace-ext", + "cfg-if", + "miette-derive", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "unicode-width 0.1.14", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "mime" version = "0.3.17" @@ -1855,6 +2000,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + [[package]] name = "nix" version = "0.29.0" @@ -1985,6 +2136,35 @@ dependencies = [ "autocfg", ] +[[package]] +name = "oauth2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" +dependencies = [ + "base64 0.22.1", + "chrono", + "getrandom 0.2.17", + "http", + "rand 0.8.8", + "reqwest", + "serde", + "serde_json", + "serde_path_to_error", + "sha2 0.10.9", + "thiserror 1.0.69", + "url", +] + +[[package]] +name = "object" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd229a0361b9d0d4396176e02d65897f487eebeab7caa6d443855ee152ca0b9c" +dependencies = [ + "memchr", +] + [[package]] name = "oid-registry" version = "0.8.1" @@ -2000,6 +2180,59 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "openshell-bootstrap" +version = "0.0.0" +dependencies = [ + "bytes", + "miette", + "openshell-core", + "openshell-crypto", + "rcgen", + "serde", + "serde_json", + "tempfile", + "tokio", + "tracing", +] + +[[package]] +name = "openshell-core" +version = "0.0.0" +dependencies = [ + "async-trait", + "base64 0.22.1", + "chrono", + "glob", + "ipnet", + "libc", + "miette", + "nix", + "openshell-crypto", + "openshell-extension-core", + "openshell-policy-schema", + "prost", + "prost-types", + "protoc-bin-vendored", + "reqwest", + "rustix", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "sha2 0.10.9", + "thiserror 2.0.19", + "tokio", + "tokio-stream", + "tonic", + "tonic-prost", + "tonic-prost-build", + "tonic-types", + "tracing", + "url", + "uuid", +] + [[package]] name = "openshell-crypto" version = "0.0.0" @@ -2012,7 +2245,7 @@ dependencies = [ "rustls", "serde", "sqlx", - "thiserror", + "thiserror 2.0.19", "tonic", "x509-parser", ] @@ -2032,9 +2265,11 @@ dependencies = [ "jsonwebtoken", "nix", "noyalib", + "openshell-bootstrap", "openshell-crypto", "openshell-ocsf-validate", "openshell-otel-test-support", + "openshell-sdk", "opentelemetry-proto", "prost", "rand 0.9.5", @@ -2054,6 +2289,18 @@ dependencies = [ "url", ] +[[package]] +name = "openshell-extension-core" +version = "0.0.0" +dependencies = [ + "hyper-util", + "serde", + "thiserror 2.0.19", + "tokio", + "tonic", + "tower", +] + [[package]] name = "openshell-ocsf" version = "0.0.0" @@ -2088,7 +2335,7 @@ dependencies = [ "opentelemetry-otlp", "opentelemetry_sdk", "serde_json", - "thiserror", + "thiserror 2.0.19", "tokio", "tonic", "tower-http", @@ -2111,6 +2358,43 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "openshell-policy-schema" +version = "0.0.0" +dependencies = [ + "miette", + "noyalib", + "serde", + "serde_json", + "serde_path_to_error", + "thiserror 2.0.19", +] + +[[package]] +name = "openshell-sdk" +version = "0.0.0" +dependencies = [ + "async-stream", + "async-trait", + "futures", + "hyper", + "hyper-util", + "miette", + "oauth2", + "openshell-core", + "openshell-crypto", + "reqwest", + "rustls", + "serde", + "thiserror 2.0.19", + "tokio", + "tokio-rustls", + "tokio-tungstenite", + "tonic", + "tower", + "tracing", +] + [[package]] name = "openssl-probe" version = "0.2.1" @@ -2127,7 +2411,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror", + "thiserror 2.0.19", "tracing", ] @@ -2142,7 +2426,7 @@ dependencies = [ "opentelemetry-proto", "opentelemetry_sdk", "prost", - "thiserror", + "thiserror 2.0.19", "tokio", "tonic", "tonic-types", @@ -2174,7 +2458,7 @@ dependencies = [ "percent-encoding", "portable-atomic", "rand 0.9.5", - "thiserror", + "thiserror 2.0.19", "tokio", "tokio-stream", ] @@ -2194,6 +2478,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" +[[package]] +name = "owo-colors" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c45bb4a6ae1280ec0803b1ef9d3455eb50f01efbbe1447ab020f1d54fba9d8" + [[package]] name = "parking" version = "2.2.1" @@ -2291,6 +2581,17 @@ dependencies = [ "pest", ] +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", +] + [[package]] name = "pin-project" version = "1.1.13" @@ -2335,6 +2636,8 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ + "serde_core", + "writeable", "zerovec", ] @@ -2353,6 +2656,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.119", +] + [[package]] name = "proc-macro2" version = "1.0.107" @@ -2372,6 +2685,27 @@ dependencies = [ "prost-derive", ] +[[package]] +name = "prost-build" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" +dependencies = [ + "heck", + "itertools", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "pulldown-cmark", + "pulldown-cmark-to-cmark", + "regex", + "syn 2.0.119", + "tempfile", +] + [[package]] name = "prost-derive" version = "0.14.4" @@ -2394,6 +2728,90 @@ dependencies = [ "prost", ] +[[package]] +name = "protoc-bin-vendored" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8760a25b6ff9c620324822737e468478fa092234190d2e449760344354896ed9" +dependencies = [ + "protoc-bin-vendored-linux-aarch_64", + "protoc-bin-vendored-linux-ppcle_64", + "protoc-bin-vendored-linux-s390_64", + "protoc-bin-vendored-linux-x86_32", + "protoc-bin-vendored-linux-x86_64", + "protoc-bin-vendored-macos-aarch_64", + "protoc-bin-vendored-macos-x86_64", + "protoc-bin-vendored-win32", +] + +[[package]] +name = "protoc-bin-vendored-linux-aarch_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fa2624782ca04cd44f51554566717377acd240e4c0016d757dd74fccc9324f" + +[[package]] +name = "protoc-bin-vendored-linux-ppcle_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2417e9817fa237dab803ad4dda7357a111656e242959cc6b8f9a1a583367d42" + +[[package]] +name = "protoc-bin-vendored-linux-s390_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d189c34636356a46a7ed3188233dc8a88c431278cc54d4a19b096a2d270e985" + +[[package]] +name = "protoc-bin-vendored-linux-x86_32" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171e39f1e846e5f322ced1ac3b8d4cd3a3833ca24b6e5d58b3632574fe6204fa" + +[[package]] +name = "protoc-bin-vendored-linux-x86_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873cdcc097593432086661aa432b8078f1cd87bfb02847c332e98ae2c119e966" + +[[package]] +name = "protoc-bin-vendored-macos-aarch_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeb72df001783b8297847fe8f5f874ee400fd742c843d60583e8c23d96977c7f" + +[[package]] +name = "protoc-bin-vendored-macos-x86_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04652167eca899dda05f32f5481adeaf25c623a98ce2fc146a001cc59a2add7" + +[[package]] +name = "protoc-bin-vendored-win32" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "263a3f48f01e7309e857138bd47f785585b4a005e8e56c6d2824ce91195999c3" + +[[package]] +name = "pulldown-cmark" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278e9268c93b9e498a2da46c34d90ba93a3255eb99009646398f34bc73ab36eb" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + +[[package]] +name = "pulldown-cmark-to-cmark" +version = "22.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84bbb29c624230c4bd1047bbdb2aa47e41c860e9665ce62ba9504eebe91bf867" +dependencies = [ + "pulldown-cmark", +] + [[package]] name = "quote" version = "1.0.47" @@ -2415,13 +2833,24 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ - "rand_chacha", + "rand_chacha 0.9.0", "rand_core 0.9.5", ] @@ -2436,6 +2865,16 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_chacha" version = "0.9.0" @@ -2568,6 +3007,45 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "ring" version = "0.17.14" @@ -2582,6 +3060,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + [[package]] name = "rustc-hash" version = "2.1.3" @@ -2805,6 +3289,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + [[package]] name = "serde_repr" version = "0.1.21" @@ -2958,7 +3453,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 2.0.19", "time", ] @@ -3037,7 +3532,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "smallvec", - "thiserror", + "thiserror 2.0.19", "tokio", "tokio-stream", "tracing", @@ -3078,7 +3573,7 @@ dependencies = [ "sqlx-postgres", "sqlx-sqlite", "syn 2.0.119", - "thiserror", + "thiserror 2.0.19", "tokio", "url", ] @@ -3105,7 +3600,7 @@ dependencies = [ "sha1 0.11.0", "sha2 0.11.0", "sqlx-core", - "thiserror", + "thiserror 2.0.19", "tracing", ] @@ -3139,7 +3634,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 2.0.19", "tracing", "whoami", ] @@ -3163,7 +3658,7 @@ dependencies = [ "percent-encoding", "serde", "sqlx-core", - "thiserror", + "thiserror 2.0.19", "tracing", "url", ] @@ -3218,6 +3713,27 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "supports-color" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" +dependencies = [ + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" + +[[package]] +name = "supports-unicode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" + [[package]] name = "syn" version = "2.0.119" @@ -3245,6 +3761,9 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -3257,6 +3776,17 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "synstructure" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "tempfile" version = "3.27.0" @@ -3270,13 +3800,53 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "terminal_size" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +dependencies = [ + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "textwrap" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ecfad6c3abc80a577f2b91c1e412ee57e7a060d430b553c1b0c940974ebcd49" +dependencies = [ + "icu_segmenter", + "unicode-width 0.2.3", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.19", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] @@ -3331,11 +3901,12 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" dependencies = [ "displaydoc", + "serde_core", "zerovec", ] @@ -3394,6 +3965,22 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.19" @@ -3441,6 +4028,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic-build" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c07bd4e9f99e2a3ed8bebad596ae02a94e53745b68acc6900e22c3475c8bc44" +dependencies = [ + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "tonic-prost" version = "0.14.6" @@ -3452,6 +4051,22 @@ dependencies = [ "tonic", ] +[[package]] +name = "tonic-prost-build" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05d8957fac6b3542999796cb4449d45da790751962f974a457e5e00c43d78c" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "prost-types", + "quote", + "syn 2.0.119", + "tempfile", + "tonic-build", +] + [[package]] name = "tonic-types" version = "0.14.6" @@ -3491,13 +4106,16 @@ dependencies = [ "base64 0.22.1", "bitflags", "bytes", + "futures-util", "http", "http-body", "mime", "pin-project-lite", + "tower", "tower-layer", "tower-service", "tracing", + "url", "uuid", ] @@ -3609,6 +4227,25 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.5", + "rustls", + "rustls-pki-types", + "sha1 0.10.7", + "thiserror 2.0.19", + "utf-8", +] + [[package]] name = "typenum" version = "1.20.1" @@ -3621,6 +4258,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" +[[package]] +name = "unicase" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f" + [[package]] name = "unicode-bidi" version = "0.3.18" @@ -3654,6 +4297,18 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca718471876992059f251e33aafc334346ada08042b7661dd1fe313a9bced557" + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -3682,8 +4337,15 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -3772,6 +4434,16 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.126" @@ -3804,6 +4476,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "web-time" version = "1.1.0" @@ -4000,9 +4682,9 @@ checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "x509-parser" @@ -4018,7 +4700,7 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 2.0.19", "time", ] @@ -4034,9 +4716,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -4045,14 +4727,14 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", - "synstructure", + "syn 3.0.3", + "synstructure 0.14.0", ] [[package]] @@ -4093,7 +4775,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.119", - "synstructure", + "synstructure 0.13.2", ] [[package]] @@ -4118,21 +4800,23 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", "zerofrom", + "zerovec", ] [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ + "serde", "yoke", "zerofrom", "zerovec-derive", @@ -4140,13 +4824,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] diff --git a/e2e/rust/Cargo.toml b/e2e/rust/Cargo.toml index b40b170996..66293d3582 100644 --- a/e2e/rust/Cargo.toml +++ b/e2e/rust/Cargo.toml @@ -32,7 +32,7 @@ e2e-docker = ["e2e", "e2e-host-gateway", "e2e-local-container-driver"] e2e-config-push = ["e2e-docker"] e2e-gpu = ["e2e"] e2e-docker-gpu = ["e2e-docker", "e2e-gpu"] -e2e-kubernetes = ["e2e"] +e2e-kubernetes = ["e2e", "dep:openshell-bootstrap", "dep:openshell-sdk"] e2e-kubernetes-ha = ["e2e-kubernetes"] e2e-kubernetes-credential-drivers = ["e2e-kubernetes"] e2e-kubernetes-workspace-managed = ["e2e-kubernetes"] @@ -194,6 +194,11 @@ name = "kubernetes_runtime_reconcile" path = "tests/kubernetes_runtime_reconcile.rs" required-features = ["e2e-kubernetes"] +[[test]] +name = "kubernetes_image_update" +path = "tests/kubernetes_image_update.rs" +required-features = ["e2e-kubernetes"] + [[test]] name = "credential_drivers" path = "tests/credential_drivers.rs" @@ -273,6 +278,8 @@ required-features = ["e2e-local-container-driver"] openshell-crypto = { path = "../../crates/openshell-crypto" } openshell-otel-test-support = { path = "../../crates/openshell-otel-test-support" } opentelemetry-proto = { version = "0.32", default-features = false, features = ["gen-tonic", "trace"] } +openshell-bootstrap = { path = "../../crates/openshell-bootstrap", optional = true } +openshell-sdk = { path = "../../crates/openshell-sdk", optional = true } base64 = "0.22" bollard = "0.20" bytes = "1" diff --git a/e2e/rust/tests/kubernetes_image_update.rs b/e2e/rust/tests/kubernetes_image_update.rs new file mode 100644 index 0000000000..9077e66761 --- /dev/null +++ b/e2e/rust/tests/kubernetes_image_update.rs @@ -0,0 +1,424 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![cfg(feature = "e2e-kubernetes")] + +//! Exercise the public image-update RPC in both Agent Sandbox API-version lanes. +//! Kubernetes object checks are read-only and scoped to this test's sandbox. + +use std::collections::BTreeMap; +use std::path::PathBuf; +use std::time::Duration; + +use openshell_bootstrap::{load_active_gateway, load_gateway_metadata}; +use openshell_e2e::harness::cli::{run_cli, wait_for_sandbox_phase}; +use openshell_e2e::harness::sandbox::SandboxGuard; +use openshell_sdk::raw::{AuthedGrpcClient, proto}; +use openshell_sdk::{ClientConfig, EdgeAuthInterceptor, OpenShellClient}; +use serde_json::Value; +use tonic::transport::{Certificate, ClientTlsConfig, Endpoint, Identity}; + +// Multi-platform release manifests; no test-local tags or cluster image loads. +const ORIGINAL_IMAGE: &str = "docker.io/library/alpine:3.21@sha256:ce64758a109eb420d874a118f87920e625e12d3634e03b4a5573fd9f6e5d3507"; +const UPDATED_IMAGE: &str = "docker.io/library/alpine:3.22@sha256:5291449c3df73caf6ed85e649dec1b9e818b39a5d8c871e97afc13e9cd5e8fa8"; +const SENTINEL_PATH: &str = "/sandbox/.image-update-sentinel"; + +/// Reuse the wrapper's registered endpoint (including its isolated XDG config). +/// The SDK owns plaintext transport; the `OpenShift` wrapper registers an mTLS +/// gateway, for which we attach its existing client bundle to a tonic channel. +async fn gateway_client() -> AuthedGrpcClient { + let name = std::env::var("OPENSHELL_GATEWAY") + .ok() + .filter(|name| !name.trim().is_empty()) + .or_else(load_active_gateway) + .expect("Kubernetes E2E wrapper must register a gateway"); + let metadata = load_gateway_metadata(&name).expect("load E2E gateway metadata"); + let client = if metadata.gateway_endpoint.starts_with("http://") { + OpenShellClient::connect(ClientConfig::new(metadata.gateway_endpoint)) + .await + .expect("connect to E2E gateway") + } else { + assert!( + matches!(metadata.auth_mode.as_deref(), None | Some("mtls")), + "Kubernetes E2E wrapper must register plaintext or mTLS transport" + ); + let config = std::env::var_os("XDG_CONFIG_HOME").map_or_else( + || PathBuf::from(std::env::var_os("HOME").expect("HOME")).join(".config"), + PathBuf::from, + ); + let bundle = config.join("openshell/gateways").join(&name).join("mtls"); + let tls = ClientTlsConfig::new() + .ca_certificate(Certificate::from_pem( + std::fs::read(bundle.join("ca.crt")).expect("read E2E gateway CA"), + )) + .identity(Identity::from_pem( + std::fs::read(bundle.join("tls.crt")).expect("read E2E client certificate"), + std::fs::read(bundle.join("tls.key")).expect("read E2E client key"), + )); + let channel = Endpoint::from_shared(metadata.gateway_endpoint) + .expect("E2E gateway endpoint") + .connect_timeout(Duration::from_secs(10)) + .timeout(Duration::from_secs(60)) + .tls_config(tls) + .expect("configure E2E gateway mTLS") + .connect() + .await + .expect("connect to E2E gateway over mTLS"); + OpenShellClient::from_parts(channel, EdgeAuthInterceptor::noop()) + }; + client.raw_grpc() +} + +fn request_id() -> String { + let mut bytes = rand::random::<[u8; 16]>(); + bytes[6] = (bytes[6] & 0x0f) | 0x40; + bytes[8] = (bytes[8] & 0x3f) | 0x80; + let hex = hex::encode(bytes); + format!( + "{}-{}-{}-{}-{}", + &hex[..8], + &hex[8..12], + &hex[12..16], + &hex[16..20], + &hex[20..] + ) +} + +fn rpc(body: T) -> tonic::Request { + let mut request = tonic::Request::new(body); + request.set_timeout(Duration::from_secs(60)); + request +} + +async fn get_sandbox(client: &mut AuthedGrpcClient, name: &str) -> proto::Sandbox { + client + .get_sandbox(rpc(proto::GetSandboxRequest { + workspace_scope: Some(proto::workspace_selector("default")), + name: name.to_owned(), + })) + .await + .expect("get test sandbox") + .into_inner() + .sandbox + .expect("Sandbox response") +} + +async fn kubectl_get(resource: &str, selector: &[&str]) -> Value { + let namespace = std::env::var("OPENSHELL_E2E_SANDBOX_NAMESPACE") + .expect("Kubernetes E2E wrapper must provide the sandbox namespace"); + let context = std::env::var("OPENSHELL_E2E_KUBE_CONTEXT_ACTIVE") + .expect("Kubernetes E2E wrapper must provide its active context"); + assert!(!namespace.trim().is_empty() && !context.trim().is_empty()); + let output = tokio::process::Command::new("kubectl") + .args([ + "--context", + &context, + "--namespace", + &namespace, + "--request-timeout=30s", + "get", + resource, + ]) + .args(selector) + .args(["--output=json"]) + .kill_on_drop(true) + .output() + .await + .expect("run scoped kubectl get"); + assert!( + output.status.success(), + "kubectl get {resource} {selector:?}: {}", + String::from_utf8_lossy(&output.stderr) + ); + serde_json::from_slice(&output.stdout).expect("parse kubectl JSON") +} + +async fn sandbox_resource(id: &str) -> Value { + let selector = format!("openshell.ai/sandbox-id={id}"); + let list = kubectl_get("sandboxes.agents.x-k8s.io", &["--selector", &selector]).await; + let [resource] = list["items"].as_array().expect("Sandbox items").as_slice() else { + panic!("expected exactly one Sandbox resource for {id}: {list}"); + }; + assert_eq!( + resource["metadata"]["labels"]["openshell.ai/sandbox-id"], + id + ); + assert!( + resource["metadata"]["uid"] + .as_str() + .is_some_and(|uid| !uid.is_empty()) + ); + resource.clone() +} + +/// Read claims by their exact names from the actual workload Pod. Do not rely +/// on controller-version-dependent PVC names or labels, or inspect other PVCs. +async fn claim_uids(resource: &Value) -> BTreeMap { + let pod_name = resource["metadata"]["annotations"]["agents.x-k8s.io/pod-name"] + .as_str() + .unwrap_or_else(|| resource["metadata"]["name"].as_str().expect("Sandbox name")); + let pod = kubectl_get("pod", &[pod_name]).await; + assert!( + pod["metadata"]["ownerReferences"] + .as_array() + .expect("workload Pod owners") + .iter() + .any(|owner| owner["uid"] == resource["metadata"]["uid"]), + "workload Pod must belong to this Sandbox resource" + ); + let agent = pod["spec"]["containers"] + .as_array() + .expect("Pod containers") + .iter() + .find(|container| container["name"] == "agent") + .expect("agent container"); + let workspace_volume = agent["volumeMounts"] + .as_array() + .expect("agent volume mounts") + .iter() + .find(|mount| mount["mountPath"] == "/sandbox") + .expect("workspace volume mount"); + let volumes = pod["spec"]["volumes"].as_array().expect("Pod volumes"); + assert!( + volumes.iter().any(|volume| { + volume["name"] == workspace_volume["name"] + && volume["persistentVolumeClaim"]["claimName"] + .as_str() + .is_some() + }), + "workspace must be backed by a PVC" + ); + let mut claims = BTreeMap::new(); + for volume in volumes { + let Some(name) = volume["persistentVolumeClaim"]["claimName"].as_str() else { + continue; + }; + let claim = kubectl_get("persistentvolumeclaim", &[name]).await; + let uid = claim["metadata"]["uid"] + .as_str() + .filter(|uid| !uid.is_empty()) + .expect("PVC UID"); + assert_eq!(claim["status"]["phase"], "Bound"); + claims.insert(name.to_owned(), uid.to_owned()); + } + assert!( + !claims.is_empty(), + "test must exercise PVC-backed workspace storage" + ); + claims +} + +fn assert_resource_retained(before: &Value, after: &Value, image: &str) { + assert_eq!(after["metadata"]["name"], before["metadata"]["name"]); + assert_eq!(after["metadata"]["uid"], before["metadata"]["uid"]); + assert_eq!( + after["spec"]["volumeClaimTemplates"], + before["spec"]["volumeClaimTemplates"] + ); + let agent = after["spec"]["podTemplate"]["spec"]["containers"] + .as_array() + .expect("workload containers") + .iter() + .find(|container| container["name"] == "agent") + .expect("agent container"); + assert_eq!(agent["image"], image); +} + +fn assert_identity_retained(before: &proto::Sandbox, after: &proto::Sandbox) { + assert_eq!( + after.metadata.as_ref().expect("metadata").id, + before.metadata.as_ref().expect("metadata").id + ); + assert_eq!(after.host_key_fingerprint, before.host_key_fingerprint); +} + +async fn assert_base_release(sandbox: &SandboxGuard, release: &str) { + assert!( + sandbox + .exec(&["cat", "/etc/alpine-release"]) + .await + .expect("base image release") + .trim() + .starts_with(release) + ); +} + +fn assert_update_completed(original: &proto::Sandbox, updated: &proto::Sandbox) { + assert_identity_retained(original, updated); + let status = updated.status.as_ref().expect("updated status"); + assert_eq!(status.phase, proto::SandboxPhase::Stopped as i32); + assert!( + status.image_update.is_none(), + "successful update must clear pending intent" + ); + assert_eq!( + updated + .spec + .as_ref() + .expect("spec") + .template + .as_ref() + .expect("template") + .image, + UPDATED_IMAGE + ); +} + +async fn assert_replay( + client: &mut AuthedGrpcClient, + update: proto::UpdateSandboxRequest, + updated: &proto::Sandbox, +) { + // Replay the exact old resource-version request. Sandbox replay returns its + // current state: ordinary watch observations may have advanced metadata and + // status since the original response, without applying the image again. + let replay = client + .update_sandbox(rpc(update)) + .await + .expect("request-ID replay"); + assert_eq!( + replay + .metadata() + .get("openshell-replayed") + .expect("replay metadata"), + "true" + ); + let replayed = replay.into_inner().sandbox.expect("replayed Sandbox"); + assert_update_completed(updated, &replayed); + assert_eq!(replayed.spec, updated.spec); + assert_eq!( + replayed + .status + .as_ref() + .expect("replayed status") + .image_revision, + updated + .status + .as_ref() + .expect("updated status") + .image_revision, + "replay must not admit another image operation" + ); + assert!( + replayed + .metadata + .as_ref() + .expect("replayed metadata") + .resource_version + >= updated + .metadata + .as_ref() + .expect("updated metadata") + .resource_version + ); +} + +#[tokio::test] +async fn image_update_retains_workspace_and_identity() { + let mut client = gateway_client().await; + // This test is Kubernetes-only: missing support is a regression, not a skip. + let info = client + .get_gateway_info(rpc(proto::GetGatewayInfoRequest {})) + .await + .expect("get gateway capabilities") + .into_inner(); + assert!(info.extensions.iter().any(|extension| { + extension + .supported_capabilities + .iter() + .any(|capability| capability == "openshell.compute.update-sandbox-image") + })); + + let mut sandbox = SandboxGuard::create(&["--from", ORIGINAL_IMAGE, "--no-auto-providers"]) + .await + .expect("create original Alpine sandbox"); + let original = get_sandbox(&mut client, &sandbox.name).await; + let id = &original.metadata.as_ref().expect("sandbox metadata").id; + assert!(!id.is_empty(), "sandbox must have a canonical ID"); + assert!( + original.host_key_fingerprint.starts_with("SHA256:"), + "sandbox must have a gateway-managed SSH identity" + ); + assert_base_release(&sandbox, "3.21.").await; + let sentinel = request_id(); + sandbox + .exec(&[ + "sh", + "-c", + &format!("printf '%s' '{sentinel}' > '{SENTINEL_PATH}'"), + ]) + .await + .expect("write workspace sentinel"); + let before = sandbox_resource(id).await; + let original_claims = claim_uids(&before).await; + + let running_update = proto::UpdateSandboxRequest { + workspace_scope: Some(proto::workspace_selector("default")), + name: sandbox.name.clone(), + image: UPDATED_IMAGE.to_owned(), + expected_resource_version: original + .metadata + .as_ref() + .expect("metadata") + .resource_version, + request_id: String::new(), + }; + let error = client + .update_sandbox(rpc(running_update.clone())) + .await + .expect_err("running update must be rejected"); + assert_eq!(error.code(), tonic::Code::FailedPrecondition); + assert_resource_retained(&before, &sandbox_resource(id).await, ORIGINAL_IMAGE); + + let (output, code) = run_cli(&["sandbox", "stop", &sandbox.name]).await; + assert_eq!(code, 0, "sandbox stop: {output}"); + wait_for_sandbox_phase(&sandbox.name, "Stopped", Duration::from_secs(120)) + .await + .expect("sandbox stopped"); + let stopped = get_sandbox(&mut client, &sandbox.name).await; + let update = proto::UpdateSandboxRequest { + expected_resource_version: stopped + .metadata + .as_ref() + .expect("metadata") + .resource_version, + request_id: request_id(), + ..running_update + }; + let updated = client + .update_sandbox(rpc(update.clone())) + .await + .expect("update stopped sandbox image") + .into_inner() + .sandbox + .expect("updated Sandbox"); + assert_update_completed(&original, &updated); + assert_resource_retained(&before, &sandbox_resource(id).await, UPDATED_IMAGE); + + assert_replay(&mut client, update, &updated).await; + + let (output, code) = run_cli(&["sandbox", "start", &sandbox.name]).await; + assert_eq!(code, 0, "sandbox start: {output}"); + wait_for_sandbox_phase(&sandbox.name, "Ready", Duration::from_secs(180)) + .await + .expect("updated sandbox ready"); + assert_base_release(&sandbox, "3.22.").await; + assert_eq!( + sandbox + .exec(&["cat", SENTINEL_PATH]) + .await + .expect("retained workspace sentinel") + .trim(), + sentinel + ); + let current = get_sandbox(&mut client, &sandbox.name).await; + assert_identity_retained(&original, ¤t); + let after = sandbox_resource(id).await; + assert_resource_retained(&before, &after, UPDATED_IMAGE); + assert_eq!( + claim_uids(&after).await, + original_claims, + "all mounted PVC names and UIDs must survive image replacement" + ); + sandbox.cleanup().await; +} diff --git a/examples/isolation-backend-v8/src/driver.rs b/examples/isolation-backend-v8/src/driver.rs index adce131a8f..6f70347cff 100644 --- a/examples/isolation-backend-v8/src/driver.rs +++ b/examples/isolation-backend-v8/src/driver.rs @@ -337,6 +337,15 @@ impl std::ops::Deref for DriverService { } #[tonic::async_trait] impl compute_driver_server::ComputeDriver for DriverService { + async fn update_sandbox_image( + &self, + _: Request, + ) -> Result, Status> { + Err(Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } + async fn get_capabilities( &self, _: Request, diff --git a/proto/compute_driver.proto b/proto/compute_driver.proto index 2eba7ef2af..a83ca1b019 100644 --- a/proto/compute_driver.proto +++ b/proto/compute_driver.proto @@ -45,6 +45,13 @@ service ComputeDriver { // Provision platform resources for a sandbox. rpc CreateSandbox(CreateSandboxRequest) returns (CreateSandboxResponse); + // Idempotently replace only the workload image of a stopped sandbox, retaining + // its stable resource and storage. Requires the optional capability + // openshell.compute.update-sandbox-image. Unsupported drivers return + // UNIMPLEMENTED without changing any resource. + rpc UpdateSandboxImage(UpdateSandboxImageRequest) + returns (UpdateSandboxImageResponse); + // Idempotently stop platform resources without deleting persistent state. rpc StopSandbox(StopSandboxRequest) returns (StopSandboxResponse); @@ -441,6 +448,27 @@ message CreateSandboxResponse { string runtime_identity = 1; } +message UpdateSandboxImageRequest { + string sandbox_id = 1; + string name = 2; + string image = 3; + // Pre-update image. A different current image conflicts unless durable driver + // evidence identifies this exact operation as already applied. + string expected_image = 4; + // Never adopt a same-name replacement resource. + string expected_runtime_identity = 5; + // Stable UUID across retries, recorded atomically with the image change. + string operation_id = 6; + // Perform all admission and state checks without writing any resource. The + // gateway uses this before recording durable intent; apply rechecks them. + bool validate_only = 7; + // Monotonic sandbox image revision. The driver atomically records it with + // the image and rejects earlier revisions even if expected_image matches. + uint64 revision = 8; +} + +message UpdateSandboxImageResponse {} + message StopSandboxRequest { // Stable sandbox ID stored by the gateway. string sandbox_id = 1; diff --git a/proto/openshell.proto b/proto/openshell.proto index 1be9dc7da8..71a0d66b69 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -53,6 +53,16 @@ service OpenShell { }; } + // Update only the workload image of a stopped sandbox without deleting its + // identity or retained storage. Requires compute-driver image-update support. + rpc UpdateSandbox(UpdateSandboxRequest) returns (SandboxResponse) { + option (openshell.options.v1.authorization) = { + auth_mode: "bearer" + scope: "sandbox:write" + workspace_role: "user" + }; + } + // Allocate a gateway-owned staging slot for a local rootfs tar archive. // // The gateway creates a request-scoped directory inside the compute driver's @@ -1242,6 +1252,20 @@ 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; + // Durable pending image change. Start is blocked until the same image update + // is retried successfully. Absence means no image update is pending. + SandboxImageUpdate image_update = 18; + // Monotonic gateway-owned image intent revision. Never reset by restart. + uint64 image_revision = 19; +} + +// Gateway-owned intent retained across interrupted driver operations. +message SandboxImageUpdate { + string operation_id = 1; + string previous_image = 2; + string image = 3; + // Fences delayed operations, including image changes that return to an old tag. + uint64 revision = 4; } // User-facing sandbox condition derived from platform or gateway observations. @@ -1330,6 +1354,22 @@ message CreateSandboxRequest { repeated SandboxServiceExposure service_exposures = 9; } +// Image-only update. Other create-time configuration is not mutable through +// this RPC. Stop before updating; start explicitly after a successful update. +message UpdateSandboxRequest { + // Workspace scope. Only a named workspace selection is accepted. + openshell.datamodel.v1.WorkspaceSelector workspace_scope = 1; + // Canonical name of the existing sandbox; this is not a rename or upsert. + string name = 2; + // Nonempty OCI workload image reference. This does not change trusted runtime + // images or reseed an existing workspace. + string image = 3; + // Required nonzero resource version read by the caller. + uint64 expected_resource_version = 4; + // Optional nonzero UUID for durable at-most-once admission. + string request_id = 5; +} + message CreateSandboxTemplateRequest { // Workspace scope. Only a named workspace selection is accepted. openshell.datamodel.v1.WorkspaceSelector workspace_scope = 2; diff --git a/sdk/go/openshell/v1/internal/converter/coverage_test.go b/sdk/go/openshell/v1/internal/converter/coverage_test.go index 785e12c9c6..8a457d0014 100644 --- a/sdk/go/openshell/v1/internal/converter/coverage_test.go +++ b/sdk/go/openshell/v1/internal/converter/coverage_test.go @@ -135,7 +135,9 @@ func TestConverterCoversAllProtoFields_SandboxStatus(t *testing.T) { // Provisioning carries gateway-owned attempt, deadline, and cleanup state; // the curated API exposes its outcome through phase and conditions. Detailed // lifecycle bookkeeping remains available through the raw protobuf API. - skipped := fieldSet{"main_process_instance_id": true, "configuration_activated": true, "provisioning": true} + // Image updates are raw-only; their pending reconciliation intent and + // monotonic image revision bookkeeping are not part of the curated status model. + skipped := fieldSet{"main_process_instance_id": true, "configuration_activated": true, "provisioning": true, "image_update": true, "image_revision": true} assertAllFieldsCovered(t, (&pb.SandboxStatus{}).ProtoReflect().Descriptor(), handled, skipped) } diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index d60dd50a68..2d8ee5ccd2 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -3253,8 +3253,13 @@ 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 + // Durable pending image change. Start is blocked until the same image update + // is retried successfully. Absence means no image update is pending. + ImageUpdate *SandboxImageUpdate `protobuf:"bytes,18,opt,name=image_update,json=imageUpdate,proto3" json:"image_update,omitempty"` + // Monotonic gateway-owned image intent revision. Never reset by restart. + ImageRevision uint64 `protobuf:"varint,19,opt,name=image_revision,json=imageRevision,proto3" json:"image_revision,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SandboxStatus) Reset() { @@ -3399,6 +3404,90 @@ func (x *SandboxStatus) GetLastTokenGrantFailure() *TokenGrantFailureObservation return nil } +func (x *SandboxStatus) GetImageUpdate() *SandboxImageUpdate { + if x != nil { + return x.ImageUpdate + } + return nil +} + +func (x *SandboxStatus) GetImageRevision() uint64 { + if x != nil { + return x.ImageRevision + } + return 0 +} + +// Gateway-owned intent retained across interrupted driver operations. +type SandboxImageUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + OperationId string `protobuf:"bytes,1,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` + PreviousImage string `protobuf:"bytes,2,opt,name=previous_image,json=previousImage,proto3" json:"previous_image,omitempty"` + Image string `protobuf:"bytes,3,opt,name=image,proto3" json:"image,omitempty"` + // Fences delayed operations, including image changes that return to an old tag. + Revision uint64 `protobuf:"varint,4,opt,name=revision,proto3" json:"revision,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxImageUpdate) Reset() { + *x = SandboxImageUpdate{} + mi := &file_openshell_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxImageUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxImageUpdate) ProtoMessage() {} + +func (x *SandboxImageUpdate) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[30] + 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 SandboxImageUpdate.ProtoReflect.Descriptor instead. +func (*SandboxImageUpdate) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{30} +} + +func (x *SandboxImageUpdate) GetOperationId() string { + if x != nil { + return x.OperationId + } + return "" +} + +func (x *SandboxImageUpdate) GetPreviousImage() string { + if x != nil { + return x.PreviousImage + } + return "" +} + +func (x *SandboxImageUpdate) GetImage() string { + if x != nil { + return x.Image + } + return "" +} + +func (x *SandboxImageUpdate) GetRevision() uint64 { + if x != nil { + return x.Revision + } + return 0 +} + // User-facing sandbox condition derived from platform or gateway observations. type SandboxCondition struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -3418,7 +3507,7 @@ type SandboxCondition struct { func (x *SandboxCondition) Reset() { *x = SandboxCondition{} - mi := &file_openshell_proto_msgTypes[30] + mi := &file_openshell_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3430,7 +3519,7 @@ func (x *SandboxCondition) String() string { func (*SandboxCondition) ProtoMessage() {} func (x *SandboxCondition) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[30] + mi := &file_openshell_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3443,7 +3532,7 @@ func (x *SandboxCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxCondition.ProtoReflect.Descriptor instead. func (*SandboxCondition) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{30} + return file_openshell_proto_rawDescGZIP(), []int{31} } func (x *SandboxCondition) GetType() string { @@ -3502,7 +3591,7 @@ type PlatformEvent struct { func (x *PlatformEvent) Reset() { *x = PlatformEvent{} - mi := &file_openshell_proto_msgTypes[31] + mi := &file_openshell_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3514,7 +3603,7 @@ func (x *PlatformEvent) String() string { func (*PlatformEvent) ProtoMessage() {} func (x *PlatformEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[31] + mi := &file_openshell_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3527,7 +3616,7 @@ func (x *PlatformEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use PlatformEvent.ProtoReflect.Descriptor instead. func (*PlatformEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{31} + return file_openshell_proto_rawDescGZIP(), []int{32} } func (x *PlatformEvent) GetEventTime() *timestamppb.Timestamp { @@ -3604,7 +3693,7 @@ type CreateSandboxRequest struct { func (x *CreateSandboxRequest) Reset() { *x = CreateSandboxRequest{} - mi := &file_openshell_proto_msgTypes[32] + mi := &file_openshell_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3616,7 +3705,7 @@ func (x *CreateSandboxRequest) String() string { func (*CreateSandboxRequest) ProtoMessage() {} func (x *CreateSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[32] + mi := &file_openshell_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3629,7 +3718,7 @@ func (x *CreateSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSandboxRequest.ProtoReflect.Descriptor instead. func (*CreateSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{32} + return file_openshell_proto_rawDescGZIP(), []int{33} } func (x *CreateSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3695,6 +3784,90 @@ func (x *CreateSandboxRequest) GetServiceExposures() []*SandboxServiceExposure { return nil } +// Image-only update. Other create-time configuration is not mutable through +// this RPC. Stop before updating; start explicitly after a successful update. +type UpdateSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Workspace scope. Only a named workspace selection is accepted. + WorkspaceScope *datamodelv1.WorkspaceSelector `protobuf:"bytes,1,opt,name=workspace_scope,json=workspaceScope,proto3" json:"workspace_scope,omitempty"` + // Canonical name of the existing sandbox; this is not a rename or upsert. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Nonempty OCI workload image reference. This does not change trusted runtime + // images or reseed an existing workspace. + Image string `protobuf:"bytes,3,opt,name=image,proto3" json:"image,omitempty"` + // Required nonzero resource version read by the caller. + ExpectedResourceVersion uint64 `protobuf:"varint,4,opt,name=expected_resource_version,json=expectedResourceVersion,proto3" json:"expected_resource_version,omitempty"` + // Optional nonzero UUID for durable at-most-once admission. + RequestId string `protobuf:"bytes,5,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateSandboxRequest) Reset() { + *x = UpdateSandboxRequest{} + mi := &file_openshell_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateSandboxRequest) ProtoMessage() {} + +func (x *UpdateSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[34] + 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 UpdateSandboxRequest.ProtoReflect.Descriptor instead. +func (*UpdateSandboxRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{34} +} + +func (x *UpdateSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { + if x != nil { + return x.WorkspaceScope + } + return nil +} + +func (x *UpdateSandboxRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdateSandboxRequest) GetImage() string { + if x != nil { + return x.Image + } + return "" +} + +func (x *UpdateSandboxRequest) GetExpectedResourceVersion() uint64 { + if x != nil { + return x.ExpectedResourceVersion + } + return 0 +} + +func (x *UpdateSandboxRequest) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + type CreateSandboxTemplateRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // Workspace scope. Only a named workspace selection is accepted. @@ -3709,7 +3882,7 @@ type CreateSandboxTemplateRequest struct { func (x *CreateSandboxTemplateRequest) Reset() { *x = CreateSandboxTemplateRequest{} - mi := &file_openshell_proto_msgTypes[33] + mi := &file_openshell_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3721,7 +3894,7 @@ func (x *CreateSandboxTemplateRequest) String() string { func (*CreateSandboxTemplateRequest) ProtoMessage() {} func (x *CreateSandboxTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[33] + mi := &file_openshell_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3734,7 +3907,7 @@ func (x *CreateSandboxTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSandboxTemplateRequest.ProtoReflect.Descriptor instead. func (*CreateSandboxTemplateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{33} + return file_openshell_proto_rawDescGZIP(), []int{35} } func (x *CreateSandboxTemplateRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3769,7 +3942,7 @@ type GetSandboxTemplateRequest struct { func (x *GetSandboxTemplateRequest) Reset() { *x = GetSandboxTemplateRequest{} - mi := &file_openshell_proto_msgTypes[34] + mi := &file_openshell_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3781,7 +3954,7 @@ func (x *GetSandboxTemplateRequest) String() string { func (*GetSandboxTemplateRequest) ProtoMessage() {} func (x *GetSandboxTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[34] + mi := &file_openshell_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3794,7 +3967,7 @@ func (x *GetSandboxTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxTemplateRequest.ProtoReflect.Descriptor instead. func (*GetSandboxTemplateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{34} + return file_openshell_proto_rawDescGZIP(), []int{36} } func (x *GetSandboxTemplateRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3829,7 +4002,7 @@ type ListSandboxTemplatesRequest struct { func (x *ListSandboxTemplatesRequest) Reset() { *x = ListSandboxTemplatesRequest{} - mi := &file_openshell_proto_msgTypes[35] + mi := &file_openshell_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3841,7 +4014,7 @@ func (x *ListSandboxTemplatesRequest) String() string { func (*ListSandboxTemplatesRequest) ProtoMessage() {} func (x *ListSandboxTemplatesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[35] + mi := &file_openshell_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3854,7 +4027,7 @@ func (x *ListSandboxTemplatesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxTemplatesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxTemplatesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{35} + return file_openshell_proto_rawDescGZIP(), []int{37} } func (x *ListSandboxTemplatesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3901,7 +4074,7 @@ type DeleteSandboxTemplateRequest struct { func (x *DeleteSandboxTemplateRequest) Reset() { *x = DeleteSandboxTemplateRequest{} - mi := &file_openshell_proto_msgTypes[36] + mi := &file_openshell_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3913,7 +4086,7 @@ func (x *DeleteSandboxTemplateRequest) String() string { func (*DeleteSandboxTemplateRequest) ProtoMessage() {} func (x *DeleteSandboxTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[36] + mi := &file_openshell_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3926,7 +4099,7 @@ func (x *DeleteSandboxTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxTemplateRequest.ProtoReflect.Descriptor instead. func (*DeleteSandboxTemplateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{36} + return file_openshell_proto_rawDescGZIP(), []int{38} } func (x *DeleteSandboxTemplateRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3966,7 +4139,7 @@ type SandboxTemplateResponse struct { func (x *SandboxTemplateResponse) Reset() { *x = SandboxTemplateResponse{} - mi := &file_openshell_proto_msgTypes[37] + mi := &file_openshell_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3978,7 +4151,7 @@ func (x *SandboxTemplateResponse) String() string { func (*SandboxTemplateResponse) ProtoMessage() {} func (x *SandboxTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[37] + mi := &file_openshell_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3991,7 +4164,7 @@ func (x *SandboxTemplateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxTemplateResponse.ProtoReflect.Descriptor instead. func (*SandboxTemplateResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{37} + return file_openshell_proto_rawDescGZIP(), []int{39} } func (x *SandboxTemplateResponse) GetTemplate() *SandboxWorkloadTemplate { @@ -4012,7 +4185,7 @@ type ListSandboxTemplatesResponse struct { func (x *ListSandboxTemplatesResponse) Reset() { *x = ListSandboxTemplatesResponse{} - mi := &file_openshell_proto_msgTypes[38] + mi := &file_openshell_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4024,7 +4197,7 @@ func (x *ListSandboxTemplatesResponse) String() string { func (*ListSandboxTemplatesResponse) ProtoMessage() {} func (x *ListSandboxTemplatesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[38] + mi := &file_openshell_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4037,7 +4210,7 @@ func (x *ListSandboxTemplatesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxTemplatesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxTemplatesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{38} + return file_openshell_proto_rawDescGZIP(), []int{40} } func (x *ListSandboxTemplatesResponse) GetTemplates() []*SandboxWorkloadTemplate { @@ -4063,7 +4236,7 @@ type DeleteSandboxTemplateResponse struct { func (x *DeleteSandboxTemplateResponse) Reset() { *x = DeleteSandboxTemplateResponse{} - mi := &file_openshell_proto_msgTypes[39] + mi := &file_openshell_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4075,7 +4248,7 @@ func (x *DeleteSandboxTemplateResponse) String() string { func (*DeleteSandboxTemplateResponse) ProtoMessage() {} func (x *DeleteSandboxTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[39] + mi := &file_openshell_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4088,7 +4261,7 @@ func (x *DeleteSandboxTemplateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxTemplateResponse.ProtoReflect.Descriptor instead. func (*DeleteSandboxTemplateResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{39} + return file_openshell_proto_rawDescGZIP(), []int{41} } func (x *DeleteSandboxTemplateResponse) GetOutcome() DeletionOutcome { @@ -4115,7 +4288,7 @@ type BeginRootfsTarStagingRequest struct { func (x *BeginRootfsTarStagingRequest) Reset() { *x = BeginRootfsTarStagingRequest{} - mi := &file_openshell_proto_msgTypes[40] + mi := &file_openshell_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4127,7 +4300,7 @@ func (x *BeginRootfsTarStagingRequest) String() string { func (*BeginRootfsTarStagingRequest) ProtoMessage() {} func (x *BeginRootfsTarStagingRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[40] + mi := &file_openshell_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4140,7 +4313,7 @@ func (x *BeginRootfsTarStagingRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BeginRootfsTarStagingRequest.ProtoReflect.Descriptor instead. func (*BeginRootfsTarStagingRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{40} + return file_openshell_proto_rawDescGZIP(), []int{42} } func (x *BeginRootfsTarStagingRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4183,7 +4356,7 @@ type BeginRootfsTarStagingResponse struct { func (x *BeginRootfsTarStagingResponse) Reset() { *x = BeginRootfsTarStagingResponse{} - mi := &file_openshell_proto_msgTypes[41] + mi := &file_openshell_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4195,7 +4368,7 @@ func (x *BeginRootfsTarStagingResponse) String() string { func (*BeginRootfsTarStagingResponse) ProtoMessage() {} func (x *BeginRootfsTarStagingResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[41] + mi := &file_openshell_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4208,7 +4381,7 @@ func (x *BeginRootfsTarStagingResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BeginRootfsTarStagingResponse.ProtoReflect.Descriptor instead. func (*BeginRootfsTarStagingResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{41} + return file_openshell_proto_rawDescGZIP(), []int{43} } func (x *BeginRootfsTarStagingResponse) GetStagingToken() string { @@ -4251,7 +4424,7 @@ type GetSandboxRequest struct { func (x *GetSandboxRequest) Reset() { *x = GetSandboxRequest{} - mi := &file_openshell_proto_msgTypes[42] + mi := &file_openshell_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4263,7 +4436,7 @@ func (x *GetSandboxRequest) String() string { func (*GetSandboxRequest) ProtoMessage() {} func (x *GetSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[42] + mi := &file_openshell_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4276,7 +4449,7 @@ func (x *GetSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxRequest.ProtoReflect.Descriptor instead. func (*GetSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{42} + return file_openshell_proto_rawDescGZIP(), []int{44} } func (x *GetSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4312,7 +4485,7 @@ type ListSandboxesRequest struct { func (x *ListSandboxesRequest) Reset() { *x = ListSandboxesRequest{} - mi := &file_openshell_proto_msgTypes[43] + mi := &file_openshell_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4324,7 +4497,7 @@ func (x *ListSandboxesRequest) String() string { func (*ListSandboxesRequest) ProtoMessage() {} func (x *ListSandboxesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[43] + mi := &file_openshell_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4337,7 +4510,7 @@ func (x *ListSandboxesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{43} + return file_openshell_proto_rawDescGZIP(), []int{45} } func (x *ListSandboxesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4386,7 +4559,7 @@ type ListSandboxProvidersRequest struct { func (x *ListSandboxProvidersRequest) Reset() { *x = ListSandboxProvidersRequest{} - mi := &file_openshell_proto_msgTypes[44] + mi := &file_openshell_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4398,7 +4571,7 @@ func (x *ListSandboxProvidersRequest) String() string { func (*ListSandboxProvidersRequest) ProtoMessage() {} func (x *ListSandboxProvidersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[44] + mi := &file_openshell_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4411,7 +4584,7 @@ func (x *ListSandboxProvidersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxProvidersRequest.ProtoReflect.Descriptor instead. func (*ListSandboxProvidersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{44} + return file_openshell_proto_rawDescGZIP(), []int{46} } func (x *ListSandboxProvidersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4464,7 +4637,7 @@ type AttachSandboxProviderRequest struct { func (x *AttachSandboxProviderRequest) Reset() { *x = AttachSandboxProviderRequest{} - mi := &file_openshell_proto_msgTypes[45] + mi := &file_openshell_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4476,7 +4649,7 @@ func (x *AttachSandboxProviderRequest) String() string { func (*AttachSandboxProviderRequest) ProtoMessage() {} func (x *AttachSandboxProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[45] + mi := &file_openshell_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4489,7 +4662,7 @@ func (x *AttachSandboxProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachSandboxProviderRequest.ProtoReflect.Descriptor instead. func (*AttachSandboxProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{45} + return file_openshell_proto_rawDescGZIP(), []int{47} } func (x *AttachSandboxProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4549,7 +4722,7 @@ type DetachSandboxProviderRequest struct { func (x *DetachSandboxProviderRequest) Reset() { *x = DetachSandboxProviderRequest{} - mi := &file_openshell_proto_msgTypes[46] + mi := &file_openshell_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4561,7 +4734,7 @@ func (x *DetachSandboxProviderRequest) String() string { func (*DetachSandboxProviderRequest) ProtoMessage() {} func (x *DetachSandboxProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[46] + mi := &file_openshell_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4574,7 +4747,7 @@ func (x *DetachSandboxProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachSandboxProviderRequest.ProtoReflect.Descriptor instead. func (*DetachSandboxProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{46} + return file_openshell_proto_rawDescGZIP(), []int{48} } func (x *DetachSandboxProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4631,7 +4804,7 @@ type DeleteSandboxRequest struct { func (x *DeleteSandboxRequest) Reset() { *x = DeleteSandboxRequest{} - mi := &file_openshell_proto_msgTypes[47] + mi := &file_openshell_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4643,7 +4816,7 @@ func (x *DeleteSandboxRequest) String() string { func (*DeleteSandboxRequest) ProtoMessage() {} func (x *DeleteSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[47] + mi := &file_openshell_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4656,7 +4829,7 @@ func (x *DeleteSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxRequest.ProtoReflect.Descriptor instead. func (*DeleteSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{47} + return file_openshell_proto_rawDescGZIP(), []int{49} } func (x *DeleteSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4702,7 +4875,7 @@ type StopSandboxRequest struct { func (x *StopSandboxRequest) Reset() { *x = StopSandboxRequest{} - mi := &file_openshell_proto_msgTypes[48] + mi := &file_openshell_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4714,7 +4887,7 @@ func (x *StopSandboxRequest) String() string { func (*StopSandboxRequest) ProtoMessage() {} func (x *StopSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[48] + mi := &file_openshell_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4727,7 +4900,7 @@ func (x *StopSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StopSandboxRequest.ProtoReflect.Descriptor instead. func (*StopSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{48} + return file_openshell_proto_rawDescGZIP(), []int{50} } func (x *StopSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4766,7 +4939,7 @@ type StartSandboxRequest struct { func (x *StartSandboxRequest) Reset() { *x = StartSandboxRequest{} - mi := &file_openshell_proto_msgTypes[49] + mi := &file_openshell_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4778,7 +4951,7 @@ func (x *StartSandboxRequest) String() string { func (*StartSandboxRequest) ProtoMessage() {} func (x *StartSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[49] + mi := &file_openshell_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4791,7 +4964,7 @@ func (x *StartSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartSandboxRequest.ProtoReflect.Descriptor instead. func (*StartSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{49} + return file_openshell_proto_rawDescGZIP(), []int{51} } func (x *StartSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4827,7 +5000,7 @@ type SuspendSandboxRequest struct { func (x *SuspendSandboxRequest) Reset() { *x = SuspendSandboxRequest{} - mi := &file_openshell_proto_msgTypes[50] + mi := &file_openshell_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4839,7 +5012,7 @@ func (x *SuspendSandboxRequest) String() string { func (*SuspendSandboxRequest) ProtoMessage() {} func (x *SuspendSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[50] + mi := &file_openshell_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4852,7 +5025,7 @@ func (x *SuspendSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendSandboxRequest.ProtoReflect.Descriptor instead. func (*SuspendSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{50} + return file_openshell_proto_rawDescGZIP(), []int{52} } func (x *SuspendSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4884,7 +5057,7 @@ type ResumeSandboxRequest struct { func (x *ResumeSandboxRequest) Reset() { *x = ResumeSandboxRequest{} - mi := &file_openshell_proto_msgTypes[51] + mi := &file_openshell_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4896,7 +5069,7 @@ func (x *ResumeSandboxRequest) String() string { func (*ResumeSandboxRequest) ProtoMessage() {} func (x *ResumeSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[51] + mi := &file_openshell_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4909,7 +5082,7 @@ func (x *ResumeSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeSandboxRequest.ProtoReflect.Descriptor instead. func (*ResumeSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{51} + return file_openshell_proto_rawDescGZIP(), []int{53} } func (x *ResumeSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4946,7 +5119,7 @@ type SandboxResponse struct { func (x *SandboxResponse) Reset() { *x = SandboxResponse{} - mi := &file_openshell_proto_msgTypes[52] + mi := &file_openshell_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4958,7 +5131,7 @@ func (x *SandboxResponse) String() string { func (*SandboxResponse) ProtoMessage() {} func (x *SandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[52] + mi := &file_openshell_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4971,7 +5144,7 @@ func (x *SandboxResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxResponse.ProtoReflect.Descriptor instead. func (*SandboxResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{52} + return file_openshell_proto_rawDescGZIP(), []int{54} } func (x *SandboxResponse) GetSandbox() *Sandbox { @@ -5000,7 +5173,7 @@ type ListSandboxesResponse struct { func (x *ListSandboxesResponse) Reset() { *x = ListSandboxesResponse{} - mi := &file_openshell_proto_msgTypes[53] + mi := &file_openshell_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5012,7 +5185,7 @@ func (x *ListSandboxesResponse) String() string { func (*ListSandboxesResponse) ProtoMessage() {} func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[53] + mi := &file_openshell_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5025,7 +5198,7 @@ func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{53} + return file_openshell_proto_rawDescGZIP(), []int{55} } func (x *ListSandboxesResponse) GetSandboxes() []*Sandbox { @@ -5054,7 +5227,7 @@ type ListSandboxProvidersResponse struct { func (x *ListSandboxProvidersResponse) Reset() { *x = ListSandboxProvidersResponse{} - mi := &file_openshell_proto_msgTypes[54] + mi := &file_openshell_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5066,7 +5239,7 @@ func (x *ListSandboxProvidersResponse) String() string { func (*ListSandboxProvidersResponse) ProtoMessage() {} func (x *ListSandboxProvidersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[54] + mi := &file_openshell_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5079,7 +5252,7 @@ func (x *ListSandboxProvidersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxProvidersResponse.ProtoReflect.Descriptor instead. func (*ListSandboxProvidersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{54} + return file_openshell_proto_rawDescGZIP(), []int{56} } func (x *ListSandboxProvidersResponse) GetProviders() []*datamodelv1.Provider { @@ -5110,7 +5283,7 @@ type AttachSandboxProviderResponse struct { func (x *AttachSandboxProviderResponse) Reset() { *x = AttachSandboxProviderResponse{} - mi := &file_openshell_proto_msgTypes[55] + mi := &file_openshell_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5122,7 +5295,7 @@ func (x *AttachSandboxProviderResponse) String() string { func (*AttachSandboxProviderResponse) ProtoMessage() {} func (x *AttachSandboxProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[55] + mi := &file_openshell_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5135,7 +5308,7 @@ func (x *AttachSandboxProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachSandboxProviderResponse.ProtoReflect.Descriptor instead. func (*AttachSandboxProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{55} + return file_openshell_proto_rawDescGZIP(), []int{57} } func (x *AttachSandboxProviderResponse) GetSandbox() *Sandbox { @@ -5173,7 +5346,7 @@ type DetachSandboxProviderResponse struct { func (x *DetachSandboxProviderResponse) Reset() { *x = DetachSandboxProviderResponse{} - mi := &file_openshell_proto_msgTypes[56] + mi := &file_openshell_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5185,7 +5358,7 @@ func (x *DetachSandboxProviderResponse) String() string { func (*DetachSandboxProviderResponse) ProtoMessage() {} func (x *DetachSandboxProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[56] + mi := &file_openshell_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5198,7 +5371,7 @@ func (x *DetachSandboxProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachSandboxProviderResponse.ProtoReflect.Descriptor instead. func (*DetachSandboxProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{56} + return file_openshell_proto_rawDescGZIP(), []int{58} } func (x *DetachSandboxProviderResponse) GetSandbox() *Sandbox { @@ -5240,7 +5413,7 @@ type ProviderDesiredIdentity struct { func (x *ProviderDesiredIdentity) Reset() { *x = ProviderDesiredIdentity{} - mi := &file_openshell_proto_msgTypes[57] + mi := &file_openshell_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5252,7 +5425,7 @@ func (x *ProviderDesiredIdentity) String() string { func (*ProviderDesiredIdentity) ProtoMessage() {} func (x *ProviderDesiredIdentity) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[57] + mi := &file_openshell_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5265,7 +5438,7 @@ func (x *ProviderDesiredIdentity) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderDesiredIdentity.ProtoReflect.Descriptor instead. func (*ProviderDesiredIdentity) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{57} + return file_openshell_proto_rawDescGZIP(), []int{59} } func (x *ProviderDesiredIdentity) GetSandboxId() string { @@ -5340,7 +5513,7 @@ type ConfigSnapshotRevision struct { func (x *ConfigSnapshotRevision) Reset() { *x = ConfigSnapshotRevision{} - mi := &file_openshell_proto_msgTypes[58] + mi := &file_openshell_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5352,7 +5525,7 @@ func (x *ConfigSnapshotRevision) String() string { func (*ConfigSnapshotRevision) ProtoMessage() {} func (x *ConfigSnapshotRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[58] + mi := &file_openshell_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5365,7 +5538,7 @@ func (x *ConfigSnapshotRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigSnapshotRevision.ProtoReflect.Descriptor instead. func (*ConfigSnapshotRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{58} + return file_openshell_proto_rawDescGZIP(), []int{60} } func (x *ConfigSnapshotRevision) GetComponent() isConfigSnapshotRevision_Component { @@ -5442,7 +5615,7 @@ type SandboxConfigRevision struct { func (x *SandboxConfigRevision) Reset() { *x = SandboxConfigRevision{} - mi := &file_openshell_proto_msgTypes[59] + mi := &file_openshell_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5454,7 +5627,7 @@ func (x *SandboxConfigRevision) String() string { func (*SandboxConfigRevision) ProtoMessage() {} func (x *SandboxConfigRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[59] + mi := &file_openshell_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5467,7 +5640,7 @@ func (x *SandboxConfigRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfigRevision.ProtoReflect.Descriptor instead. func (*SandboxConfigRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{59} + return file_openshell_proto_rawDescGZIP(), []int{61} } func (x *SandboxConfigRevision) GetConfigRevision() uint64 { @@ -5526,7 +5699,7 @@ type ConfigUpdateOperation struct { func (x *ConfigUpdateOperation) Reset() { *x = ConfigUpdateOperation{} - mi := &file_openshell_proto_msgTypes[60] + mi := &file_openshell_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5538,7 +5711,7 @@ func (x *ConfigUpdateOperation) String() string { func (*ConfigUpdateOperation) ProtoMessage() {} func (x *ConfigUpdateOperation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[60] + mi := &file_openshell_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5551,7 +5724,7 @@ func (x *ConfigUpdateOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdateOperation.ProtoReflect.Descriptor instead. func (*ConfigUpdateOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{60} + return file_openshell_proto_rawDescGZIP(), []int{62} } func (x *ConfigUpdateOperation) GetOperationId() string { @@ -5641,7 +5814,7 @@ type ProviderMutationReceipt struct { func (x *ProviderMutationReceipt) Reset() { *x = ProviderMutationReceipt{} - mi := &file_openshell_proto_msgTypes[61] + mi := &file_openshell_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5653,7 +5826,7 @@ func (x *ProviderMutationReceipt) String() string { func (*ProviderMutationReceipt) ProtoMessage() {} func (x *ProviderMutationReceipt) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[61] + mi := &file_openshell_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5666,7 +5839,7 @@ func (x *ProviderMutationReceipt) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderMutationReceipt.ProtoReflect.Descriptor instead. func (*ProviderMutationReceipt) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{61} + return file_openshell_proto_rawDescGZIP(), []int{63} } func (x *ProviderMutationReceipt) GetReceiptId() string { @@ -5742,7 +5915,7 @@ type ProviderReadinessObservation struct { func (x *ProviderReadinessObservation) Reset() { *x = ProviderReadinessObservation{} - mi := &file_openshell_proto_msgTypes[62] + mi := &file_openshell_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5754,7 +5927,7 @@ func (x *ProviderReadinessObservation) String() string { func (*ProviderReadinessObservation) ProtoMessage() {} func (x *ProviderReadinessObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[62] + mi := &file_openshell_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5767,7 +5940,7 @@ func (x *ProviderReadinessObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderReadinessObservation.ProtoReflect.Descriptor instead. func (*ProviderReadinessObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{62} + return file_openshell_proto_rawDescGZIP(), []int{64} } func (x *ProviderReadinessObservation) GetSessionId() string { @@ -5866,7 +6039,7 @@ type ProviderReadinessStatus struct { func (x *ProviderReadinessStatus) Reset() { *x = ProviderReadinessStatus{} - mi := &file_openshell_proto_msgTypes[63] + mi := &file_openshell_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5878,7 +6051,7 @@ func (x *ProviderReadinessStatus) String() string { func (*ProviderReadinessStatus) ProtoMessage() {} func (x *ProviderReadinessStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[63] + mi := &file_openshell_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5891,7 +6064,7 @@ func (x *ProviderReadinessStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderReadinessStatus.ProtoReflect.Descriptor instead. func (*ProviderReadinessStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{63} + return file_openshell_proto_rawDescGZIP(), []int{65} } func (x *ProviderReadinessStatus) GetReceipt() *ProviderMutationReceipt { @@ -5965,7 +6138,7 @@ type GetSandboxProviderStatusRequest struct { func (x *GetSandboxProviderStatusRequest) Reset() { *x = GetSandboxProviderStatusRequest{} - mi := &file_openshell_proto_msgTypes[64] + mi := &file_openshell_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5977,7 +6150,7 @@ func (x *GetSandboxProviderStatusRequest) String() string { func (*GetSandboxProviderStatusRequest) ProtoMessage() {} func (x *GetSandboxProviderStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[64] + mi := &file_openshell_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5990,7 +6163,7 @@ func (x *GetSandboxProviderStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxProviderStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxProviderStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{64} + return file_openshell_proto_rawDescGZIP(), []int{66} } func (x *GetSandboxProviderStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6030,7 +6203,7 @@ type GetSandboxProviderStatusResponse struct { func (x *GetSandboxProviderStatusResponse) Reset() { *x = GetSandboxProviderStatusResponse{} - mi := &file_openshell_proto_msgTypes[65] + mi := &file_openshell_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6042,7 +6215,7 @@ func (x *GetSandboxProviderStatusResponse) String() string { func (*GetSandboxProviderStatusResponse) ProtoMessage() {} func (x *GetSandboxProviderStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[65] + mi := &file_openshell_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6055,7 +6228,7 @@ func (x *GetSandboxProviderStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxProviderStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxProviderStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{65} + return file_openshell_proto_rawDescGZIP(), []int{67} } func (x *GetSandboxProviderStatusResponse) GetStatus() *ProviderReadinessStatus { @@ -6077,7 +6250,7 @@ type ReportProviderReadinessRequest struct { func (x *ReportProviderReadinessRequest) Reset() { *x = ReportProviderReadinessRequest{} - mi := &file_openshell_proto_msgTypes[66] + mi := &file_openshell_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6089,7 +6262,7 @@ func (x *ReportProviderReadinessRequest) String() string { func (*ReportProviderReadinessRequest) ProtoMessage() {} func (x *ReportProviderReadinessRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[66] + mi := &file_openshell_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6102,7 +6275,7 @@ func (x *ReportProviderReadinessRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportProviderReadinessRequest.ProtoReflect.Descriptor instead. func (*ReportProviderReadinessRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{66} + return file_openshell_proto_rawDescGZIP(), []int{68} } func (x *ReportProviderReadinessRequest) GetSandboxId() string { @@ -6132,7 +6305,7 @@ type ReportProviderReadinessResponse struct { func (x *ReportProviderReadinessResponse) Reset() { *x = ReportProviderReadinessResponse{} - mi := &file_openshell_proto_msgTypes[67] + mi := &file_openshell_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6144,7 +6317,7 @@ func (x *ReportProviderReadinessResponse) String() string { func (*ReportProviderReadinessResponse) ProtoMessage() {} func (x *ReportProviderReadinessResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[67] + mi := &file_openshell_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6157,7 +6330,7 @@ func (x *ReportProviderReadinessResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportProviderReadinessResponse.ProtoReflect.Descriptor instead. func (*ReportProviderReadinessResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{67} + return file_openshell_proto_rawDescGZIP(), []int{69} } func (x *ReportProviderReadinessResponse) GetAcceptedSequence() uint64 { @@ -6194,7 +6367,7 @@ type DeleteSandboxResponse struct { func (x *DeleteSandboxResponse) Reset() { *x = DeleteSandboxResponse{} - mi := &file_openshell_proto_msgTypes[68] + mi := &file_openshell_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6206,7 +6379,7 @@ func (x *DeleteSandboxResponse) String() string { func (*DeleteSandboxResponse) ProtoMessage() {} func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[68] + mi := &file_openshell_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6219,7 +6392,7 @@ func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxResponse.ProtoReflect.Descriptor instead. func (*DeleteSandboxResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{68} + return file_openshell_proto_rawDescGZIP(), []int{70} } func (x *DeleteSandboxResponse) GetOutcome() DeletionOutcome { @@ -6248,7 +6421,7 @@ type CreateSshSessionRequest struct { func (x *CreateSshSessionRequest) Reset() { *x = CreateSshSessionRequest{} - mi := &file_openshell_proto_msgTypes[69] + mi := &file_openshell_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6260,7 +6433,7 @@ func (x *CreateSshSessionRequest) String() string { func (*CreateSshSessionRequest) ProtoMessage() {} func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[69] + mi := &file_openshell_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6273,7 +6446,7 @@ func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSshSessionRequest.ProtoReflect.Descriptor instead. func (*CreateSshSessionRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{69} + return file_openshell_proto_rawDescGZIP(), []int{71} } func (x *CreateSshSessionRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6324,7 +6497,7 @@ type CreateSshSessionResponse struct { func (x *CreateSshSessionResponse) Reset() { *x = CreateSshSessionResponse{} - mi := &file_openshell_proto_msgTypes[70] + mi := &file_openshell_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6336,7 +6509,7 @@ func (x *CreateSshSessionResponse) String() string { func (*CreateSshSessionResponse) ProtoMessage() {} func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[70] + mi := &file_openshell_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6349,7 +6522,7 @@ func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSshSessionResponse.ProtoReflect.Descriptor instead. func (*CreateSshSessionResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{70} + return file_openshell_proto_rawDescGZIP(), []int{72} } func (x *CreateSshSessionResponse) GetSandboxId() string { @@ -6424,7 +6597,7 @@ type ExposeServiceRequest struct { func (x *ExposeServiceRequest) Reset() { *x = ExposeServiceRequest{} - mi := &file_openshell_proto_msgTypes[71] + mi := &file_openshell_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6436,7 +6609,7 @@ func (x *ExposeServiceRequest) String() string { func (*ExposeServiceRequest) ProtoMessage() {} func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[71] + mi := &file_openshell_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6449,7 +6622,7 @@ func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExposeServiceRequest.ProtoReflect.Descriptor instead. func (*ExposeServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{71} + return file_openshell_proto_rawDescGZIP(), []int{73} } func (x *ExposeServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6515,7 +6688,7 @@ type GetServiceRequest struct { func (x *GetServiceRequest) Reset() { *x = GetServiceRequest{} - mi := &file_openshell_proto_msgTypes[72] + mi := &file_openshell_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6527,7 +6700,7 @@ func (x *GetServiceRequest) String() string { func (*GetServiceRequest) ProtoMessage() {} func (x *GetServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[72] + mi := &file_openshell_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6540,7 +6713,7 @@ func (x *GetServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetServiceRequest.ProtoReflect.Descriptor instead. func (*GetServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{72} + return file_openshell_proto_rawDescGZIP(), []int{74} } func (x *GetServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6583,7 +6756,7 @@ type ListServicesRequest struct { func (x *ListServicesRequest) Reset() { *x = ListServicesRequest{} - mi := &file_openshell_proto_msgTypes[73] + mi := &file_openshell_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6595,7 +6768,7 @@ func (x *ListServicesRequest) String() string { func (*ListServicesRequest) ProtoMessage() {} func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[73] + mi := &file_openshell_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6608,7 +6781,7 @@ func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesRequest.ProtoReflect.Descriptor instead. func (*ListServicesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{73} + return file_openshell_proto_rawDescGZIP(), []int{75} } func (x *ListServicesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6651,7 +6824,7 @@ type ListServicesResponse struct { func (x *ListServicesResponse) Reset() { *x = ListServicesResponse{} - mi := &file_openshell_proto_msgTypes[74] + mi := &file_openshell_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6663,7 +6836,7 @@ func (x *ListServicesResponse) String() string { func (*ListServicesResponse) ProtoMessage() {} func (x *ListServicesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[74] + mi := &file_openshell_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6676,7 +6849,7 @@ func (x *ListServicesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesResponse.ProtoReflect.Descriptor instead. func (*ListServicesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{74} + return file_openshell_proto_rawDescGZIP(), []int{76} } func (x *ListServicesResponse) GetServices() []*ServiceEndpointResponse { @@ -6711,7 +6884,7 @@ type DeleteServiceRequest struct { func (x *DeleteServiceRequest) Reset() { *x = DeleteServiceRequest{} - mi := &file_openshell_proto_msgTypes[75] + mi := &file_openshell_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6723,7 +6896,7 @@ func (x *DeleteServiceRequest) String() string { func (*DeleteServiceRequest) ProtoMessage() {} func (x *DeleteServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[75] + mi := &file_openshell_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6736,7 +6909,7 @@ func (x *DeleteServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteServiceRequest.ProtoReflect.Descriptor instead. func (*DeleteServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{75} + return file_openshell_proto_rawDescGZIP(), []int{77} } func (x *DeleteServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6784,7 +6957,7 @@ type DeleteServiceResponse struct { func (x *DeleteServiceResponse) Reset() { *x = DeleteServiceResponse{} - mi := &file_openshell_proto_msgTypes[76] + mi := &file_openshell_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6796,7 +6969,7 @@ func (x *DeleteServiceResponse) String() string { func (*DeleteServiceResponse) ProtoMessage() {} func (x *DeleteServiceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[76] + mi := &file_openshell_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6809,7 +6982,7 @@ func (x *DeleteServiceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteServiceResponse.ProtoReflect.Descriptor instead. func (*DeleteServiceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{76} + return file_openshell_proto_rawDescGZIP(), []int{78} } func (x *DeleteServiceResponse) GetOutcome() DeletionOutcome { @@ -6842,7 +7015,7 @@ type ServiceEndpoint struct { func (x *ServiceEndpoint) Reset() { *x = ServiceEndpoint{} - mi := &file_openshell_proto_msgTypes[77] + mi := &file_openshell_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6854,7 +7027,7 @@ func (x *ServiceEndpoint) String() string { func (*ServiceEndpoint) ProtoMessage() {} func (x *ServiceEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[77] + mi := &file_openshell_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6867,7 +7040,7 @@ func (x *ServiceEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceEndpoint.ProtoReflect.Descriptor instead. func (*ServiceEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{77} + return file_openshell_proto_rawDescGZIP(), []int{79} } func (x *ServiceEndpoint) GetMetadata() *datamodelv1.ObjectMeta { @@ -6930,7 +7103,7 @@ type ServiceEndpointResponse struct { func (x *ServiceEndpointResponse) Reset() { *x = ServiceEndpointResponse{} - mi := &file_openshell_proto_msgTypes[78] + mi := &file_openshell_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6942,7 +7115,7 @@ func (x *ServiceEndpointResponse) String() string { func (*ServiceEndpointResponse) ProtoMessage() {} func (x *ServiceEndpointResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[78] + mi := &file_openshell_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6955,7 +7128,7 @@ func (x *ServiceEndpointResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceEndpointResponse.ProtoReflect.Descriptor instead. func (*ServiceEndpointResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{78} + return file_openshell_proto_rawDescGZIP(), []int{80} } func (x *ServiceEndpointResponse) GetEndpoint() *ServiceEndpoint { @@ -6986,7 +7159,7 @@ type RevokeSshSessionRequest struct { func (x *RevokeSshSessionRequest) Reset() { *x = RevokeSshSessionRequest{} - mi := &file_openshell_proto_msgTypes[79] + mi := &file_openshell_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6998,7 +7171,7 @@ func (x *RevokeSshSessionRequest) String() string { func (*RevokeSshSessionRequest) ProtoMessage() {} func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[79] + mi := &file_openshell_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7011,7 +7184,7 @@ func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RevokeSshSessionRequest.ProtoReflect.Descriptor instead. func (*RevokeSshSessionRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{79} + return file_openshell_proto_rawDescGZIP(), []int{81} } func (x *RevokeSshSessionRequest) GetToken() string { @@ -7038,7 +7211,7 @@ type RevokeSshSessionResponse struct { func (x *RevokeSshSessionResponse) Reset() { *x = RevokeSshSessionResponse{} - mi := &file_openshell_proto_msgTypes[80] + mi := &file_openshell_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7050,7 +7223,7 @@ func (x *RevokeSshSessionResponse) String() string { func (*RevokeSshSessionResponse) ProtoMessage() {} func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[80] + mi := &file_openshell_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7063,7 +7236,7 @@ func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RevokeSshSessionResponse.ProtoReflect.Descriptor instead. func (*RevokeSshSessionResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{80} + return file_openshell_proto_rawDescGZIP(), []int{82} } func (x *RevokeSshSessionResponse) GetOutcome() DeletionOutcome { @@ -7113,7 +7286,7 @@ type ExecSandboxRequest struct { func (x *ExecSandboxRequest) Reset() { *x = ExecSandboxRequest{} - mi := &file_openshell_proto_msgTypes[81] + mi := &file_openshell_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7125,7 +7298,7 @@ func (x *ExecSandboxRequest) String() string { func (*ExecSandboxRequest) ProtoMessage() {} func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[81] + mi := &file_openshell_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7138,7 +7311,7 @@ func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxRequest.ProtoReflect.Descriptor instead. func (*ExecSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{81} + return file_openshell_proto_rawDescGZIP(), []int{83} } func (x *ExecSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -7235,7 +7408,7 @@ type ExecSandboxStdout struct { func (x *ExecSandboxStdout) Reset() { *x = ExecSandboxStdout{} - mi := &file_openshell_proto_msgTypes[82] + mi := &file_openshell_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7247,7 +7420,7 @@ func (x *ExecSandboxStdout) String() string { func (*ExecSandboxStdout) ProtoMessage() {} func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[82] + mi := &file_openshell_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7260,7 +7433,7 @@ func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxStdout.ProtoReflect.Descriptor instead. func (*ExecSandboxStdout) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{82} + return file_openshell_proto_rawDescGZIP(), []int{84} } func (x *ExecSandboxStdout) GetData() []byte { @@ -7280,7 +7453,7 @@ type ExecSandboxStderr struct { func (x *ExecSandboxStderr) Reset() { *x = ExecSandboxStderr{} - mi := &file_openshell_proto_msgTypes[83] + mi := &file_openshell_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7292,7 +7465,7 @@ func (x *ExecSandboxStderr) String() string { func (*ExecSandboxStderr) ProtoMessage() {} func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[83] + mi := &file_openshell_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7305,7 +7478,7 @@ func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxStderr.ProtoReflect.Descriptor instead. func (*ExecSandboxStderr) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{83} + return file_openshell_proto_rawDescGZIP(), []int{85} } func (x *ExecSandboxStderr) GetData() []byte { @@ -7325,7 +7498,7 @@ type ExecSandboxExit struct { func (x *ExecSandboxExit) Reset() { *x = ExecSandboxExit{} - mi := &file_openshell_proto_msgTypes[84] + mi := &file_openshell_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7337,7 +7510,7 @@ func (x *ExecSandboxExit) String() string { func (*ExecSandboxExit) ProtoMessage() {} func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[84] + mi := &file_openshell_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7350,7 +7523,7 @@ func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxExit.ProtoReflect.Descriptor instead. func (*ExecSandboxExit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{84} + return file_openshell_proto_rawDescGZIP(), []int{86} } func (x *ExecSandboxExit) GetExitCode() int32 { @@ -7375,7 +7548,7 @@ type ExecSandboxEvent struct { func (x *ExecSandboxEvent) Reset() { *x = ExecSandboxEvent{} - mi := &file_openshell_proto_msgTypes[85] + mi := &file_openshell_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7387,7 +7560,7 @@ func (x *ExecSandboxEvent) String() string { func (*ExecSandboxEvent) ProtoMessage() {} func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[85] + mi := &file_openshell_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7400,7 +7573,7 @@ func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxEvent.ProtoReflect.Descriptor instead. func (*ExecSandboxEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{85} + return file_openshell_proto_rawDescGZIP(), []int{87} } func (x *ExecSandboxEvent) GetPayload() isExecSandboxEvent_Payload { @@ -7482,7 +7655,7 @@ type TcpForwardInit struct { func (x *TcpForwardInit) Reset() { *x = TcpForwardInit{} - mi := &file_openshell_proto_msgTypes[86] + mi := &file_openshell_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7494,7 +7667,7 @@ func (x *TcpForwardInit) String() string { func (*TcpForwardInit) ProtoMessage() {} func (x *TcpForwardInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[86] + mi := &file_openshell_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7507,7 +7680,7 @@ func (x *TcpForwardInit) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpForwardInit.ProtoReflect.Descriptor instead. func (*TcpForwardInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{86} + return file_openshell_proto_rawDescGZIP(), []int{88} } func (x *TcpForwardInit) GetSandbox() string { @@ -7593,7 +7766,7 @@ type TcpForwardFrame struct { func (x *TcpForwardFrame) Reset() { *x = TcpForwardFrame{} - mi := &file_openshell_proto_msgTypes[87] + mi := &file_openshell_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7605,7 +7778,7 @@ func (x *TcpForwardFrame) String() string { func (*TcpForwardFrame) ProtoMessage() {} func (x *TcpForwardFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[87] + mi := &file_openshell_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7618,7 +7791,7 @@ func (x *TcpForwardFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpForwardFrame.ProtoReflect.Descriptor instead. func (*TcpForwardFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{87} + return file_openshell_proto_rawDescGZIP(), []int{89} } func (x *TcpForwardFrame) GetPayload() isTcpForwardFrame_Payload { @@ -7677,7 +7850,7 @@ type ExecSandboxInput struct { func (x *ExecSandboxInput) Reset() { *x = ExecSandboxInput{} - mi := &file_openshell_proto_msgTypes[88] + mi := &file_openshell_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7689,7 +7862,7 @@ func (x *ExecSandboxInput) String() string { func (*ExecSandboxInput) ProtoMessage() {} func (x *ExecSandboxInput) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[88] + mi := &file_openshell_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7702,7 +7875,7 @@ func (x *ExecSandboxInput) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxInput.ProtoReflect.Descriptor instead. func (*ExecSandboxInput) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{88} + return file_openshell_proto_rawDescGZIP(), []int{90} } func (x *ExecSandboxInput) GetPayload() isExecSandboxInput_Payload { @@ -7775,7 +7948,7 @@ type ExecSandboxWindowResize struct { func (x *ExecSandboxWindowResize) Reset() { *x = ExecSandboxWindowResize{} - mi := &file_openshell_proto_msgTypes[89] + mi := &file_openshell_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7787,7 +7960,7 @@ func (x *ExecSandboxWindowResize) String() string { func (*ExecSandboxWindowResize) ProtoMessage() {} func (x *ExecSandboxWindowResize) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[89] + mi := &file_openshell_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7800,7 +7973,7 @@ func (x *ExecSandboxWindowResize) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxWindowResize.ProtoReflect.Descriptor instead. func (*ExecSandboxWindowResize) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{89} + return file_openshell_proto_rawDescGZIP(), []int{91} } func (x *ExecSandboxWindowResize) GetCols() uint32 { @@ -7836,7 +8009,7 @@ type SshSession struct { func (x *SshSession) Reset() { *x = SshSession{} - mi := &file_openshell_proto_msgTypes[90] + mi := &file_openshell_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7848,7 +8021,7 @@ func (x *SshSession) String() string { func (*SshSession) ProtoMessage() {} func (x *SshSession) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[90] + mi := &file_openshell_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7861,7 +8034,7 @@ func (x *SshSession) ProtoReflect() protoreflect.Message { // Deprecated: Use SshSession.ProtoReflect.Descriptor instead. func (*SshSession) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{90} + return file_openshell_proto_rawDescGZIP(), []int{92} } func (x *SshSession) GetMetadata() *datamodelv1.ObjectMeta { @@ -7950,7 +8123,7 @@ type WatchSandboxRequest struct { func (x *WatchSandboxRequest) Reset() { *x = WatchSandboxRequest{} - mi := &file_openshell_proto_msgTypes[91] + mi := &file_openshell_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7962,7 +8135,7 @@ func (x *WatchSandboxRequest) String() string { func (*WatchSandboxRequest) ProtoMessage() {} func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[91] + mi := &file_openshell_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7975,7 +8148,7 @@ func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchSandboxRequest.ProtoReflect.Descriptor instead. func (*WatchSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{91} + return file_openshell_proto_rawDescGZIP(), []int{93} } func (x *WatchSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8091,7 +8264,7 @@ type SandboxStreamEvent struct { func (x *SandboxStreamEvent) Reset() { *x = SandboxStreamEvent{} - mi := &file_openshell_proto_msgTypes[92] + mi := &file_openshell_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8103,7 +8276,7 @@ func (x *SandboxStreamEvent) String() string { func (*SandboxStreamEvent) ProtoMessage() {} func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[92] + mi := &file_openshell_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8116,7 +8289,7 @@ func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStreamEvent.ProtoReflect.Descriptor instead. func (*SandboxStreamEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{92} + return file_openshell_proto_rawDescGZIP(), []int{94} } func (x *SandboxStreamEvent) GetPayload() isSandboxStreamEvent_Payload { @@ -8238,7 +8411,7 @@ type SandboxLogLine struct { func (x *SandboxLogLine) Reset() { *x = SandboxLogLine{} - mi := &file_openshell_proto_msgTypes[93] + mi := &file_openshell_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8250,7 +8423,7 @@ func (x *SandboxLogLine) String() string { func (*SandboxLogLine) ProtoMessage() {} func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[93] + mi := &file_openshell_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8263,7 +8436,7 @@ func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxLogLine.ProtoReflect.Descriptor instead. func (*SandboxLogLine) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{93} + return file_openshell_proto_rawDescGZIP(), []int{95} } func (x *SandboxLogLine) GetSandboxId() string { @@ -8329,7 +8502,7 @@ type SandboxStreamWarning struct { func (x *SandboxStreamWarning) Reset() { *x = SandboxStreamWarning{} - mi := &file_openshell_proto_msgTypes[94] + mi := &file_openshell_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8341,7 +8514,7 @@ func (x *SandboxStreamWarning) String() string { func (*SandboxStreamWarning) ProtoMessage() {} func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[94] + mi := &file_openshell_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8354,7 +8527,7 @@ func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStreamWarning.ProtoReflect.Descriptor instead. func (*SandboxStreamWarning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{94} + return file_openshell_proto_rawDescGZIP(), []int{96} } func (x *SandboxStreamWarning) GetMessage() string { @@ -8379,7 +8552,7 @@ type CreateProviderRequest struct { func (x *CreateProviderRequest) Reset() { *x = CreateProviderRequest{} - mi := &file_openshell_proto_msgTypes[95] + mi := &file_openshell_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8391,7 +8564,7 @@ func (x *CreateProviderRequest) String() string { func (*CreateProviderRequest) ProtoMessage() {} func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[95] + mi := &file_openshell_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8404,7 +8577,7 @@ func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateProviderRequest.ProtoReflect.Descriptor instead. func (*CreateProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{95} + return file_openshell_proto_rawDescGZIP(), []int{97} } func (x *CreateProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8440,7 +8613,7 @@ type GetProviderRequest struct { func (x *GetProviderRequest) Reset() { *x = GetProviderRequest{} - mi := &file_openshell_proto_msgTypes[96] + mi := &file_openshell_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8452,7 +8625,7 @@ func (x *GetProviderRequest) String() string { func (*GetProviderRequest) ProtoMessage() {} func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[96] + mi := &file_openshell_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8465,7 +8638,7 @@ func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRequest.ProtoReflect.Descriptor instead. func (*GetProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{96} + return file_openshell_proto_rawDescGZIP(), []int{98} } func (x *GetProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8500,7 +8673,7 @@ type GetProviderCredentialsRequest struct { func (x *GetProviderCredentialsRequest) Reset() { *x = GetProviderCredentialsRequest{} - mi := &file_openshell_proto_msgTypes[97] + mi := &file_openshell_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8512,7 +8685,7 @@ func (x *GetProviderCredentialsRequest) String() string { func (*GetProviderCredentialsRequest) ProtoMessage() {} func (x *GetProviderCredentialsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[97] + mi := &file_openshell_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8525,7 +8698,7 @@ func (x *GetProviderCredentialsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderCredentialsRequest.ProtoReflect.Descriptor instead. func (*GetProviderCredentialsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{97} + return file_openshell_proto_rawDescGZIP(), []int{99} } func (x *GetProviderCredentialsRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8568,7 +8741,7 @@ type ProviderCredentialValue struct { func (x *ProviderCredentialValue) Reset() { *x = ProviderCredentialValue{} - mi := &file_openshell_proto_msgTypes[98] + mi := &file_openshell_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8580,7 +8753,7 @@ func (x *ProviderCredentialValue) String() string { func (*ProviderCredentialValue) ProtoMessage() {} func (x *ProviderCredentialValue) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[98] + mi := &file_openshell_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8593,7 +8766,7 @@ func (x *ProviderCredentialValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialValue.ProtoReflect.Descriptor instead. func (*ProviderCredentialValue) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{98} + return file_openshell_proto_rawDescGZIP(), []int{100} } func (x *ProviderCredentialValue) GetValue() string { @@ -8620,7 +8793,7 @@ type GetProviderCredentialsResponse struct { func (x *GetProviderCredentialsResponse) Reset() { *x = GetProviderCredentialsResponse{} - mi := &file_openshell_proto_msgTypes[99] + mi := &file_openshell_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8632,7 +8805,7 @@ func (x *GetProviderCredentialsResponse) String() string { func (*GetProviderCredentialsResponse) ProtoMessage() {} func (x *GetProviderCredentialsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[99] + mi := &file_openshell_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8645,7 +8818,7 @@ func (x *GetProviderCredentialsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderCredentialsResponse.ProtoReflect.Descriptor instead. func (*GetProviderCredentialsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{99} + return file_openshell_proto_rawDescGZIP(), []int{101} } func (x *GetProviderCredentialsResponse) GetCredentials() map[string]*ProviderCredentialValue { @@ -8674,7 +8847,7 @@ type ListProvidersRequest struct { func (x *ListProvidersRequest) Reset() { *x = ListProvidersRequest{} - mi := &file_openshell_proto_msgTypes[100] + mi := &file_openshell_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8686,7 +8859,7 @@ func (x *ListProvidersRequest) String() string { func (*ListProvidersRequest) ProtoMessage() {} func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[100] + mi := &file_openshell_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8699,7 +8872,7 @@ func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProvidersRequest.ProtoReflect.Descriptor instead. func (*ListProvidersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{100} + return file_openshell_proto_rawDescGZIP(), []int{102} } func (x *ListProvidersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8751,7 +8924,7 @@ type UpdateProviderRequest struct { func (x *UpdateProviderRequest) Reset() { *x = UpdateProviderRequest{} - mi := &file_openshell_proto_msgTypes[101] + mi := &file_openshell_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8763,7 +8936,7 @@ func (x *UpdateProviderRequest) String() string { func (*UpdateProviderRequest) ProtoMessage() {} func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[101] + mi := &file_openshell_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8776,7 +8949,7 @@ func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{101} + return file_openshell_proto_rawDescGZIP(), []int{103} } func (x *UpdateProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8830,7 +9003,7 @@ type DeleteProviderRequest struct { func (x *DeleteProviderRequest) Reset() { *x = DeleteProviderRequest{} - mi := &file_openshell_proto_msgTypes[102] + mi := &file_openshell_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8842,7 +9015,7 @@ func (x *DeleteProviderRequest) String() string { func (*DeleteProviderRequest) ProtoMessage() {} func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[102] + mi := &file_openshell_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8855,7 +9028,7 @@ func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{102} + return file_openshell_proto_rawDescGZIP(), []int{104} } func (x *DeleteProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8901,7 +9074,7 @@ type ProviderResponse struct { func (x *ProviderResponse) Reset() { *x = ProviderResponse{} - mi := &file_openshell_proto_msgTypes[103] + mi := &file_openshell_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8913,7 +9086,7 @@ func (x *ProviderResponse) String() string { func (*ProviderResponse) ProtoMessage() {} func (x *ProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[103] + mi := &file_openshell_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8926,7 +9099,7 @@ func (x *ProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderResponse.ProtoReflect.Descriptor instead. func (*ProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{103} + return file_openshell_proto_rawDescGZIP(), []int{105} } func (x *ProviderResponse) GetProvider() *datamodelv1.Provider { @@ -8962,7 +9135,7 @@ type ListProvidersResponse struct { func (x *ListProvidersResponse) Reset() { *x = ListProvidersResponse{} - mi := &file_openshell_proto_msgTypes[104] + mi := &file_openshell_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8974,7 +9147,7 @@ func (x *ListProvidersResponse) String() string { func (*ListProvidersResponse) ProtoMessage() {} func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[104] + mi := &file_openshell_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8987,7 +9160,7 @@ func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProvidersResponse.ProtoReflect.Descriptor instead. func (*ListProvidersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{104} + return file_openshell_proto_rawDescGZIP(), []int{106} } func (x *ListProvidersResponse) GetProviders() []*datamodelv1.Provider { @@ -9021,7 +9194,7 @@ type ListProviderProfilesRequest struct { func (x *ListProviderProfilesRequest) Reset() { *x = ListProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[105] + mi := &file_openshell_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9033,7 +9206,7 @@ func (x *ListProviderProfilesRequest) String() string { func (*ListProviderProfilesRequest) ProtoMessage() {} func (x *ListProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[105] + mi := &file_openshell_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9046,7 +9219,7 @@ func (x *ListProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ListProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{105} + return file_openshell_proto_rawDescGZIP(), []int{107} } func (x *ListProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -9082,7 +9255,7 @@ type GetProviderProfileRequest struct { func (x *GetProviderProfileRequest) Reset() { *x = GetProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[106] + mi := &file_openshell_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9094,7 +9267,7 @@ func (x *GetProviderProfileRequest) String() string { func (*GetProviderProfileRequest) ProtoMessage() {} func (x *GetProviderProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[106] + mi := &file_openshell_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9107,7 +9280,7 @@ func (x *GetProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderProfileRequest.ProtoReflect.Descriptor instead. func (*GetProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{106} + return file_openshell_proto_rawDescGZIP(), []int{108} } func (x *GetProviderProfileRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -9135,7 +9308,7 @@ type ProviderProfileImportItem struct { func (x *ProviderProfileImportItem) Reset() { *x = ProviderProfileImportItem{} - mi := &file_openshell_proto_msgTypes[107] + mi := &file_openshell_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9147,7 +9320,7 @@ func (x *ProviderProfileImportItem) String() string { func (*ProviderProfileImportItem) ProtoMessage() {} func (x *ProviderProfileImportItem) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[107] + mi := &file_openshell_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9160,7 +9333,7 @@ func (x *ProviderProfileImportItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileImportItem.ProtoReflect.Descriptor instead. func (*ProviderProfileImportItem) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{107} + return file_openshell_proto_rawDescGZIP(), []int{109} } func (x *ProviderProfileImportItem) GetProfile() *ProviderProfile { @@ -9191,7 +9364,7 @@ type ProviderProfileDiagnostic struct { func (x *ProviderProfileDiagnostic) Reset() { *x = ProviderProfileDiagnostic{} - mi := &file_openshell_proto_msgTypes[108] + mi := &file_openshell_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9203,7 +9376,7 @@ func (x *ProviderProfileDiagnostic) String() string { func (*ProviderProfileDiagnostic) ProtoMessage() {} func (x *ProviderProfileDiagnostic) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[108] + mi := &file_openshell_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9216,7 +9389,7 @@ func (x *ProviderProfileDiagnostic) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileDiagnostic.ProtoReflect.Descriptor instead. func (*ProviderProfileDiagnostic) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{108} + return file_openshell_proto_rawDescGZIP(), []int{110} } func (x *ProviderProfileDiagnostic) GetSource() string { @@ -9273,7 +9446,7 @@ type ProviderCredentialTokenGrantAudienceOverride struct { func (x *ProviderCredentialTokenGrantAudienceOverride) Reset() { *x = ProviderCredentialTokenGrantAudienceOverride{} - mi := &file_openshell_proto_msgTypes[109] + mi := &file_openshell_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9285,7 +9458,7 @@ func (x *ProviderCredentialTokenGrantAudienceOverride) String() string { func (*ProviderCredentialTokenGrantAudienceOverride) ProtoMessage() {} func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[109] + mi := &file_openshell_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9298,7 +9471,7 @@ func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protorefle // Deprecated: Use ProviderCredentialTokenGrantAudienceOverride.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrantAudienceOverride) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{109} + return file_openshell_proto_rawDescGZIP(), []int{111} } func (x *ProviderCredentialTokenGrantAudienceOverride) GetHost() string { @@ -9352,7 +9525,7 @@ type ProviderCredentialTokenGrantSubjectToken struct { func (x *ProviderCredentialTokenGrantSubjectToken) Reset() { *x = ProviderCredentialTokenGrantSubjectToken{} - mi := &file_openshell_proto_msgTypes[110] + mi := &file_openshell_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9364,7 +9537,7 @@ func (x *ProviderCredentialTokenGrantSubjectToken) String() string { func (*ProviderCredentialTokenGrantSubjectToken) ProtoMessage() {} func (x *ProviderCredentialTokenGrantSubjectToken) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[110] + mi := &file_openshell_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9377,7 +9550,7 @@ func (x *ProviderCredentialTokenGrantSubjectToken) ProtoReflect() protoreflect.M // Deprecated: Use ProviderCredentialTokenGrantSubjectToken.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrantSubjectToken) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{110} + return file_openshell_proto_rawDescGZIP(), []int{112} } func (x *ProviderCredentialTokenGrantSubjectToken) GetSource() string { @@ -9433,7 +9606,7 @@ type ProviderCredentialTokenGrant struct { func (x *ProviderCredentialTokenGrant) Reset() { *x = ProviderCredentialTokenGrant{} - mi := &file_openshell_proto_msgTypes[111] + mi := &file_openshell_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9445,7 +9618,7 @@ func (x *ProviderCredentialTokenGrant) String() string { func (*ProviderCredentialTokenGrant) ProtoMessage() {} func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[111] + mi := &file_openshell_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9458,7 +9631,7 @@ func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialTokenGrant.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrant) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{111} + return file_openshell_proto_rawDescGZIP(), []int{113} } func (x *ProviderCredentialTokenGrant) GetTokenEndpoint() string { @@ -9562,7 +9735,7 @@ type ProviderProfileCredential struct { func (x *ProviderProfileCredential) Reset() { *x = ProviderProfileCredential{} - mi := &file_openshell_proto_msgTypes[112] + mi := &file_openshell_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9574,7 +9747,7 @@ func (x *ProviderProfileCredential) String() string { func (*ProviderProfileCredential) ProtoMessage() {} func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[112] + mi := &file_openshell_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9587,7 +9760,7 @@ func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileCredential.ProtoReflect.Descriptor instead. func (*ProviderProfileCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{112} + return file_openshell_proto_rawDescGZIP(), []int{114} } func (x *ProviderProfileCredential) GetName() string { @@ -9686,7 +9859,7 @@ type ProviderCredentialRefreshMaterial struct { func (x *ProviderCredentialRefreshMaterial) Reset() { *x = ProviderCredentialRefreshMaterial{} - mi := &file_openshell_proto_msgTypes[113] + mi := &file_openshell_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9698,7 +9871,7 @@ func (x *ProviderCredentialRefreshMaterial) String() string { func (*ProviderCredentialRefreshMaterial) ProtoMessage() {} func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[113] + mi := &file_openshell_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9711,7 +9884,7 @@ func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message // Deprecated: Use ProviderCredentialRefreshMaterial.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshMaterial) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{113} + return file_openshell_proto_rawDescGZIP(), []int{115} } func (x *ProviderCredentialRefreshMaterial) GetName() string { @@ -9756,7 +9929,7 @@ type ProviderCredentialRefreshOutput struct { func (x *ProviderCredentialRefreshOutput) Reset() { *x = ProviderCredentialRefreshOutput{} - mi := &file_openshell_proto_msgTypes[114] + mi := &file_openshell_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9768,7 +9941,7 @@ func (x *ProviderCredentialRefreshOutput) String() string { func (*ProviderCredentialRefreshOutput) ProtoMessage() {} func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[114] + mi := &file_openshell_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9781,7 +9954,7 @@ func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefreshOutput.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshOutput) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{114} + return file_openshell_proto_rawDescGZIP(), []int{116} } func (x *ProviderCredentialRefreshOutput) GetOutput() string { @@ -9813,7 +9986,7 @@ type ProviderCredentialRefresh struct { func (x *ProviderCredentialRefresh) Reset() { *x = ProviderCredentialRefresh{} - mi := &file_openshell_proto_msgTypes[115] + mi := &file_openshell_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9825,7 +9998,7 @@ func (x *ProviderCredentialRefresh) String() string { func (*ProviderCredentialRefresh) ProtoMessage() {} func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[115] + mi := &file_openshell_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9838,7 +10011,7 @@ func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefresh.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefresh) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{115} + return file_openshell_proto_rawDescGZIP(), []int{117} } func (x *ProviderCredentialRefresh) GetStrategy() ProviderCredentialRefreshStrategy { @@ -9919,7 +10092,7 @@ type ProviderCredentialRefreshStatus struct { func (x *ProviderCredentialRefreshStatus) Reset() { *x = ProviderCredentialRefreshStatus{} - mi := &file_openshell_proto_msgTypes[116] + mi := &file_openshell_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9931,7 +10104,7 @@ func (x *ProviderCredentialRefreshStatus) String() string { func (*ProviderCredentialRefreshStatus) ProtoMessage() {} func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[116] + mi := &file_openshell_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9944,7 +10117,7 @@ func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefreshStatus.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{116} + return file_openshell_proto_rawDescGZIP(), []int{118} } func (x *ProviderCredentialRefreshStatus) GetProvider() string { @@ -10049,7 +10222,7 @@ type ProviderProfileDiscovery struct { func (x *ProviderProfileDiscovery) Reset() { *x = ProviderProfileDiscovery{} - mi := &file_openshell_proto_msgTypes[117] + mi := &file_openshell_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10061,7 +10234,7 @@ func (x *ProviderProfileDiscovery) String() string { func (*ProviderProfileDiscovery) ProtoMessage() {} func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[117] + mi := &file_openshell_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10074,7 +10247,7 @@ func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileDiscovery.ProtoReflect.Descriptor instead. func (*ProviderProfileDiscovery) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{117} + return file_openshell_proto_rawDescGZIP(), []int{119} } func (x *ProviderProfileDiscovery) GetCredentials() []string { @@ -10096,7 +10269,7 @@ type GetProviderRefreshStatusRequest struct { func (x *GetProviderRefreshStatusRequest) Reset() { *x = GetProviderRefreshStatusRequest{} - mi := &file_openshell_proto_msgTypes[118] + mi := &file_openshell_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10108,7 +10281,7 @@ func (x *GetProviderRefreshStatusRequest) String() string { func (*GetProviderRefreshStatusRequest) ProtoMessage() {} func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[118] + mi := &file_openshell_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10121,7 +10294,7 @@ func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRefreshStatusRequest.ProtoReflect.Descriptor instead. func (*GetProviderRefreshStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{118} + return file_openshell_proto_rawDescGZIP(), []int{120} } func (x *GetProviderRefreshStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10154,7 +10327,7 @@ type GetProviderRefreshStatusResponse struct { func (x *GetProviderRefreshStatusResponse) Reset() { *x = GetProviderRefreshStatusResponse{} - mi := &file_openshell_proto_msgTypes[119] + mi := &file_openshell_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10166,7 +10339,7 @@ func (x *GetProviderRefreshStatusResponse) String() string { func (*GetProviderRefreshStatusResponse) ProtoMessage() {} func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[119] + mi := &file_openshell_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10179,7 +10352,7 @@ func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRefreshStatusResponse.ProtoReflect.Descriptor instead. func (*GetProviderRefreshStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{119} + return file_openshell_proto_rawDescGZIP(), []int{121} } func (x *GetProviderRefreshStatusResponse) GetCredentials() []*ProviderCredentialRefreshStatus { @@ -10211,7 +10384,7 @@ type ConfigureProviderRefreshRequest struct { func (x *ConfigureProviderRefreshRequest) Reset() { *x = ConfigureProviderRefreshRequest{} - mi := &file_openshell_proto_msgTypes[120] + mi := &file_openshell_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10223,7 +10396,7 @@ func (x *ConfigureProviderRefreshRequest) String() string { func (*ConfigureProviderRefreshRequest) ProtoMessage() {} func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[120] + mi := &file_openshell_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10236,7 +10409,7 @@ func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureProviderRefreshRequest.ProtoReflect.Descriptor instead. func (*ConfigureProviderRefreshRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{120} + return file_openshell_proto_rawDescGZIP(), []int{122} } func (x *ConfigureProviderRefreshRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10304,7 +10477,7 @@ type ConfigureProviderRefreshResponse struct { func (x *ConfigureProviderRefreshResponse) Reset() { *x = ConfigureProviderRefreshResponse{} - mi := &file_openshell_proto_msgTypes[121] + mi := &file_openshell_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10316,7 +10489,7 @@ func (x *ConfigureProviderRefreshResponse) String() string { func (*ConfigureProviderRefreshResponse) ProtoMessage() {} func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[121] + mi := &file_openshell_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10329,7 +10502,7 @@ func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureProviderRefreshResponse.ProtoReflect.Descriptor instead. func (*ConfigureProviderRefreshResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{121} + return file_openshell_proto_rawDescGZIP(), []int{123} } func (x *ConfigureProviderRefreshResponse) GetStatus() *ProviderCredentialRefreshStatus { @@ -10354,7 +10527,7 @@ type RotateProviderCredentialRequest struct { func (x *RotateProviderCredentialRequest) Reset() { *x = RotateProviderCredentialRequest{} - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10366,7 +10539,7 @@ func (x *RotateProviderCredentialRequest) String() string { func (*RotateProviderCredentialRequest) ProtoMessage() {} func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10379,7 +10552,7 @@ func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateProviderCredentialRequest.ProtoReflect.Descriptor instead. func (*RotateProviderCredentialRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{122} + return file_openshell_proto_rawDescGZIP(), []int{124} } func (x *RotateProviderCredentialRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10419,7 +10592,7 @@ type RotateProviderCredentialResponse struct { func (x *RotateProviderCredentialResponse) Reset() { *x = RotateProviderCredentialResponse{} - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10431,7 +10604,7 @@ func (x *RotateProviderCredentialResponse) String() string { func (*RotateProviderCredentialResponse) ProtoMessage() {} func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10444,7 +10617,7 @@ func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateProviderCredentialResponse.ProtoReflect.Descriptor instead. func (*RotateProviderCredentialResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{123} + return file_openshell_proto_rawDescGZIP(), []int{125} } func (x *RotateProviderCredentialResponse) GetStatus() *ProviderCredentialRefreshStatus { @@ -10470,7 +10643,7 @@ type DeleteProviderRefreshRequest struct { func (x *DeleteProviderRefreshRequest) Reset() { *x = DeleteProviderRefreshRequest{} - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10482,7 +10655,7 @@ func (x *DeleteProviderRefreshRequest) String() string { func (*DeleteProviderRefreshRequest) ProtoMessage() {} func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10495,7 +10668,7 @@ func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRefreshRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderRefreshRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{124} + return file_openshell_proto_rawDescGZIP(), []int{126} } func (x *DeleteProviderRefreshRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10542,7 +10715,7 @@ type DeleteProviderRefreshResponse struct { func (x *DeleteProviderRefreshResponse) Reset() { *x = DeleteProviderRefreshResponse{} - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10554,7 +10727,7 @@ func (x *DeleteProviderRefreshResponse) String() string { func (*DeleteProviderRefreshResponse) ProtoMessage() {} func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10567,7 +10740,7 @@ func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRefreshResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderRefreshResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{125} + return file_openshell_proto_rawDescGZIP(), []int{127} } func (x *DeleteProviderRefreshResponse) GetOutcome() DeletionOutcome { @@ -10610,7 +10783,7 @@ type ProviderProfile struct { func (x *ProviderProfile) Reset() { *x = ProviderProfile{} - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10622,7 +10795,7 @@ func (x *ProviderProfile) String() string { func (*ProviderProfile) ProtoMessage() {} func (x *ProviderProfile) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10635,7 +10808,7 @@ func (x *ProviderProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfile.ProtoReflect.Descriptor instead. func (*ProviderProfile) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{126} + return file_openshell_proto_rawDescGZIP(), []int{128} } func (x *ProviderProfile) GetId() string { @@ -10751,7 +10924,7 @@ type ProviderProfileFile struct { func (x *ProviderProfileFile) Reset() { *x = ProviderProfileFile{} - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10763,7 +10936,7 @@ func (x *ProviderProfileFile) String() string { func (*ProviderProfileFile) ProtoMessage() {} func (x *ProviderProfileFile) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10776,7 +10949,7 @@ func (x *ProviderProfileFile) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileFile.ProtoReflect.Descriptor instead. func (*ProviderProfileFile) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{127} + return file_openshell_proto_rawDescGZIP(), []int{129} } func (x *ProviderProfileFile) GetPath() string { @@ -10810,7 +10983,7 @@ type ProviderProfileResponse struct { func (x *ProviderProfileResponse) Reset() { *x = ProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10822,7 +10995,7 @@ func (x *ProviderProfileResponse) String() string { func (*ProviderProfileResponse) ProtoMessage() {} func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10835,7 +11008,7 @@ func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileResponse.ProtoReflect.Descriptor instead. func (*ProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{128} + return file_openshell_proto_rawDescGZIP(), []int{130} } func (x *ProviderProfileResponse) GetProfile() *ProviderProfile { @@ -10857,7 +11030,7 @@ type ListProviderProfilesResponse struct { func (x *ListProviderProfilesResponse) Reset() { *x = ListProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10869,7 +11042,7 @@ func (x *ListProviderProfilesResponse) String() string { func (*ListProviderProfilesResponse) ProtoMessage() {} func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[131] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10882,7 +11055,7 @@ func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ListProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{129} + return file_openshell_proto_rawDescGZIP(), []int{131} } func (x *ListProviderProfilesResponse) GetProfiles() []*ProviderProfile { @@ -10914,7 +11087,7 @@ type ImportProviderProfilesRequest struct { func (x *ImportProviderProfilesRequest) Reset() { *x = ImportProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10926,7 +11099,7 @@ func (x *ImportProviderProfilesRequest) String() string { func (*ImportProviderProfilesRequest) ProtoMessage() {} func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10939,7 +11112,7 @@ func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{130} + return file_openshell_proto_rawDescGZIP(), []int{132} } func (x *ImportProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10975,7 +11148,7 @@ type ImportProviderProfilesResponse struct { func (x *ImportProviderProfilesResponse) Reset() { *x = ImportProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10987,7 +11160,7 @@ func (x *ImportProviderProfilesResponse) String() string { func (*ImportProviderProfilesResponse) ProtoMessage() {} func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11000,7 +11173,7 @@ func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{131} + return file_openshell_proto_rawDescGZIP(), []int{133} } func (x *ImportProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11046,7 +11219,7 @@ type UpdateProviderProfilesRequest struct { func (x *UpdateProviderProfilesRequest) Reset() { *x = UpdateProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11058,7 +11231,7 @@ func (x *UpdateProviderProfilesRequest) String() string { func (*UpdateProviderProfilesRequest) ProtoMessage() {} func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[134] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11071,7 +11244,7 @@ func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{132} + return file_openshell_proto_rawDescGZIP(), []int{134} } func (x *UpdateProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11121,7 +11294,7 @@ type UpdateProviderProfilesResponse struct { func (x *UpdateProviderProfilesResponse) Reset() { *x = UpdateProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11133,7 +11306,7 @@ func (x *UpdateProviderProfilesResponse) String() string { func (*UpdateProviderProfilesResponse) ProtoMessage() {} func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[135] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11146,7 +11319,7 @@ func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{133} + return file_openshell_proto_rawDescGZIP(), []int{135} } func (x *UpdateProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11182,7 +11355,7 @@ type LintProviderProfilesRequest struct { func (x *LintProviderProfilesRequest) Reset() { *x = LintProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11194,7 +11367,7 @@ func (x *LintProviderProfilesRequest) String() string { func (*LintProviderProfilesRequest) ProtoMessage() {} func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[136] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11207,7 +11380,7 @@ func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*LintProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{134} + return file_openshell_proto_rawDescGZIP(), []int{136} } func (x *LintProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11238,7 +11411,7 @@ type LintProviderProfilesResponse struct { func (x *LintProviderProfilesResponse) Reset() { *x = LintProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11250,7 +11423,7 @@ func (x *LintProviderProfilesResponse) String() string { func (*LintProviderProfilesResponse) ProtoMessage() {} func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[137] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11263,7 +11436,7 @@ func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*LintProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{135} + return file_openshell_proto_rawDescGZIP(), []int{137} } func (x *LintProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11297,7 +11470,7 @@ type DeleteProviderResponse struct { func (x *DeleteProviderResponse) Reset() { *x = DeleteProviderResponse{} - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11309,7 +11482,7 @@ func (x *DeleteProviderResponse) String() string { func (*DeleteProviderResponse) ProtoMessage() {} func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[138] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11322,7 +11495,7 @@ func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{136} + return file_openshell_proto_rawDescGZIP(), []int{138} } func (x *DeleteProviderResponse) GetOutcome() DeletionOutcome { @@ -11348,7 +11521,7 @@ type DeleteProviderProfileRequest struct { func (x *DeleteProviderProfileRequest) Reset() { *x = DeleteProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11360,7 +11533,7 @@ func (x *DeleteProviderProfileRequest) String() string { func (*DeleteProviderProfileRequest) ProtoMessage() {} func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[139] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11373,7 +11546,7 @@ func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{137} + return file_openshell_proto_rawDescGZIP(), []int{139} } func (x *DeleteProviderProfileRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11414,7 +11587,7 @@ type DeleteProviderProfileResponse struct { func (x *DeleteProviderProfileResponse) Reset() { *x = DeleteProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[140] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11426,7 +11599,7 @@ func (x *DeleteProviderProfileResponse) String() string { func (*DeleteProviderProfileResponse) ProtoMessage() {} func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[140] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11439,7 +11612,7 @@ func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{138} + return file_openshell_proto_rawDescGZIP(), []int{140} } func (x *DeleteProviderProfileResponse) GetOutcome() DeletionOutcome { @@ -11468,7 +11641,7 @@ type GetSandboxProviderEnvironmentRequest struct { func (x *GetSandboxProviderEnvironmentRequest) Reset() { *x = GetSandboxProviderEnvironmentRequest{} - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11480,7 +11653,7 @@ func (x *GetSandboxProviderEnvironmentRequest) String() string { func (*GetSandboxProviderEnvironmentRequest) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[141] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11493,7 +11666,7 @@ func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Messa // Deprecated: Use GetSandboxProviderEnvironmentRequest.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{139} + return file_openshell_proto_rawDescGZIP(), []int{141} } func (x *GetSandboxProviderEnvironmentRequest) GetSandboxId() string { @@ -11529,7 +11702,7 @@ type StaticCredentialEndpointBinding struct { func (x *StaticCredentialEndpointBinding) Reset() { *x = StaticCredentialEndpointBinding{} - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[142] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11541,7 +11714,7 @@ func (x *StaticCredentialEndpointBinding) String() string { func (*StaticCredentialEndpointBinding) ProtoMessage() {} func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[142] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11554,7 +11727,7 @@ func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialEndpointBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialEndpointBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{140} + return file_openshell_proto_rawDescGZIP(), []int{142} } func (x *StaticCredentialEndpointBinding) GetHost() string { @@ -11598,7 +11771,7 @@ type StaticCredentialBinding struct { func (x *StaticCredentialBinding) Reset() { *x = StaticCredentialBinding{} - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[143] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11610,7 +11783,7 @@ func (x *StaticCredentialBinding) String() string { func (*StaticCredentialBinding) ProtoMessage() {} func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[143] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11623,7 +11796,7 @@ func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{141} + return file_openshell_proto_rawDescGZIP(), []int{143} } func (x *StaticCredentialBinding) GetEndpoints() []*StaticCredentialEndpointBinding { @@ -11693,7 +11866,7 @@ type GetSandboxProviderEnvironmentResponse struct { func (x *GetSandboxProviderEnvironmentResponse) Reset() { *x = GetSandboxProviderEnvironmentResponse{} - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[144] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11705,7 +11878,7 @@ func (x *GetSandboxProviderEnvironmentResponse) String() string { func (*GetSandboxProviderEnvironmentResponse) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[144] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11718,7 +11891,7 @@ func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Mess // Deprecated: Use GetSandboxProviderEnvironmentResponse.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{142} + return file_openshell_proto_rawDescGZIP(), []int{144} } func (x *GetSandboxProviderEnvironmentResponse) GetEnvironment() map[string]string { @@ -11827,7 +12000,7 @@ type ProviderEnvironmentValue struct { func (x *ProviderEnvironmentValue) Reset() { *x = ProviderEnvironmentValue{} - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11839,7 +12012,7 @@ func (x *ProviderEnvironmentValue) String() string { func (*ProviderEnvironmentValue) ProtoMessage() {} func (x *ProviderEnvironmentValue) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[145] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11852,7 +12025,7 @@ func (x *ProviderEnvironmentValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderEnvironmentValue.ProtoReflect.Descriptor instead. func (*ProviderEnvironmentValue) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{143} + return file_openshell_proto_rawDescGZIP(), []int{145} } func (x *ProviderEnvironmentValue) GetName() string { @@ -11918,7 +12091,7 @@ type ProviderEnvironmentSnapshot struct { func (x *ProviderEnvironmentSnapshot) Reset() { *x = ProviderEnvironmentSnapshot{} - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11930,7 +12103,7 @@ func (x *ProviderEnvironmentSnapshot) String() string { func (*ProviderEnvironmentSnapshot) ProtoMessage() {} func (x *ProviderEnvironmentSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[146] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11943,7 +12116,7 @@ func (x *ProviderEnvironmentSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderEnvironmentSnapshot.ProtoReflect.Descriptor instead. func (*ProviderEnvironmentSnapshot) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{144} + return file_openshell_proto_rawDescGZIP(), []int{146} } func (x *ProviderEnvironmentSnapshot) GetProviderEnvRevision() uint64 { @@ -12012,7 +12185,7 @@ type ExchangeProviderSubjectTokenRequest struct { func (x *ExchangeProviderSubjectTokenRequest) Reset() { *x = ExchangeProviderSubjectTokenRequest{} - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[147] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12024,7 +12197,7 @@ func (x *ExchangeProviderSubjectTokenRequest) String() string { func (*ExchangeProviderSubjectTokenRequest) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[147] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12037,7 +12210,7 @@ func (x *ExchangeProviderSubjectTokenRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use ExchangeProviderSubjectTokenRequest.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{145} + return file_openshell_proto_rawDescGZIP(), []int{147} } func (x *ExchangeProviderSubjectTokenRequest) GetSandboxId() string { @@ -12079,7 +12252,7 @@ type ExchangeProviderSubjectTokenResponse struct { func (x *ExchangeProviderSubjectTokenResponse) Reset() { *x = ExchangeProviderSubjectTokenResponse{} - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12091,7 +12264,7 @@ func (x *ExchangeProviderSubjectTokenResponse) String() string { func (*ExchangeProviderSubjectTokenResponse) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[148] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12104,7 +12277,7 @@ func (x *ExchangeProviderSubjectTokenResponse) ProtoReflect() protoreflect.Messa // Deprecated: Use ExchangeProviderSubjectTokenResponse.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{146} + return file_openshell_proto_rawDescGZIP(), []int{148} } func (x *ExchangeProviderSubjectTokenResponse) GetAccessToken() string { @@ -12178,7 +12351,7 @@ type UpdateConfigRequest struct { func (x *UpdateConfigRequest) Reset() { *x = UpdateConfigRequest{} - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12190,7 +12363,7 @@ func (x *UpdateConfigRequest) String() string { func (*UpdateConfigRequest) ProtoMessage() {} func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[149] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12203,7 +12376,7 @@ func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigRequest.ProtoReflect.Descriptor instead. func (*UpdateConfigRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{147} + return file_openshell_proto_rawDescGZIP(), []int{149} } func (x *UpdateConfigRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -12300,7 +12473,7 @@ type PolicyMergeOperation struct { func (x *PolicyMergeOperation) Reset() { *x = PolicyMergeOperation{} - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12312,7 +12485,7 @@ func (x *PolicyMergeOperation) String() string { func (*PolicyMergeOperation) ProtoMessage() {} func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[150] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12325,7 +12498,7 @@ func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyMergeOperation.ProtoReflect.Descriptor instead. func (*PolicyMergeOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{148} + return file_openshell_proto_rawDescGZIP(), []int{150} } func (x *PolicyMergeOperation) GetOperation() isPolicyMergeOperation_Operation { @@ -12439,7 +12612,7 @@ type AddNetworkRule struct { func (x *AddNetworkRule) Reset() { *x = AddNetworkRule{} - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12451,7 +12624,7 @@ func (x *AddNetworkRule) String() string { func (*AddNetworkRule) ProtoMessage() {} func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[151] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12464,7 +12637,7 @@ func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use AddNetworkRule.ProtoReflect.Descriptor instead. func (*AddNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{149} + return file_openshell_proto_rawDescGZIP(), []int{151} } func (x *AddNetworkRule) GetRuleName() string { @@ -12492,7 +12665,7 @@ type RemoveNetworkEndpoint struct { func (x *RemoveNetworkEndpoint) Reset() { *x = RemoveNetworkEndpoint{} - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12504,7 +12677,7 @@ func (x *RemoveNetworkEndpoint) String() string { func (*RemoveNetworkEndpoint) ProtoMessage() {} func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[152] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12517,7 +12690,7 @@ func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkEndpoint.ProtoReflect.Descriptor instead. func (*RemoveNetworkEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{150} + return file_openshell_proto_rawDescGZIP(), []int{152} } func (x *RemoveNetworkEndpoint) GetRuleName() string { @@ -12550,7 +12723,7 @@ type RemoveNetworkRule struct { func (x *RemoveNetworkRule) Reset() { *x = RemoveNetworkRule{} - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12562,7 +12735,7 @@ func (x *RemoveNetworkRule) String() string { func (*RemoveNetworkRule) ProtoMessage() {} func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[153] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12575,7 +12748,7 @@ func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkRule.ProtoReflect.Descriptor instead. func (*RemoveNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{151} + return file_openshell_proto_rawDescGZIP(), []int{153} } func (x *RemoveNetworkRule) GetRuleName() string { @@ -12604,7 +12777,7 @@ type L7RuleTarget struct { func (x *L7RuleTarget) Reset() { *x = L7RuleTarget{} - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[154] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12616,7 +12789,7 @@ func (x *L7RuleTarget) String() string { func (*L7RuleTarget) ProtoMessage() {} func (x *L7RuleTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[154] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12629,7 +12802,7 @@ func (x *L7RuleTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RuleTarget.ProtoReflect.Descriptor instead. func (*L7RuleTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{152} + return file_openshell_proto_rawDescGZIP(), []int{154} } func (x *L7RuleTarget) GetRuleName() string { @@ -12684,7 +12857,7 @@ type AddDenyRules struct { func (x *AddDenyRules) Reset() { *x = AddDenyRules{} - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[155] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12696,7 +12869,7 @@ func (x *AddDenyRules) String() string { func (*AddDenyRules) ProtoMessage() {} func (x *AddDenyRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[155] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12709,7 +12882,7 @@ func (x *AddDenyRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddDenyRules.ProtoReflect.Descriptor instead. func (*AddDenyRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{153} + return file_openshell_proto_rawDescGZIP(), []int{155} } func (x *AddDenyRules) GetDenyRules() []*sandboxv1.L7DenyRule { @@ -12736,7 +12909,7 @@ type AddAllowRules struct { func (x *AddAllowRules) Reset() { *x = AddAllowRules{} - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[156] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12748,7 +12921,7 @@ func (x *AddAllowRules) String() string { func (*AddAllowRules) ProtoMessage() {} func (x *AddAllowRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[156] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12761,7 +12934,7 @@ func (x *AddAllowRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAllowRules.ProtoReflect.Descriptor instead. func (*AddAllowRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{154} + return file_openshell_proto_rawDescGZIP(), []int{156} } func (x *AddAllowRules) GetRules() []*sandboxv1.L7Rule { @@ -12788,7 +12961,7 @@ type RemoveNetworkBinary struct { func (x *RemoveNetworkBinary) Reset() { *x = RemoveNetworkBinary{} - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[157] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12800,7 +12973,7 @@ func (x *RemoveNetworkBinary) String() string { func (*RemoveNetworkBinary) ProtoMessage() {} func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[157] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12813,7 +12986,7 @@ func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkBinary.ProtoReflect.Descriptor instead. func (*RemoveNetworkBinary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{155} + return file_openshell_proto_rawDescGZIP(), []int{157} } func (x *RemoveNetworkBinary) GetRuleName() string { @@ -12849,7 +13022,7 @@ type UpdateConfigResponse struct { func (x *UpdateConfigResponse) Reset() { *x = UpdateConfigResponse{} - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[158] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12861,7 +13034,7 @@ func (x *UpdateConfigResponse) String() string { func (*UpdateConfigResponse) ProtoMessage() {} func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[158] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12874,7 +13047,7 @@ func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigResponse.ProtoReflect.Descriptor instead. func (*UpdateConfigResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{156} + return file_openshell_proto_rawDescGZIP(), []int{158} } func (x *UpdateConfigResponse) GetVersion() uint32 { @@ -12928,7 +13101,7 @@ type GetSandboxPolicyStatusRequest struct { func (x *GetSandboxPolicyStatusRequest) Reset() { *x = GetSandboxPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[159] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12940,7 +13113,7 @@ func (x *GetSandboxPolicyStatusRequest) String() string { func (*GetSandboxPolicyStatusRequest) ProtoMessage() {} func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[159] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12953,7 +13126,7 @@ func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{157} + return file_openshell_proto_rawDescGZIP(), []int{159} } func (x *GetSandboxPolicyStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -12997,7 +13170,7 @@ type GetSandboxPolicyStatusResponse struct { func (x *GetSandboxPolicyStatusResponse) Reset() { *x = GetSandboxPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[160] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13009,7 +13182,7 @@ func (x *GetSandboxPolicyStatusResponse) String() string { func (*GetSandboxPolicyStatusResponse) ProtoMessage() {} func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[160] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13022,7 +13195,7 @@ func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{158} + return file_openshell_proto_rawDescGZIP(), []int{160} } func (x *GetSandboxPolicyStatusResponse) GetRevision() *SandboxPolicyRevision { @@ -13059,7 +13232,7 @@ type ListSandboxPoliciesRequest struct { func (x *ListSandboxPoliciesRequest) Reset() { *x = ListSandboxPoliciesRequest{} - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[161] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13071,7 +13244,7 @@ func (x *ListSandboxPoliciesRequest) String() string { func (*ListSandboxPoliciesRequest) ProtoMessage() {} func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[161] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13084,7 +13257,7 @@ func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{159} + return file_openshell_proto_rawDescGZIP(), []int{161} } func (x *ListSandboxPoliciesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -13136,7 +13309,7 @@ type ListSandboxPoliciesResponse struct { func (x *ListSandboxPoliciesResponse) Reset() { *x = ListSandboxPoliciesResponse{} - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[162] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13148,7 +13321,7 @@ func (x *ListSandboxPoliciesResponse) String() string { func (*ListSandboxPoliciesResponse) ProtoMessage() {} func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[162] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13161,7 +13334,7 @@ func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{160} + return file_openshell_proto_rawDescGZIP(), []int{162} } func (x *ListSandboxPoliciesResponse) GetRevisions() []*SandboxPolicyRevision { @@ -13195,7 +13368,7 @@ type ReportPolicyStatusRequest struct { func (x *ReportPolicyStatusRequest) Reset() { *x = ReportPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[163] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13207,7 +13380,7 @@ func (x *ReportPolicyStatusRequest) String() string { func (*ReportPolicyStatusRequest) ProtoMessage() {} func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[163] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13220,7 +13393,7 @@ func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{161} + return file_openshell_proto_rawDescGZIP(), []int{163} } func (x *ReportPolicyStatusRequest) GetSandboxId() string { @@ -13260,7 +13433,7 @@ type ReportPolicyStatusResponse struct { func (x *ReportPolicyStatusResponse) Reset() { *x = ReportPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[164] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13272,7 +13445,7 @@ func (x *ReportPolicyStatusResponse) String() string { func (*ReportPolicyStatusResponse) ProtoMessage() {} func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[164] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13285,7 +13458,7 @@ func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{162} + return file_openshell_proto_rawDescGZIP(), []int{164} } type SandboxConfigurationAdmission struct { @@ -13303,7 +13476,7 @@ type SandboxConfigurationAdmission struct { func (x *SandboxConfigurationAdmission) Reset() { *x = SandboxConfigurationAdmission{} - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[165] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13315,7 +13488,7 @@ func (x *SandboxConfigurationAdmission) String() string { func (*SandboxConfigurationAdmission) ProtoMessage() {} func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[165] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13328,7 +13501,7 @@ func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfigurationAdmission.ProtoReflect.Descriptor instead. func (*SandboxConfigurationAdmission) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{163} + return file_openshell_proto_rawDescGZIP(), []int{165} } func (x *SandboxConfigurationAdmission) GetInstanceId() string { @@ -13392,7 +13565,7 @@ type ReportSandboxConfigurationRequest struct { func (x *ReportSandboxConfigurationRequest) Reset() { *x = ReportSandboxConfigurationRequest{} - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[166] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13404,7 +13577,7 @@ func (x *ReportSandboxConfigurationRequest) String() string { func (*ReportSandboxConfigurationRequest) ProtoMessage() {} func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[166] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13417,7 +13590,7 @@ func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ReportSandboxConfigurationRequest.ProtoReflect.Descriptor instead. func (*ReportSandboxConfigurationRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{164} + return file_openshell_proto_rawDescGZIP(), []int{166} } func (x *ReportSandboxConfigurationRequest) GetSandboxId() string { @@ -13449,7 +13622,7 @@ type ReportSandboxConfigurationResponse struct { func (x *ReportSandboxConfigurationResponse) Reset() { *x = ReportSandboxConfigurationResponse{} - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[167] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13461,7 +13634,7 @@ func (x *ReportSandboxConfigurationResponse) String() string { func (*ReportSandboxConfigurationResponse) ProtoMessage() {} func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[167] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13474,7 +13647,7 @@ func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ReportSandboxConfigurationResponse.ProtoReflect.Descriptor instead. func (*ReportSandboxConfigurationResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{165} + return file_openshell_proto_rawDescGZIP(), []int{167} } // A versioned policy revision with metadata. @@ -13507,7 +13680,7 @@ type SandboxPolicyRevision struct { func (x *SandboxPolicyRevision) Reset() { *x = SandboxPolicyRevision{} - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[168] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13519,7 +13692,7 @@ func (x *SandboxPolicyRevision) String() string { func (*SandboxPolicyRevision) ProtoMessage() {} func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[168] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13532,7 +13705,7 @@ func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxPolicyRevision.ProtoReflect.Descriptor instead. func (*SandboxPolicyRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{166} + return file_openshell_proto_rawDescGZIP(), []int{168} } func (x *SandboxPolicyRevision) GetVersion() uint32 { @@ -13612,7 +13785,7 @@ type GetSandboxLogsRequest struct { func (x *GetSandboxLogsRequest) Reset() { *x = GetSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[169] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13624,7 +13797,7 @@ func (x *GetSandboxLogsRequest) String() string { func (*GetSandboxLogsRequest) ProtoMessage() {} func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[169] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13637,7 +13810,7 @@ func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*GetSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{167} + return file_openshell_proto_rawDescGZIP(), []int{169} } func (x *GetSandboxLogsRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -13695,7 +13868,7 @@ type PushSandboxLogsRequest struct { func (x *PushSandboxLogsRequest) Reset() { *x = PushSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[170] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13707,7 +13880,7 @@ func (x *PushSandboxLogsRequest) String() string { func (*PushSandboxLogsRequest) ProtoMessage() {} func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[170] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13720,7 +13893,7 @@ func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*PushSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{168} + return file_openshell_proto_rawDescGZIP(), []int{170} } func (x *PushSandboxLogsRequest) GetSandboxId() string { @@ -13746,7 +13919,7 @@ type PushSandboxLogsResponse struct { func (x *PushSandboxLogsResponse) Reset() { *x = PushSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[171] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13758,7 +13931,7 @@ func (x *PushSandboxLogsResponse) String() string { func (*PushSandboxLogsResponse) ProtoMessage() {} func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[171] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13771,7 +13944,7 @@ func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*PushSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{169} + return file_openshell_proto_rawDescGZIP(), []int{171} } // Get sandbox logs response. @@ -13787,7 +13960,7 @@ type GetSandboxLogsResponse struct { func (x *GetSandboxLogsResponse) Reset() { *x = GetSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[172] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13799,7 +13972,7 @@ func (x *GetSandboxLogsResponse) String() string { func (*GetSandboxLogsResponse) ProtoMessage() {} func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[172] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13812,7 +13985,7 @@ func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*GetSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{170} + return file_openshell_proto_rawDescGZIP(), []int{172} } func (x *GetSandboxLogsResponse) GetLogs() []*SandboxLogLine { @@ -13846,7 +14019,7 @@ type SupervisorMessage struct { func (x *SupervisorMessage) Reset() { *x = SupervisorMessage{} - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[173] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13858,7 +14031,7 @@ func (x *SupervisorMessage) String() string { func (*SupervisorMessage) ProtoMessage() {} func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[173] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13871,7 +14044,7 @@ func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMessage.ProtoReflect.Descriptor instead. func (*SupervisorMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{171} + return file_openshell_proto_rawDescGZIP(), []int{173} } func (x *SupervisorMessage) GetPayload() isSupervisorMessage_Payload { @@ -13979,7 +14152,7 @@ type GatewayMessage struct { func (x *GatewayMessage) Reset() { *x = GatewayMessage{} - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[174] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13991,7 +14164,7 @@ func (x *GatewayMessage) String() string { func (*GatewayMessage) ProtoMessage() {} func (x *GatewayMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[174] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14004,7 +14177,7 @@ func (x *GatewayMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayMessage.ProtoReflect.Descriptor instead. func (*GatewayMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{172} + return file_openshell_proto_rawDescGZIP(), []int{174} } func (x *GatewayMessage) GetPayload() isGatewayMessage_Payload { @@ -14154,7 +14327,7 @@ type SupervisorHello struct { func (x *SupervisorHello) Reset() { *x = SupervisorHello{} - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[175] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14166,7 +14339,7 @@ func (x *SupervisorHello) String() string { func (*SupervisorHello) ProtoMessage() {} func (x *SupervisorHello) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[175] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14179,7 +14352,7 @@ func (x *SupervisorHello) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHello.ProtoReflect.Descriptor instead. func (*SupervisorHello) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{173} + return file_openshell_proto_rawDescGZIP(), []int{175} } func (x *SupervisorHello) GetSandboxId() string { @@ -14252,7 +14425,7 @@ type SessionAccepted struct { func (x *SessionAccepted) Reset() { *x = SessionAccepted{} - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[176] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14264,7 +14437,7 @@ func (x *SessionAccepted) String() string { func (*SessionAccepted) ProtoMessage() {} func (x *SessionAccepted) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[176] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14277,7 +14450,7 @@ func (x *SessionAccepted) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionAccepted.ProtoReflect.Descriptor instead. func (*SessionAccepted) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{174} + return file_openshell_proto_rawDescGZIP(), []int{176} } func (x *SessionAccepted) GetSessionId() string { @@ -14326,7 +14499,7 @@ type ConfigUpdate struct { func (x *ConfigUpdate) Reset() { *x = ConfigUpdate{} - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[177] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14338,7 +14511,7 @@ func (x *ConfigUpdate) String() string { func (*ConfigUpdate) ProtoMessage() {} func (x *ConfigUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[177] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14351,7 +14524,7 @@ func (x *ConfigUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdate.ProtoReflect.Descriptor instead. func (*ConfigUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{175} + return file_openshell_proto_rawDescGZIP(), []int{177} } func (x *ConfigUpdate) GetUpdateId() string { @@ -14388,7 +14561,7 @@ type ConfigApplyFailure struct { func (x *ConfigApplyFailure) Reset() { *x = ConfigApplyFailure{} - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[178] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14400,7 +14573,7 @@ func (x *ConfigApplyFailure) String() string { func (*ConfigApplyFailure) ProtoMessage() {} func (x *ConfigApplyFailure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[178] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14413,7 +14586,7 @@ func (x *ConfigApplyFailure) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigApplyFailure.ProtoReflect.Descriptor instead. func (*ConfigApplyFailure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{176} + return file_openshell_proto_rawDescGZIP(), []int{178} } func (x *ConfigApplyFailure) GetCode() string { @@ -14457,7 +14630,7 @@ type ConfigUpdateResult struct { func (x *ConfigUpdateResult) Reset() { *x = ConfigUpdateResult{} - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[179] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14469,7 +14642,7 @@ func (x *ConfigUpdateResult) String() string { func (*ConfigUpdateResult) ProtoMessage() {} func (x *ConfigUpdateResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[179] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14482,7 +14655,7 @@ func (x *ConfigUpdateResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdateResult.ProtoReflect.Descriptor instead. func (*ConfigUpdateResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{177} + return file_openshell_proto_rawDescGZIP(), []int{179} } func (x *ConfigUpdateResult) GetUpdateId() string { @@ -14533,7 +14706,7 @@ type PolicyLoadResult struct { func (x *PolicyLoadResult) Reset() { *x = PolicyLoadResult{} - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[180] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14545,7 +14718,7 @@ func (x *PolicyLoadResult) String() string { func (*PolicyLoadResult) ProtoMessage() {} func (x *PolicyLoadResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[180] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14558,7 +14731,7 @@ func (x *PolicyLoadResult) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyLoadResult.ProtoReflect.Descriptor instead. func (*PolicyLoadResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{178} + return file_openshell_proto_rawDescGZIP(), []int{180} } func (x *PolicyLoadResult) GetVersion() uint32 { @@ -14593,7 +14766,7 @@ type SessionRejected struct { func (x *SessionRejected) Reset() { *x = SessionRejected{} - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[181] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14605,7 +14778,7 @@ func (x *SessionRejected) String() string { func (*SessionRejected) ProtoMessage() {} func (x *SessionRejected) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[181] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14618,7 +14791,7 @@ func (x *SessionRejected) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRejected.ProtoReflect.Descriptor instead. func (*SessionRejected) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{179} + return file_openshell_proto_rawDescGZIP(), []int{181} } func (x *SessionRejected) GetReason() string { @@ -14647,7 +14820,7 @@ type SessionRedirect struct { func (x *SessionRedirect) Reset() { *x = SessionRedirect{} - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[182] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14659,7 +14832,7 @@ func (x *SessionRedirect) String() string { func (*SessionRedirect) ProtoMessage() {} func (x *SessionRedirect) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[182] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14672,7 +14845,7 @@ func (x *SessionRedirect) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRedirect.ProtoReflect.Descriptor instead. func (*SessionRedirect) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{180} + return file_openshell_proto_rawDescGZIP(), []int{182} } func (x *SessionRedirect) GetPeerEndpoint() string { @@ -14698,7 +14871,7 @@ type SupervisorHeartbeat struct { func (x *SupervisorHeartbeat) Reset() { *x = SupervisorHeartbeat{} - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[183] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14710,7 +14883,7 @@ func (x *SupervisorHeartbeat) String() string { func (*SupervisorHeartbeat) ProtoMessage() {} func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[183] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14723,7 +14896,7 @@ func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHeartbeat.ProtoReflect.Descriptor instead. func (*SupervisorHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{181} + return file_openshell_proto_rawDescGZIP(), []int{183} } // Gateway heartbeat. @@ -14735,7 +14908,7 @@ type GatewayHeartbeat struct { func (x *GatewayHeartbeat) Reset() { *x = GatewayHeartbeat{} - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[184] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14747,7 +14920,7 @@ func (x *GatewayHeartbeat) String() string { func (*GatewayHeartbeat) ProtoMessage() {} func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[184] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14760,7 +14933,7 @@ func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayHeartbeat.ProtoReflect.Descriptor instead. func (*GatewayHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{182} + return file_openshell_proto_rawDescGZIP(), []int{184} } // Terminal result reported before the supervisor shuts down. A successful RPC @@ -14777,7 +14950,7 @@ type ReportMainProcessExitRequest struct { func (x *ReportMainProcessExitRequest) Reset() { *x = ReportMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[185] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14789,7 +14962,7 @@ func (x *ReportMainProcessExitRequest) String() string { func (*ReportMainProcessExitRequest) ProtoMessage() {} func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[185] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14802,7 +14975,7 @@ func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{183} + return file_openshell_proto_rawDescGZIP(), []int{185} } func (x *ReportMainProcessExitRequest) GetSandboxId() string { @@ -14834,7 +15007,7 @@ type ReportMainProcessExitResponse struct { func (x *ReportMainProcessExitResponse) Reset() { *x = ReportMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[186] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14846,7 +15019,7 @@ func (x *ReportMainProcessExitResponse) String() string { func (*ReportMainProcessExitResponse) ProtoMessage() {} func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[186] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14859,7 +15032,7 @@ func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{184} + return file_openshell_proto_rawDescGZIP(), []int{186} } // Terminal-delivery completion reported after all expected foreground SSH @@ -14874,7 +15047,7 @@ type FinalizeMainProcessExitRequest struct { func (x *FinalizeMainProcessExitRequest) Reset() { *x = FinalizeMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[187] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14886,7 +15059,7 @@ func (x *FinalizeMainProcessExitRequest) String() string { func (*FinalizeMainProcessExitRequest) ProtoMessage() {} func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[187] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14899,7 +15072,7 @@ func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{185} + return file_openshell_proto_rawDescGZIP(), []int{187} } func (x *FinalizeMainProcessExitRequest) GetSandboxId() string { @@ -14924,7 +15097,7 @@ type FinalizeMainProcessExitResponse struct { func (x *FinalizeMainProcessExitResponse) Reset() { *x = FinalizeMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[188] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14936,7 +15109,7 @@ func (x *FinalizeMainProcessExitResponse) String() string { func (*FinalizeMainProcessExitResponse) ProtoMessage() {} func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[188] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14949,7 +15122,7 @@ func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{186} + return file_openshell_proto_rawDescGZIP(), []int{188} } // Gateway requests the supervisor to open a relay channel. @@ -14978,7 +15151,7 @@ type RelayOpen struct { func (x *RelayOpen) Reset() { *x = RelayOpen{} - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[189] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14990,7 +15163,7 @@ func (x *RelayOpen) String() string { func (*RelayOpen) ProtoMessage() {} func (x *RelayOpen) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[189] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15003,7 +15176,7 @@ func (x *RelayOpen) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpen.ProtoReflect.Descriptor instead. func (*RelayOpen) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{187} + return file_openshell_proto_rawDescGZIP(), []int{189} } func (x *RelayOpen) GetChannelId() string { @@ -15070,7 +15243,7 @@ type SshRelayTarget struct { func (x *SshRelayTarget) Reset() { *x = SshRelayTarget{} - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[190] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15082,7 +15255,7 @@ func (x *SshRelayTarget) String() string { func (*SshRelayTarget) ProtoMessage() {} func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[190] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15095,7 +15268,7 @@ func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use SshRelayTarget.ProtoReflect.Descriptor instead. func (*SshRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{188} + return file_openshell_proto_rawDescGZIP(), []int{190} } // TCP target dialed by the supervisor from inside the sandbox. @@ -15111,7 +15284,7 @@ type TcpRelayTarget struct { func (x *TcpRelayTarget) Reset() { *x = TcpRelayTarget{} - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[191] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15123,7 +15296,7 @@ func (x *TcpRelayTarget) String() string { func (*TcpRelayTarget) ProtoMessage() {} func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[191] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15136,7 +15309,7 @@ func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpRelayTarget.ProtoReflect.Descriptor instead. func (*TcpRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{189} + return file_openshell_proto_rawDescGZIP(), []int{191} } func (x *TcpRelayTarget) GetHost() string { @@ -15164,7 +15337,7 @@ type RelayInit struct { func (x *RelayInit) Reset() { *x = RelayInit{} - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[192] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15176,7 +15349,7 @@ func (x *RelayInit) String() string { func (*RelayInit) ProtoMessage() {} func (x *RelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[192] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15189,7 +15362,7 @@ func (x *RelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayInit.ProtoReflect.Descriptor instead. func (*RelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{190} + return file_openshell_proto_rawDescGZIP(), []int{192} } func (x *RelayInit) GetChannelId() string { @@ -15216,7 +15389,7 @@ type RelayFrame struct { func (x *RelayFrame) Reset() { *x = RelayFrame{} - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15228,7 +15401,7 @@ func (x *RelayFrame) String() string { func (*RelayFrame) ProtoMessage() {} func (x *RelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[193] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15241,7 +15414,7 @@ func (x *RelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayFrame.ProtoReflect.Descriptor instead. func (*RelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{191} + return file_openshell_proto_rawDescGZIP(), []int{193} } func (x *RelayFrame) GetPayload() isRelayFrame_Payload { @@ -15301,7 +15474,7 @@ type PeerRelayInit struct { func (x *PeerRelayInit) Reset() { *x = PeerRelayInit{} - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15313,7 +15486,7 @@ func (x *PeerRelayInit) String() string { func (*PeerRelayInit) ProtoMessage() {} func (x *PeerRelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[194] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15326,7 +15499,7 @@ func (x *PeerRelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerRelayInit.ProtoReflect.Descriptor instead. func (*PeerRelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{192} + return file_openshell_proto_rawDescGZIP(), []int{194} } func (x *PeerRelayInit) GetSandboxId() string { @@ -15364,7 +15537,7 @@ type PeerRelayFrame struct { func (x *PeerRelayFrame) Reset() { *x = PeerRelayFrame{} - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15376,7 +15549,7 @@ func (x *PeerRelayFrame) String() string { func (*PeerRelayFrame) ProtoMessage() {} func (x *PeerRelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[195] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15389,7 +15562,7 @@ func (x *PeerRelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerRelayFrame.ProtoReflect.Descriptor instead. func (*PeerRelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{193} + return file_openshell_proto_rawDescGZIP(), []int{195} } func (x *PeerRelayFrame) GetPayload() isPeerRelayFrame_Payload { @@ -15444,7 +15617,7 @@ type PeerConfigSandboxTarget struct { func (x *PeerConfigSandboxTarget) Reset() { *x = PeerConfigSandboxTarget{} - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15456,7 +15629,7 @@ func (x *PeerConfigSandboxTarget) String() string { func (*PeerConfigSandboxTarget) ProtoMessage() {} func (x *PeerConfigSandboxTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[196] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15469,7 +15642,7 @@ func (x *PeerConfigSandboxTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerConfigSandboxTarget.ProtoReflect.Descriptor instead. func (*PeerConfigSandboxTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{194} + return file_openshell_proto_rawDescGZIP(), []int{196} } func (x *PeerConfigSandboxTarget) GetSandboxId() string { @@ -15497,7 +15670,7 @@ type PeerConfigProviderTarget struct { func (x *PeerConfigProviderTarget) Reset() { *x = PeerConfigProviderTarget{} - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15509,7 +15682,7 @@ func (x *PeerConfigProviderTarget) String() string { func (*PeerConfigProviderTarget) ProtoMessage() {} func (x *PeerConfigProviderTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[197] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15522,7 +15695,7 @@ func (x *PeerConfigProviderTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerConfigProviderTarget.ProtoReflect.Descriptor instead. func (*PeerConfigProviderTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{195} + return file_openshell_proto_rawDescGZIP(), []int{197} } func (x *PeerConfigProviderTarget) GetWorkspace() string { @@ -15554,7 +15727,7 @@ type PeerNotifyConfigUpdateRequest struct { func (x *PeerNotifyConfigUpdateRequest) Reset() { *x = PeerNotifyConfigUpdateRequest{} - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15566,7 +15739,7 @@ func (x *PeerNotifyConfigUpdateRequest) String() string { func (*PeerNotifyConfigUpdateRequest) ProtoMessage() {} func (x *PeerNotifyConfigUpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[198] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15579,7 +15752,7 @@ func (x *PeerNotifyConfigUpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerNotifyConfigUpdateRequest.ProtoReflect.Descriptor instead. func (*PeerNotifyConfigUpdateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{196} + return file_openshell_proto_rawDescGZIP(), []int{198} } func (x *PeerNotifyConfigUpdateRequest) GetScope() isPeerNotifyConfigUpdateRequest_Scope { @@ -15663,7 +15836,7 @@ type PeerNotifyConfigUpdateResponse struct { func (x *PeerNotifyConfigUpdateResponse) Reset() { *x = PeerNotifyConfigUpdateResponse{} - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15675,7 +15848,7 @@ func (x *PeerNotifyConfigUpdateResponse) String() string { func (*PeerNotifyConfigUpdateResponse) ProtoMessage() {} func (x *PeerNotifyConfigUpdateResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[199] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15688,7 +15861,7 @@ func (x *PeerNotifyConfigUpdateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerNotifyConfigUpdateResponse.ProtoReflect.Descriptor instead. func (*PeerNotifyConfigUpdateResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{197} + return file_openshell_proto_rawDescGZIP(), []int{199} } func (x *PeerNotifyConfigUpdateResponse) GetStaleOwner() bool { @@ -15713,7 +15886,7 @@ type RelayOpenResult struct { func (x *RelayOpenResult) Reset() { *x = RelayOpenResult{} - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[200] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15725,7 +15898,7 @@ func (x *RelayOpenResult) String() string { func (*RelayOpenResult) ProtoMessage() {} func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[200] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15738,7 +15911,7 @@ func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpenResult.ProtoReflect.Descriptor instead. func (*RelayOpenResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{198} + return file_openshell_proto_rawDescGZIP(), []int{200} } func (x *RelayOpenResult) GetChannelId() string { @@ -15775,7 +15948,7 @@ type RelayClose struct { func (x *RelayClose) Reset() { *x = RelayClose{} - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[201] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15787,7 +15960,7 @@ func (x *RelayClose) String() string { func (*RelayClose) ProtoMessage() {} func (x *RelayClose) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[201] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15800,7 +15973,7 @@ func (x *RelayClose) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayClose.ProtoReflect.Descriptor instead. func (*RelayClose) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{199} + return file_openshell_proto_rawDescGZIP(), []int{201} } func (x *RelayClose) GetChannelId() string { @@ -15834,7 +16007,7 @@ type L7RequestSample struct { func (x *L7RequestSample) Reset() { *x = L7RequestSample{} - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[202] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15846,7 +16019,7 @@ func (x *L7RequestSample) String() string { func (*L7RequestSample) ProtoMessage() {} func (x *L7RequestSample) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[202] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15859,7 +16032,7 @@ func (x *L7RequestSample) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RequestSample.ProtoReflect.Descriptor instead. func (*L7RequestSample) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{200} + return file_openshell_proto_rawDescGZIP(), []int{202} } func (x *L7RequestSample) GetMethod() string { @@ -15933,7 +16106,7 @@ type DenialSummary struct { func (x *DenialSummary) Reset() { *x = DenialSummary{} - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[203] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15945,7 +16118,7 @@ func (x *DenialSummary) String() string { func (*DenialSummary) ProtoMessage() {} func (x *DenialSummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[203] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15958,7 +16131,7 @@ func (x *DenialSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialSummary.ProtoReflect.Descriptor instead. func (*DenialSummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{201} + return file_openshell_proto_rawDescGZIP(), []int{203} } func (x *DenialSummary) GetSandboxId() string { @@ -16093,7 +16266,7 @@ type DenialGroupCount struct { func (x *DenialGroupCount) Reset() { *x = DenialGroupCount{} - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[204] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16105,7 +16278,7 @@ func (x *DenialGroupCount) String() string { func (*DenialGroupCount) ProtoMessage() {} func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[204] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16118,7 +16291,7 @@ func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialGroupCount.ProtoReflect.Descriptor instead. func (*DenialGroupCount) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{202} + return file_openshell_proto_rawDescGZIP(), []int{204} } func (x *DenialGroupCount) GetDenyGroup() string { @@ -16151,7 +16324,7 @@ type NetworkActivitySummary struct { func (x *NetworkActivitySummary) Reset() { *x = NetworkActivitySummary{} - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[205] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16163,7 +16336,7 @@ func (x *NetworkActivitySummary) String() string { func (*NetworkActivitySummary) ProtoMessage() {} func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[205] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16176,7 +16349,7 @@ func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkActivitySummary.ProtoReflect.Descriptor instead. func (*NetworkActivitySummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{203} + return file_openshell_proto_rawDescGZIP(), []int{205} } func (x *NetworkActivitySummary) GetNetworkActivityCount() uint32 { @@ -16264,7 +16437,7 @@ type PolicyChunk struct { func (x *PolicyChunk) Reset() { *x = PolicyChunk{} - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[206] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16276,7 +16449,7 @@ func (x *PolicyChunk) String() string { func (*PolicyChunk) ProtoMessage() {} func (x *PolicyChunk) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[206] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16289,7 +16462,7 @@ func (x *PolicyChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyChunk.ProtoReflect.Descriptor instead. func (*PolicyChunk) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{204} + return file_openshell_proto_rawDescGZIP(), []int{206} } func (x *PolicyChunk) GetId() string { @@ -16477,7 +16650,7 @@ type DraftPolicyUpdate struct { func (x *DraftPolicyUpdate) Reset() { *x = DraftPolicyUpdate{} - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[207] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16489,7 +16662,7 @@ func (x *DraftPolicyUpdate) String() string { func (*DraftPolicyUpdate) ProtoMessage() {} func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[207] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16502,7 +16675,7 @@ func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftPolicyUpdate.ProtoReflect.Descriptor instead. func (*DraftPolicyUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{205} + return file_openshell_proto_rawDescGZIP(), []int{207} } func (x *DraftPolicyUpdate) GetDraftVersion() uint64 { @@ -16561,7 +16734,7 @@ type SubmitPolicyAnalysisRequest struct { func (x *SubmitPolicyAnalysisRequest) Reset() { *x = SubmitPolicyAnalysisRequest{} - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[208] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16573,7 +16746,7 @@ func (x *SubmitPolicyAnalysisRequest) String() string { func (*SubmitPolicyAnalysisRequest) ProtoMessage() {} func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[208] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16586,7 +16759,7 @@ func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisRequest.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{206} + return file_openshell_proto_rawDescGZIP(), []int{208} } func (x *SubmitPolicyAnalysisRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16649,7 +16822,7 @@ type SubmitPolicyAnalysisResponse struct { func (x *SubmitPolicyAnalysisResponse) Reset() { *x = SubmitPolicyAnalysisResponse{} - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[209] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16661,7 +16834,7 @@ func (x *SubmitPolicyAnalysisResponse) String() string { func (*SubmitPolicyAnalysisResponse) ProtoMessage() {} func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[209] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16674,7 +16847,7 @@ func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisResponse.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{207} + return file_openshell_proto_rawDescGZIP(), []int{209} } func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunks() uint32 { @@ -16719,7 +16892,7 @@ type GetDraftPolicyRequest struct { func (x *GetDraftPolicyRequest) Reset() { *x = GetDraftPolicyRequest{} - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[210] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16731,7 +16904,7 @@ func (x *GetDraftPolicyRequest) String() string { func (*GetDraftPolicyRequest) ProtoMessage() {} func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[210] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16744,7 +16917,7 @@ func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyRequest.ProtoReflect.Descriptor instead. func (*GetDraftPolicyRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{208} + return file_openshell_proto_rawDescGZIP(), []int{210} } func (x *GetDraftPolicyRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16784,7 +16957,7 @@ type GetDraftPolicyResponse struct { func (x *GetDraftPolicyResponse) Reset() { *x = GetDraftPolicyResponse{} - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[211] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16796,7 +16969,7 @@ func (x *GetDraftPolicyResponse) String() string { func (*GetDraftPolicyResponse) ProtoMessage() {} func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[211] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16809,7 +16982,7 @@ func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyResponse.ProtoReflect.Descriptor instead. func (*GetDraftPolicyResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{209} + return file_openshell_proto_rawDescGZIP(), []int{211} } func (x *GetDraftPolicyResponse) GetChunks() []*PolicyChunk { @@ -16860,7 +17033,7 @@ type ApproveDraftChunkRequest struct { func (x *ApproveDraftChunkRequest) Reset() { *x = ApproveDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[212] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16872,7 +17045,7 @@ func (x *ApproveDraftChunkRequest) String() string { func (*ApproveDraftChunkRequest) ProtoMessage() {} func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[212] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16885,7 +17058,7 @@ func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkRequest.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{210} + return file_openshell_proto_rawDescGZIP(), []int{212} } func (x *ApproveDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16935,7 +17108,7 @@ type ApproveDraftChunkResponse struct { func (x *ApproveDraftChunkResponse) Reset() { *x = ApproveDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[213] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16947,7 +17120,7 @@ func (x *ApproveDraftChunkResponse) String() string { func (*ApproveDraftChunkResponse) ProtoMessage() {} func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[213] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16960,7 +17133,7 @@ func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkResponse.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{211} + return file_openshell_proto_rawDescGZIP(), []int{213} } func (x *ApproveDraftChunkResponse) GetPolicyVersion() uint32 { @@ -16996,7 +17169,7 @@ type RejectDraftChunkRequest struct { func (x *RejectDraftChunkRequest) Reset() { *x = RejectDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[214] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17008,7 +17181,7 @@ func (x *RejectDraftChunkRequest) String() string { func (*RejectDraftChunkRequest) ProtoMessage() {} func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[214] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17021,7 +17194,7 @@ func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkRequest.ProtoReflect.Descriptor instead. func (*RejectDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{212} + return file_openshell_proto_rawDescGZIP(), []int{214} } func (x *RejectDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17067,7 +17240,7 @@ type RejectDraftChunkResponse struct { func (x *RejectDraftChunkResponse) Reset() { *x = RejectDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[215] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17079,7 +17252,7 @@ func (x *RejectDraftChunkResponse) String() string { func (*RejectDraftChunkResponse) ProtoMessage() {} func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[215] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17092,7 +17265,7 @@ func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkResponse.ProtoReflect.Descriptor instead. func (*RejectDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{213} + return file_openshell_proto_rawDescGZIP(), []int{215} } // Approve all pending chunks. @@ -17106,7 +17279,7 @@ type DraftChunkApproval struct { func (x *DraftChunkApproval) Reset() { *x = DraftChunkApproval{} - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[216] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17118,7 +17291,7 @@ func (x *DraftChunkApproval) String() string { func (*DraftChunkApproval) ProtoMessage() {} func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[216] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17131,7 +17304,7 @@ func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftChunkApproval.ProtoReflect.Descriptor instead. func (*DraftChunkApproval) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{214} + return file_openshell_proto_rawDescGZIP(), []int{216} } func (x *DraftChunkApproval) GetChunkId() string { @@ -17167,7 +17340,7 @@ type ApproveAllDraftChunksRequest struct { func (x *ApproveAllDraftChunksRequest) Reset() { *x = ApproveAllDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[217] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17179,7 +17352,7 @@ func (x *ApproveAllDraftChunksRequest) String() string { func (*ApproveAllDraftChunksRequest) ProtoMessage() {} func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[217] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17192,7 +17365,7 @@ func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{215} + return file_openshell_proto_rawDescGZIP(), []int{217} } func (x *ApproveAllDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17247,7 +17420,7 @@ type ApproveAllDraftChunksResponse struct { func (x *ApproveAllDraftChunksResponse) Reset() { *x = ApproveAllDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[218] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17259,7 +17432,7 @@ func (x *ApproveAllDraftChunksResponse) String() string { func (*ApproveAllDraftChunksResponse) ProtoMessage() {} func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[218] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17272,7 +17445,7 @@ func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{216} + return file_openshell_proto_rawDescGZIP(), []int{218} } func (x *ApproveAllDraftChunksResponse) GetPolicyVersion() uint32 { @@ -17322,7 +17495,7 @@ type EditDraftChunkRequest struct { func (x *EditDraftChunkRequest) Reset() { *x = EditDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[219] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17334,7 +17507,7 @@ func (x *EditDraftChunkRequest) String() string { func (*EditDraftChunkRequest) ProtoMessage() {} func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[219] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17347,7 +17520,7 @@ func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkRequest.ProtoReflect.Descriptor instead. func (*EditDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{217} + return file_openshell_proto_rawDescGZIP(), []int{219} } func (x *EditDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17393,7 +17566,7 @@ type EditDraftChunkResponse struct { func (x *EditDraftChunkResponse) Reset() { *x = EditDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[220] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17405,7 +17578,7 @@ func (x *EditDraftChunkResponse) String() string { func (*EditDraftChunkResponse) ProtoMessage() {} func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[220] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17418,7 +17591,7 @@ func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkResponse.ProtoReflect.Descriptor instead. func (*EditDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{218} + return file_openshell_proto_rawDescGZIP(), []int{220} } // Reverse an approval (remove merged rule from active policy). @@ -17438,7 +17611,7 @@ type UndoDraftChunkRequest struct { func (x *UndoDraftChunkRequest) Reset() { *x = UndoDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[221] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17450,7 +17623,7 @@ func (x *UndoDraftChunkRequest) String() string { func (*UndoDraftChunkRequest) ProtoMessage() {} func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[221] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17463,7 +17636,7 @@ func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkRequest.ProtoReflect.Descriptor instead. func (*UndoDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{219} + return file_openshell_proto_rawDescGZIP(), []int{221} } func (x *UndoDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17506,7 +17679,7 @@ type UndoDraftChunkResponse struct { func (x *UndoDraftChunkResponse) Reset() { *x = UndoDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[222] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17518,7 +17691,7 @@ func (x *UndoDraftChunkResponse) String() string { func (*UndoDraftChunkResponse) ProtoMessage() {} func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[222] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17531,7 +17704,7 @@ func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkResponse.ProtoReflect.Descriptor instead. func (*UndoDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{220} + return file_openshell_proto_rawDescGZIP(), []int{222} } func (x *UndoDraftChunkResponse) GetPolicyVersion() uint32 { @@ -17563,7 +17736,7 @@ type ClearDraftChunksRequest struct { func (x *ClearDraftChunksRequest) Reset() { *x = ClearDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[223] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17575,7 +17748,7 @@ func (x *ClearDraftChunksRequest) String() string { func (*ClearDraftChunksRequest) ProtoMessage() {} func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[223] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17588,7 +17761,7 @@ func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ClearDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{221} + return file_openshell_proto_rawDescGZIP(), []int{223} } func (x *ClearDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17622,7 +17795,7 @@ type ClearDraftChunksResponse struct { func (x *ClearDraftChunksResponse) Reset() { *x = ClearDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[224] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17634,7 +17807,7 @@ func (x *ClearDraftChunksResponse) String() string { func (*ClearDraftChunksResponse) ProtoMessage() {} func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[224] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17647,7 +17820,7 @@ func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ClearDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{222} + return file_openshell_proto_rawDescGZIP(), []int{224} } func (x *ClearDraftChunksResponse) GetChunksCleared() uint32 { @@ -17669,7 +17842,7 @@ type GetDraftHistoryRequest struct { func (x *GetDraftHistoryRequest) Reset() { *x = GetDraftHistoryRequest{} - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[225] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17681,7 +17854,7 @@ func (x *GetDraftHistoryRequest) String() string { func (*GetDraftHistoryRequest) ProtoMessage() {} func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[225] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17694,7 +17867,7 @@ func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryRequest.ProtoReflect.Descriptor instead. func (*GetDraftHistoryRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{223} + return file_openshell_proto_rawDescGZIP(), []int{225} } func (x *GetDraftHistoryRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17728,7 +17901,7 @@ type DraftHistoryEntry struct { func (x *DraftHistoryEntry) Reset() { *x = DraftHistoryEntry{} - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[226] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17740,7 +17913,7 @@ func (x *DraftHistoryEntry) String() string { func (*DraftHistoryEntry) ProtoMessage() {} func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[226] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17753,7 +17926,7 @@ func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftHistoryEntry.ProtoReflect.Descriptor instead. func (*DraftHistoryEntry) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{224} + return file_openshell_proto_rawDescGZIP(), []int{226} } func (x *DraftHistoryEntry) GetEventTime() *timestamppb.Timestamp { @@ -17794,7 +17967,7 @@ type GetDraftHistoryResponse struct { func (x *GetDraftHistoryResponse) Reset() { *x = GetDraftHistoryResponse{} - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[227] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17806,7 +17979,7 @@ func (x *GetDraftHistoryResponse) String() string { func (*GetDraftHistoryResponse) ProtoMessage() {} func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[227] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17819,7 +17992,7 @@ func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryResponse.ProtoReflect.Descriptor instead. func (*GetDraftHistoryResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{225} + return file_openshell_proto_rawDescGZIP(), []int{227} } func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry { @@ -17844,7 +18017,7 @@ type CreateWorkspaceRequest struct { func (x *CreateWorkspaceRequest) Reset() { *x = CreateWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[228] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17856,7 +18029,7 @@ func (x *CreateWorkspaceRequest) String() string { func (*CreateWorkspaceRequest) ProtoMessage() {} func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[228] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17869,7 +18042,7 @@ func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceRequest.ProtoReflect.Descriptor instead. func (*CreateWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{226} + return file_openshell_proto_rawDescGZIP(), []int{228} } func (x *CreateWorkspaceRequest) GetName() string { @@ -17903,7 +18076,7 @@ type CreateWorkspaceResponse struct { func (x *CreateWorkspaceResponse) Reset() { *x = CreateWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[229] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17915,7 +18088,7 @@ func (x *CreateWorkspaceResponse) String() string { func (*CreateWorkspaceResponse) ProtoMessage() {} func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[229] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17928,7 +18101,7 @@ func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceResponse.ProtoReflect.Descriptor instead. func (*CreateWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{227} + return file_openshell_proto_rawDescGZIP(), []int{229} } func (x *CreateWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -17949,7 +18122,7 @@ type GetWorkspaceRequest struct { func (x *GetWorkspaceRequest) Reset() { *x = GetWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[230] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17961,7 +18134,7 @@ func (x *GetWorkspaceRequest) String() string { func (*GetWorkspaceRequest) ProtoMessage() {} func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[230] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17974,7 +18147,7 @@ func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceRequest.ProtoReflect.Descriptor instead. func (*GetWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{228} + return file_openshell_proto_rawDescGZIP(), []int{230} } func (x *GetWorkspaceRequest) GetName() string { @@ -17994,7 +18167,7 @@ type GetWorkspaceResponse struct { func (x *GetWorkspaceResponse) Reset() { *x = GetWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[231] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18006,7 +18179,7 @@ func (x *GetWorkspaceResponse) String() string { func (*GetWorkspaceResponse) ProtoMessage() {} func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[231] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18019,7 +18192,7 @@ func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceResponse.ProtoReflect.Descriptor instead. func (*GetWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{229} + return file_openshell_proto_rawDescGZIP(), []int{231} } func (x *GetWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -18046,7 +18219,7 @@ type ListWorkspacesRequest struct { func (x *ListWorkspacesRequest) Reset() { *x = ListWorkspacesRequest{} - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[232] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18058,7 +18231,7 @@ func (x *ListWorkspacesRequest) String() string { func (*ListWorkspacesRequest) ProtoMessage() {} func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[232] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18071,7 +18244,7 @@ func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesRequest.ProtoReflect.Descriptor instead. func (*ListWorkspacesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{230} + return file_openshell_proto_rawDescGZIP(), []int{232} } func (x *ListWorkspacesRequest) GetPageSize() int32 { @@ -18107,7 +18280,7 @@ type ListWorkspacesResponse struct { func (x *ListWorkspacesResponse) Reset() { *x = ListWorkspacesResponse{} - mi := &file_openshell_proto_msgTypes[231] + mi := &file_openshell_proto_msgTypes[233] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18119,7 +18292,7 @@ func (x *ListWorkspacesResponse) String() string { func (*ListWorkspacesResponse) ProtoMessage() {} func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[231] + mi := &file_openshell_proto_msgTypes[233] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18132,7 +18305,7 @@ func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesResponse.ProtoReflect.Descriptor instead. func (*ListWorkspacesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{231} + return file_openshell_proto_rawDescGZIP(), []int{233} } func (x *ListWorkspacesResponse) GetWorkspaces() []*datamodelv1.Workspace { @@ -18163,7 +18336,7 @@ type DeleteWorkspaceRequest struct { func (x *DeleteWorkspaceRequest) Reset() { *x = DeleteWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[232] + mi := &file_openshell_proto_msgTypes[234] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18175,7 +18348,7 @@ func (x *DeleteWorkspaceRequest) String() string { func (*DeleteWorkspaceRequest) ProtoMessage() {} func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[232] + mi := &file_openshell_proto_msgTypes[234] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18188,7 +18361,7 @@ func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{232} + return file_openshell_proto_rawDescGZIP(), []int{234} } func (x *DeleteWorkspaceRequest) GetName() string { @@ -18222,7 +18395,7 @@ type DeleteWorkspaceResponse struct { func (x *DeleteWorkspaceResponse) Reset() { *x = DeleteWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[233] + mi := &file_openshell_proto_msgTypes[235] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18234,7 +18407,7 @@ func (x *DeleteWorkspaceResponse) String() string { func (*DeleteWorkspaceResponse) ProtoMessage() {} func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[233] + mi := &file_openshell_proto_msgTypes[235] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18247,7 +18420,7 @@ func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceResponse.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{233} + return file_openshell_proto_rawDescGZIP(), []int{235} } func (x *DeleteWorkspaceResponse) GetOutcome() DeletionOutcome { @@ -18271,7 +18444,7 @@ type WorkspaceMember struct { func (x *WorkspaceMember) Reset() { *x = WorkspaceMember{} - mi := &file_openshell_proto_msgTypes[234] + mi := &file_openshell_proto_msgTypes[236] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18283,7 +18456,7 @@ func (x *WorkspaceMember) String() string { func (*WorkspaceMember) ProtoMessage() {} func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[234] + mi := &file_openshell_proto_msgTypes[236] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18296,7 +18469,7 @@ func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkspaceMember.ProtoReflect.Descriptor instead. func (*WorkspaceMember) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{234} + return file_openshell_proto_rawDescGZIP(), []int{236} } func (x *WorkspaceMember) GetMetadata() *datamodelv1.ObjectMeta { @@ -18337,7 +18510,7 @@ type AddWorkspaceMemberRequest struct { func (x *AddWorkspaceMemberRequest) Reset() { *x = AddWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[235] + mi := &file_openshell_proto_msgTypes[237] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18349,7 +18522,7 @@ func (x *AddWorkspaceMemberRequest) String() string { func (*AddWorkspaceMemberRequest) ProtoMessage() {} func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[235] + mi := &file_openshell_proto_msgTypes[237] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18362,7 +18535,7 @@ func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{235} + return file_openshell_proto_rawDescGZIP(), []int{237} } func (x *AddWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18403,7 +18576,7 @@ type AddWorkspaceMemberResponse struct { func (x *AddWorkspaceMemberResponse) Reset() { *x = AddWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[236] + mi := &file_openshell_proto_msgTypes[238] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18415,7 +18588,7 @@ func (x *AddWorkspaceMemberResponse) String() string { func (*AddWorkspaceMemberResponse) ProtoMessage() {} func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[236] + mi := &file_openshell_proto_msgTypes[238] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18428,7 +18601,7 @@ func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{236} + return file_openshell_proto_rawDescGZIP(), []int{238} } func (x *AddWorkspaceMemberResponse) GetMember() *WorkspaceMember { @@ -18454,7 +18627,7 @@ type RemoveWorkspaceMemberRequest struct { func (x *RemoveWorkspaceMemberRequest) Reset() { *x = RemoveWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[237] + mi := &file_openshell_proto_msgTypes[239] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18466,7 +18639,7 @@ func (x *RemoveWorkspaceMemberRequest) String() string { func (*RemoveWorkspaceMemberRequest) ProtoMessage() {} func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[237] + mi := &file_openshell_proto_msgTypes[239] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18479,7 +18652,7 @@ func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{237} + return file_openshell_proto_rawDescGZIP(), []int{239} } func (x *RemoveWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18520,7 +18693,7 @@ type RemoveWorkspaceMemberResponse struct { func (x *RemoveWorkspaceMemberResponse) Reset() { *x = RemoveWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[238] + mi := &file_openshell_proto_msgTypes[240] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18532,7 +18705,7 @@ func (x *RemoveWorkspaceMemberResponse) String() string { func (*RemoveWorkspaceMemberResponse) ProtoMessage() {} func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[238] + mi := &file_openshell_proto_msgTypes[240] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18545,7 +18718,7 @@ func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{238} + return file_openshell_proto_rawDescGZIP(), []int{240} } func (x *RemoveWorkspaceMemberResponse) GetOutcome() DeletionOutcome { @@ -18572,7 +18745,7 @@ type ListWorkspaceMembersRequest struct { func (x *ListWorkspaceMembersRequest) Reset() { *x = ListWorkspaceMembersRequest{} - mi := &file_openshell_proto_msgTypes[239] + mi := &file_openshell_proto_msgTypes[241] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18584,7 +18757,7 @@ func (x *ListWorkspaceMembersRequest) String() string { func (*ListWorkspaceMembersRequest) ProtoMessage() {} func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[239] + mi := &file_openshell_proto_msgTypes[241] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18597,7 +18770,7 @@ func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersRequest.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{239} + return file_openshell_proto_rawDescGZIP(), []int{241} } func (x *ListWorkspaceMembersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18633,7 +18806,7 @@ type ListWorkspaceMembersResponse struct { func (x *ListWorkspaceMembersResponse) Reset() { *x = ListWorkspaceMembersResponse{} - mi := &file_openshell_proto_msgTypes[240] + mi := &file_openshell_proto_msgTypes[242] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18645,7 +18818,7 @@ func (x *ListWorkspaceMembersResponse) String() string { func (*ListWorkspaceMembersResponse) ProtoMessage() {} func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[240] + mi := &file_openshell_proto_msgTypes[242] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18658,7 +18831,7 @@ func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersResponse.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{240} + return file_openshell_proto_rawDescGZIP(), []int{242} } func (x *ListWorkspaceMembersResponse) GetMembers() []*WorkspaceMember { @@ -18693,7 +18866,7 @@ type ExtensionServiceCredential struct { func (x *ExtensionServiceCredential) Reset() { *x = ExtensionServiceCredential{} - mi := &file_openshell_proto_msgTypes[241] + mi := &file_openshell_proto_msgTypes[243] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18705,7 +18878,7 @@ func (x *ExtensionServiceCredential) String() string { func (*ExtensionServiceCredential) ProtoMessage() {} func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[241] + mi := &file_openshell_proto_msgTypes[243] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18718,7 +18891,7 @@ func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionServiceCredential.ProtoReflect.Descriptor instead. func (*ExtensionServiceCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{241} + return file_openshell_proto_rawDescGZIP(), []int{243} } func (x *ExtensionServiceCredential) GetServiceName() string { @@ -18758,7 +18931,7 @@ type EndpointObservation struct { func (x *EndpointObservation) Reset() { *x = EndpointObservation{} - mi := &file_openshell_proto_msgTypes[242] + mi := &file_openshell_proto_msgTypes[244] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18770,7 +18943,7 @@ func (x *EndpointObservation) String() string { func (*EndpointObservation) ProtoMessage() {} func (x *EndpointObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[242] + mi := &file_openshell_proto_msgTypes[244] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18783,7 +18956,7 @@ func (x *EndpointObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointObservation.ProtoReflect.Descriptor instead. func (*EndpointObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{242} + return file_openshell_proto_rawDescGZIP(), []int{244} } func (x *EndpointObservation) GetEndpointId() string { @@ -18836,7 +19009,7 @@ type ReportEndpointStatusRequest struct { func (x *ReportEndpointStatusRequest) Reset() { *x = ReportEndpointStatusRequest{} - mi := &file_openshell_proto_msgTypes[243] + mi := &file_openshell_proto_msgTypes[245] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18848,7 +19021,7 @@ func (x *ReportEndpointStatusRequest) String() string { func (*ReportEndpointStatusRequest) ProtoMessage() {} func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[243] + mi := &file_openshell_proto_msgTypes[245] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18861,7 +19034,7 @@ func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusRequest.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{243} + return file_openshell_proto_rawDescGZIP(), []int{245} } func (x *ReportEndpointStatusRequest) GetSandboxId() string { @@ -18930,7 +19103,7 @@ type TokenGrantStatus struct { func (x *TokenGrantStatus) Reset() { *x = TokenGrantStatus{} - mi := &file_openshell_proto_msgTypes[244] + mi := &file_openshell_proto_msgTypes[246] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18942,7 +19115,7 @@ func (x *TokenGrantStatus) String() string { func (*TokenGrantStatus) ProtoMessage() {} func (x *TokenGrantStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[244] + mi := &file_openshell_proto_msgTypes[246] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18955,7 +19128,7 @@ func (x *TokenGrantStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use TokenGrantStatus.ProtoReflect.Descriptor instead. func (*TokenGrantStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{244} + return file_openshell_proto_rawDescGZIP(), []int{246} } func (x *TokenGrantStatus) GetLastFailure() *TokenGrantFailureObservation { @@ -18982,7 +19155,7 @@ type TokenGrantFailureObservation struct { func (x *TokenGrantFailureObservation) Reset() { *x = TokenGrantFailureObservation{} - mi := &file_openshell_proto_msgTypes[245] + mi := &file_openshell_proto_msgTypes[247] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18994,7 +19167,7 @@ func (x *TokenGrantFailureObservation) String() string { func (*TokenGrantFailureObservation) ProtoMessage() {} func (x *TokenGrantFailureObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[245] + mi := &file_openshell_proto_msgTypes[247] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19007,7 +19180,7 @@ func (x *TokenGrantFailureObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use TokenGrantFailureObservation.ProtoReflect.Descriptor instead. func (*TokenGrantFailureObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{245} + return file_openshell_proto_rawDescGZIP(), []int{247} } func (x *TokenGrantFailureObservation) GetDestinationHost() string { @@ -19040,7 +19213,7 @@ type ReportEndpointStatusResponse struct { func (x *ReportEndpointStatusResponse) Reset() { *x = ReportEndpointStatusResponse{} - mi := &file_openshell_proto_msgTypes[246] + mi := &file_openshell_proto_msgTypes[248] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19052,7 +19225,7 @@ func (x *ReportEndpointStatusResponse) String() string { func (*ReportEndpointStatusResponse) ProtoMessage() {} func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[246] + mi := &file_openshell_proto_msgTypes[248] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19065,7 +19238,7 @@ func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusResponse.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{246} + return file_openshell_proto_rawDescGZIP(), []int{248} } // A configured endpoint and its last accepted network result in one record. @@ -19099,7 +19272,7 @@ type EndpointStatus struct { func (x *EndpointStatus) Reset() { *x = EndpointStatus{} - mi := &file_openshell_proto_msgTypes[247] + mi := &file_openshell_proto_msgTypes[249] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19111,7 +19284,7 @@ func (x *EndpointStatus) String() string { func (*EndpointStatus) ProtoMessage() {} func (x *EndpointStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[247] + mi := &file_openshell_proto_msgTypes[249] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19124,7 +19297,7 @@ func (x *EndpointStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointStatus.ProtoReflect.Descriptor instead. func (*EndpointStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{247} + return file_openshell_proto_rawDescGZIP(), []int{249} } func (x *EndpointStatus) GetEndpointId() string { @@ -19219,7 +19392,7 @@ type SandboxProvisioning struct { func (x *SandboxProvisioning) Reset() { *x = SandboxProvisioning{} - mi := &file_openshell_proto_msgTypes[248] + mi := &file_openshell_proto_msgTypes[250] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19231,7 +19404,7 @@ func (x *SandboxProvisioning) String() string { func (*SandboxProvisioning) ProtoMessage() {} func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[248] + mi := &file_openshell_proto_msgTypes[250] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19244,7 +19417,7 @@ func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxProvisioning.ProtoReflect.Descriptor instead. func (*SandboxProvisioning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{248} + return file_openshell_proto_rawDescGZIP(), []int{250} } func (x *SandboxProvisioning) GetAttemptId() string { @@ -19367,7 +19540,7 @@ type SandboxServiceExposure struct { func (x *SandboxServiceExposure) Reset() { *x = SandboxServiceExposure{} - mi := &file_openshell_proto_msgTypes[249] + mi := &file_openshell_proto_msgTypes[251] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19379,7 +19552,7 @@ func (x *SandboxServiceExposure) String() string { func (*SandboxServiceExposure) ProtoMessage() {} func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[249] + mi := &file_openshell_proto_msgTypes[251] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19392,7 +19565,7 @@ func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxServiceExposure.ProtoReflect.Descriptor instead. func (*SandboxServiceExposure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{249} + return file_openshell_proto_rawDescGZIP(), []int{251} } func (x *SandboxServiceExposure) GetService() string { @@ -19446,7 +19619,7 @@ type EndpointFailure struct { func (x *EndpointFailure) Reset() { *x = EndpointFailure{} - mi := &file_openshell_proto_msgTypes[250] + mi := &file_openshell_proto_msgTypes[252] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19458,7 +19631,7 @@ func (x *EndpointFailure) String() string { func (*EndpointFailure) ProtoMessage() {} func (x *EndpointFailure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[250] + mi := &file_openshell_proto_msgTypes[252] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19471,7 +19644,7 @@ func (x *EndpointFailure) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointFailure.ProtoReflect.Descriptor instead. func (*EndpointFailure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{250} + return file_openshell_proto_rawDescGZIP(), []int{252} } func (x *EndpointFailure) GetDomain() EndpointFailureDomain { @@ -19671,7 +19844,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\"\xde\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" + @@ -19692,10 +19865,17 @@ 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\x12C\n" + + "\fimage_update\x18\x12 \x01(\v2 .openshell.v1.SandboxImageUpdateR\vimageUpdate\x12%\n" + + "\x0eimage_revision\x18\x13 \x01(\x04R\rimageRevisionB\f\n" + "\n" + "_exit_codeB\x1a\n" + - "\x18_configuration_activated\"\xd1\x01\n" + + "\x18_configuration_activated\"\x90\x01\n" + + "\x12SandboxImageUpdate\x12!\n" + + "\foperation_id\x18\x01 \x01(\tR\voperationId\x12%\n" + + "\x0eprevious_image\x18\x02 \x01(\tR\rpreviousImage\x12\x14\n" + + "\x05image\x18\x03 \x01(\tR\x05image\x12\x1a\n" + + "\brevision\x18\x04 \x01(\x04R\brevision\"\xd1\x01\n" + "\x10SandboxCondition\x12\x12\n" + "\x04type\x18\x01 \x01(\tR\x04type\x12\x16\n" + "\x06status\x18\x02 \x01(\tR\x06status\x12\x16\n" + @@ -19729,7 +19909,14 @@ const file_openshell_proto_rawDesc = "" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a>\n" + "\x10AnnotationsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xd4\x01\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xef\x01\n" + + "\x14UpdateSandboxRequest\x12R\n" + + "\x0fworkspace_scope\x18\x01 \x01(\v2).openshell.datamodel.v1.WorkspaceSelectorR\x0eworkspaceScope\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" + + "\x05image\x18\x03 \x01(\tR\x05image\x12:\n" + + "\x19expected_resource_version\x18\x04 \x01(\x04R\x17expectedResourceVersion\x12\x1d\n" + + "\n" + + "request_id\x18\x05 \x01(\tR\trequestId\"\xd4\x01\n" + "\x1cCreateSandboxTemplateRequest\x12R\n" + "\x0fworkspace_scope\x18\x02 \x01(\v2).openshell.datamodel.v1.WorkspaceSelectorR\x0eworkspaceScope\x12A\n" + "\btemplate\x18\x01 \x01(\v2%.openshell.v1.SandboxWorkloadTemplateR\btemplate\x12\x1d\n" + @@ -21144,7 +21331,7 @@ const file_openshell_proto_rawDesc = "" + "-SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH\x10\x02*i\n" + "\x15EndpointFailureDomain\x12'\n" + "#ENDPOINT_FAILURE_DOMAIN_UNSPECIFIED\x10\x00\x12'\n" + - "#ENDPOINT_FAILURE_DOMAIN_TOKEN_GRANT\x10\x012\xa6Y\n" + + "#ENDPOINT_FAILURE_DOMAIN_TOKEN_GRANT\x10\x012\x9dZ\n" + "\tOpenShell\x12Z\n" + "\x06Health\x12\x1b.openshell.v1.HealthRequest\x1a\x1c.openshell.v1.HealthResponse\"\x15\x82\xb5\x18\x11\n" + "\x0funauthenticated\x12i\n" + @@ -21153,6 +21340,8 @@ const file_openshell_proto_rawDesc = "" + "\x0eGetGatewayInfo\x12#.openshell.v1.GetGatewayInfoRequest\x1a$.openshell.v1.GetGatewayInfoResponse\")\x82\xb5\x18%\n" + "\x06bearer\x1a\x0eplatform_admin\"\vconfig:read\x12u\n" + "\rCreateSandbox\x12\".openshell.v1.CreateSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\"!\x82\xb5\x18\x1d\n" + + "\x06bearer\x12\x04user\"\rsandbox:write\x12u\n" + + "\rUpdateSandbox\x12\".openshell.v1.UpdateSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\"!\x82\xb5\x18\x1d\n" + "\x06bearer\x12\x04user\"\rsandbox:write\x12\x93\x01\n" + "\x15BeginRootfsTarStaging\x12*.openshell.v1.BeginRootfsTarStagingRequest\x1a+.openshell.v1.BeginRootfsTarStagingResponse\"!\x82\xb5\x18\x1d\n" + "\x06bearer\x12\x04user\"\rsandbox:write\x12n\n" + @@ -21341,7 +21530,7 @@ func file_openshell_proto_rawDescGZIP() []byte { } var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 22) -var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 277) +var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 279) var file_openshell_proto_goTypes = []any{ (ExtensionKind)(0), // 0: openshell.v1.ExtensionKind (SandboxPhase)(0), // 1: openshell.v1.SandboxPhase @@ -21395,279 +21584,281 @@ var file_openshell_proto_goTypes = []any{ (*SandboxStartup)(nil), // 49: openshell.v1.SandboxStartup (*SandboxWorkloadTemplateProvenance)(nil), // 50: openshell.v1.SandboxWorkloadTemplateProvenance (*SandboxStatus)(nil), // 51: openshell.v1.SandboxStatus - (*SandboxCondition)(nil), // 52: openshell.v1.SandboxCondition - (*PlatformEvent)(nil), // 53: openshell.v1.PlatformEvent - (*CreateSandboxRequest)(nil), // 54: openshell.v1.CreateSandboxRequest - (*CreateSandboxTemplateRequest)(nil), // 55: openshell.v1.CreateSandboxTemplateRequest - (*GetSandboxTemplateRequest)(nil), // 56: openshell.v1.GetSandboxTemplateRequest - (*ListSandboxTemplatesRequest)(nil), // 57: openshell.v1.ListSandboxTemplatesRequest - (*DeleteSandboxTemplateRequest)(nil), // 58: openshell.v1.DeleteSandboxTemplateRequest - (*SandboxTemplateResponse)(nil), // 59: openshell.v1.SandboxTemplateResponse - (*ListSandboxTemplatesResponse)(nil), // 60: openshell.v1.ListSandboxTemplatesResponse - (*DeleteSandboxTemplateResponse)(nil), // 61: openshell.v1.DeleteSandboxTemplateResponse - (*BeginRootfsTarStagingRequest)(nil), // 62: openshell.v1.BeginRootfsTarStagingRequest - (*BeginRootfsTarStagingResponse)(nil), // 63: openshell.v1.BeginRootfsTarStagingResponse - (*GetSandboxRequest)(nil), // 64: openshell.v1.GetSandboxRequest - (*ListSandboxesRequest)(nil), // 65: openshell.v1.ListSandboxesRequest - (*ListSandboxProvidersRequest)(nil), // 66: openshell.v1.ListSandboxProvidersRequest - (*AttachSandboxProviderRequest)(nil), // 67: openshell.v1.AttachSandboxProviderRequest - (*DetachSandboxProviderRequest)(nil), // 68: openshell.v1.DetachSandboxProviderRequest - (*DeleteSandboxRequest)(nil), // 69: openshell.v1.DeleteSandboxRequest - (*StopSandboxRequest)(nil), // 70: openshell.v1.StopSandboxRequest - (*StartSandboxRequest)(nil), // 71: openshell.v1.StartSandboxRequest - (*SuspendSandboxRequest)(nil), // 72: openshell.v1.SuspendSandboxRequest - (*ResumeSandboxRequest)(nil), // 73: openshell.v1.ResumeSandboxRequest - (*SandboxResponse)(nil), // 74: openshell.v1.SandboxResponse - (*ListSandboxesResponse)(nil), // 75: openshell.v1.ListSandboxesResponse - (*ListSandboxProvidersResponse)(nil), // 76: openshell.v1.ListSandboxProvidersResponse - (*AttachSandboxProviderResponse)(nil), // 77: openshell.v1.AttachSandboxProviderResponse - (*DetachSandboxProviderResponse)(nil), // 78: openshell.v1.DetachSandboxProviderResponse - (*ProviderDesiredIdentity)(nil), // 79: openshell.v1.ProviderDesiredIdentity - (*ConfigSnapshotRevision)(nil), // 80: openshell.v1.ConfigSnapshotRevision - (*SandboxConfigRevision)(nil), // 81: openshell.v1.SandboxConfigRevision - (*ConfigUpdateOperation)(nil), // 82: openshell.v1.ConfigUpdateOperation - (*ProviderMutationReceipt)(nil), // 83: openshell.v1.ProviderMutationReceipt - (*ProviderReadinessObservation)(nil), // 84: openshell.v1.ProviderReadinessObservation - (*ProviderReadinessStatus)(nil), // 85: openshell.v1.ProviderReadinessStatus - (*GetSandboxProviderStatusRequest)(nil), // 86: openshell.v1.GetSandboxProviderStatusRequest - (*GetSandboxProviderStatusResponse)(nil), // 87: openshell.v1.GetSandboxProviderStatusResponse - (*ReportProviderReadinessRequest)(nil), // 88: openshell.v1.ReportProviderReadinessRequest - (*ReportProviderReadinessResponse)(nil), // 89: openshell.v1.ReportProviderReadinessResponse - (*DeleteSandboxResponse)(nil), // 90: openshell.v1.DeleteSandboxResponse - (*CreateSshSessionRequest)(nil), // 91: openshell.v1.CreateSshSessionRequest - (*CreateSshSessionResponse)(nil), // 92: openshell.v1.CreateSshSessionResponse - (*ExposeServiceRequest)(nil), // 93: openshell.v1.ExposeServiceRequest - (*GetServiceRequest)(nil), // 94: openshell.v1.GetServiceRequest - (*ListServicesRequest)(nil), // 95: openshell.v1.ListServicesRequest - (*ListServicesResponse)(nil), // 96: openshell.v1.ListServicesResponse - (*DeleteServiceRequest)(nil), // 97: openshell.v1.DeleteServiceRequest - (*DeleteServiceResponse)(nil), // 98: openshell.v1.DeleteServiceResponse - (*ServiceEndpoint)(nil), // 99: openshell.v1.ServiceEndpoint - (*ServiceEndpointResponse)(nil), // 100: openshell.v1.ServiceEndpointResponse - (*RevokeSshSessionRequest)(nil), // 101: openshell.v1.RevokeSshSessionRequest - (*RevokeSshSessionResponse)(nil), // 102: openshell.v1.RevokeSshSessionResponse - (*ExecSandboxRequest)(nil), // 103: openshell.v1.ExecSandboxRequest - (*ExecSandboxStdout)(nil), // 104: openshell.v1.ExecSandboxStdout - (*ExecSandboxStderr)(nil), // 105: openshell.v1.ExecSandboxStderr - (*ExecSandboxExit)(nil), // 106: openshell.v1.ExecSandboxExit - (*ExecSandboxEvent)(nil), // 107: openshell.v1.ExecSandboxEvent - (*TcpForwardInit)(nil), // 108: openshell.v1.TcpForwardInit - (*TcpForwardFrame)(nil), // 109: openshell.v1.TcpForwardFrame - (*ExecSandboxInput)(nil), // 110: openshell.v1.ExecSandboxInput - (*ExecSandboxWindowResize)(nil), // 111: openshell.v1.ExecSandboxWindowResize - (*SshSession)(nil), // 112: openshell.v1.SshSession - (*WatchSandboxRequest)(nil), // 113: openshell.v1.WatchSandboxRequest - (*SandboxStreamEvent)(nil), // 114: openshell.v1.SandboxStreamEvent - (*SandboxLogLine)(nil), // 115: openshell.v1.SandboxLogLine - (*SandboxStreamWarning)(nil), // 116: openshell.v1.SandboxStreamWarning - (*CreateProviderRequest)(nil), // 117: openshell.v1.CreateProviderRequest - (*GetProviderRequest)(nil), // 118: openshell.v1.GetProviderRequest - (*GetProviderCredentialsRequest)(nil), // 119: openshell.v1.GetProviderCredentialsRequest - (*ProviderCredentialValue)(nil), // 120: openshell.v1.ProviderCredentialValue - (*GetProviderCredentialsResponse)(nil), // 121: openshell.v1.GetProviderCredentialsResponse - (*ListProvidersRequest)(nil), // 122: openshell.v1.ListProvidersRequest - (*UpdateProviderRequest)(nil), // 123: openshell.v1.UpdateProviderRequest - (*DeleteProviderRequest)(nil), // 124: openshell.v1.DeleteProviderRequest - (*ProviderResponse)(nil), // 125: openshell.v1.ProviderResponse - (*ListProvidersResponse)(nil), // 126: openshell.v1.ListProvidersResponse - (*ListProviderProfilesRequest)(nil), // 127: openshell.v1.ListProviderProfilesRequest - (*GetProviderProfileRequest)(nil), // 128: openshell.v1.GetProviderProfileRequest - (*ProviderProfileImportItem)(nil), // 129: openshell.v1.ProviderProfileImportItem - (*ProviderProfileDiagnostic)(nil), // 130: openshell.v1.ProviderProfileDiagnostic - (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 131: openshell.v1.ProviderCredentialTokenGrantAudienceOverride - (*ProviderCredentialTokenGrantSubjectToken)(nil), // 132: openshell.v1.ProviderCredentialTokenGrantSubjectToken - (*ProviderCredentialTokenGrant)(nil), // 133: openshell.v1.ProviderCredentialTokenGrant - (*ProviderProfileCredential)(nil), // 134: openshell.v1.ProviderProfileCredential - (*ProviderCredentialRefreshMaterial)(nil), // 135: openshell.v1.ProviderCredentialRefreshMaterial - (*ProviderCredentialRefreshOutput)(nil), // 136: openshell.v1.ProviderCredentialRefreshOutput - (*ProviderCredentialRefresh)(nil), // 137: openshell.v1.ProviderCredentialRefresh - (*ProviderCredentialRefreshStatus)(nil), // 138: openshell.v1.ProviderCredentialRefreshStatus - (*ProviderProfileDiscovery)(nil), // 139: openshell.v1.ProviderProfileDiscovery - (*GetProviderRefreshStatusRequest)(nil), // 140: openshell.v1.GetProviderRefreshStatusRequest - (*GetProviderRefreshStatusResponse)(nil), // 141: openshell.v1.GetProviderRefreshStatusResponse - (*ConfigureProviderRefreshRequest)(nil), // 142: openshell.v1.ConfigureProviderRefreshRequest - (*ConfigureProviderRefreshResponse)(nil), // 143: openshell.v1.ConfigureProviderRefreshResponse - (*RotateProviderCredentialRequest)(nil), // 144: openshell.v1.RotateProviderCredentialRequest - (*RotateProviderCredentialResponse)(nil), // 145: openshell.v1.RotateProviderCredentialResponse - (*DeleteProviderRefreshRequest)(nil), // 146: openshell.v1.DeleteProviderRefreshRequest - (*DeleteProviderRefreshResponse)(nil), // 147: openshell.v1.DeleteProviderRefreshResponse - (*ProviderProfile)(nil), // 148: openshell.v1.ProviderProfile - (*ProviderProfileFile)(nil), // 149: openshell.v1.ProviderProfileFile - (*ProviderProfileResponse)(nil), // 150: openshell.v1.ProviderProfileResponse - (*ListProviderProfilesResponse)(nil), // 151: openshell.v1.ListProviderProfilesResponse - (*ImportProviderProfilesRequest)(nil), // 152: openshell.v1.ImportProviderProfilesRequest - (*ImportProviderProfilesResponse)(nil), // 153: openshell.v1.ImportProviderProfilesResponse - (*UpdateProviderProfilesRequest)(nil), // 154: openshell.v1.UpdateProviderProfilesRequest - (*UpdateProviderProfilesResponse)(nil), // 155: openshell.v1.UpdateProviderProfilesResponse - (*LintProviderProfilesRequest)(nil), // 156: openshell.v1.LintProviderProfilesRequest - (*LintProviderProfilesResponse)(nil), // 157: openshell.v1.LintProviderProfilesResponse - (*DeleteProviderResponse)(nil), // 158: openshell.v1.DeleteProviderResponse - (*DeleteProviderProfileRequest)(nil), // 159: openshell.v1.DeleteProviderProfileRequest - (*DeleteProviderProfileResponse)(nil), // 160: openshell.v1.DeleteProviderProfileResponse - (*GetSandboxProviderEnvironmentRequest)(nil), // 161: openshell.v1.GetSandboxProviderEnvironmentRequest - (*StaticCredentialEndpointBinding)(nil), // 162: openshell.v1.StaticCredentialEndpointBinding - (*StaticCredentialBinding)(nil), // 163: openshell.v1.StaticCredentialBinding - (*GetSandboxProviderEnvironmentResponse)(nil), // 164: openshell.v1.GetSandboxProviderEnvironmentResponse - (*ProviderEnvironmentValue)(nil), // 165: openshell.v1.ProviderEnvironmentValue - (*ProviderEnvironmentSnapshot)(nil), // 166: openshell.v1.ProviderEnvironmentSnapshot - (*ExchangeProviderSubjectTokenRequest)(nil), // 167: openshell.v1.ExchangeProviderSubjectTokenRequest - (*ExchangeProviderSubjectTokenResponse)(nil), // 168: openshell.v1.ExchangeProviderSubjectTokenResponse - (*UpdateConfigRequest)(nil), // 169: openshell.v1.UpdateConfigRequest - (*PolicyMergeOperation)(nil), // 170: openshell.v1.PolicyMergeOperation - (*AddNetworkRule)(nil), // 171: openshell.v1.AddNetworkRule - (*RemoveNetworkEndpoint)(nil), // 172: openshell.v1.RemoveNetworkEndpoint - (*RemoveNetworkRule)(nil), // 173: openshell.v1.RemoveNetworkRule - (*L7RuleTarget)(nil), // 174: openshell.v1.L7RuleTarget - (*AddDenyRules)(nil), // 175: openshell.v1.AddDenyRules - (*AddAllowRules)(nil), // 176: openshell.v1.AddAllowRules - (*RemoveNetworkBinary)(nil), // 177: openshell.v1.RemoveNetworkBinary - (*UpdateConfigResponse)(nil), // 178: openshell.v1.UpdateConfigResponse - (*GetSandboxPolicyStatusRequest)(nil), // 179: openshell.v1.GetSandboxPolicyStatusRequest - (*GetSandboxPolicyStatusResponse)(nil), // 180: openshell.v1.GetSandboxPolicyStatusResponse - (*ListSandboxPoliciesRequest)(nil), // 181: openshell.v1.ListSandboxPoliciesRequest - (*ListSandboxPoliciesResponse)(nil), // 182: openshell.v1.ListSandboxPoliciesResponse - (*ReportPolicyStatusRequest)(nil), // 183: openshell.v1.ReportPolicyStatusRequest - (*ReportPolicyStatusResponse)(nil), // 184: openshell.v1.ReportPolicyStatusResponse - (*SandboxConfigurationAdmission)(nil), // 185: openshell.v1.SandboxConfigurationAdmission - (*ReportSandboxConfigurationRequest)(nil), // 186: openshell.v1.ReportSandboxConfigurationRequest - (*ReportSandboxConfigurationResponse)(nil), // 187: openshell.v1.ReportSandboxConfigurationResponse - (*SandboxPolicyRevision)(nil), // 188: openshell.v1.SandboxPolicyRevision - (*GetSandboxLogsRequest)(nil), // 189: openshell.v1.GetSandboxLogsRequest - (*PushSandboxLogsRequest)(nil), // 190: openshell.v1.PushSandboxLogsRequest - (*PushSandboxLogsResponse)(nil), // 191: openshell.v1.PushSandboxLogsResponse - (*GetSandboxLogsResponse)(nil), // 192: openshell.v1.GetSandboxLogsResponse - (*SupervisorMessage)(nil), // 193: openshell.v1.SupervisorMessage - (*GatewayMessage)(nil), // 194: openshell.v1.GatewayMessage - (*SupervisorHello)(nil), // 195: openshell.v1.SupervisorHello - (*SessionAccepted)(nil), // 196: openshell.v1.SessionAccepted - (*ConfigUpdate)(nil), // 197: openshell.v1.ConfigUpdate - (*ConfigApplyFailure)(nil), // 198: openshell.v1.ConfigApplyFailure - (*ConfigUpdateResult)(nil), // 199: openshell.v1.ConfigUpdateResult - (*PolicyLoadResult)(nil), // 200: openshell.v1.PolicyLoadResult - (*SessionRejected)(nil), // 201: openshell.v1.SessionRejected - (*SessionRedirect)(nil), // 202: openshell.v1.SessionRedirect - (*SupervisorHeartbeat)(nil), // 203: openshell.v1.SupervisorHeartbeat - (*GatewayHeartbeat)(nil), // 204: openshell.v1.GatewayHeartbeat - (*ReportMainProcessExitRequest)(nil), // 205: openshell.v1.ReportMainProcessExitRequest - (*ReportMainProcessExitResponse)(nil), // 206: openshell.v1.ReportMainProcessExitResponse - (*FinalizeMainProcessExitRequest)(nil), // 207: openshell.v1.FinalizeMainProcessExitRequest - (*FinalizeMainProcessExitResponse)(nil), // 208: openshell.v1.FinalizeMainProcessExitResponse - (*RelayOpen)(nil), // 209: openshell.v1.RelayOpen - (*SshRelayTarget)(nil), // 210: openshell.v1.SshRelayTarget - (*TcpRelayTarget)(nil), // 211: openshell.v1.TcpRelayTarget - (*RelayInit)(nil), // 212: openshell.v1.RelayInit - (*RelayFrame)(nil), // 213: openshell.v1.RelayFrame - (*PeerRelayInit)(nil), // 214: openshell.v1.PeerRelayInit - (*PeerRelayFrame)(nil), // 215: openshell.v1.PeerRelayFrame - (*PeerConfigSandboxTarget)(nil), // 216: openshell.v1.PeerConfigSandboxTarget - (*PeerConfigProviderTarget)(nil), // 217: openshell.v1.PeerConfigProviderTarget - (*PeerNotifyConfigUpdateRequest)(nil), // 218: openshell.v1.PeerNotifyConfigUpdateRequest - (*PeerNotifyConfigUpdateResponse)(nil), // 219: openshell.v1.PeerNotifyConfigUpdateResponse - (*RelayOpenResult)(nil), // 220: openshell.v1.RelayOpenResult - (*RelayClose)(nil), // 221: openshell.v1.RelayClose - (*L7RequestSample)(nil), // 222: openshell.v1.L7RequestSample - (*DenialSummary)(nil), // 223: openshell.v1.DenialSummary - (*DenialGroupCount)(nil), // 224: openshell.v1.DenialGroupCount - (*NetworkActivitySummary)(nil), // 225: openshell.v1.NetworkActivitySummary - (*PolicyChunk)(nil), // 226: openshell.v1.PolicyChunk - (*DraftPolicyUpdate)(nil), // 227: openshell.v1.DraftPolicyUpdate - (*SubmitPolicyAnalysisRequest)(nil), // 228: openshell.v1.SubmitPolicyAnalysisRequest - (*SubmitPolicyAnalysisResponse)(nil), // 229: openshell.v1.SubmitPolicyAnalysisResponse - (*GetDraftPolicyRequest)(nil), // 230: openshell.v1.GetDraftPolicyRequest - (*GetDraftPolicyResponse)(nil), // 231: openshell.v1.GetDraftPolicyResponse - (*ApproveDraftChunkRequest)(nil), // 232: openshell.v1.ApproveDraftChunkRequest - (*ApproveDraftChunkResponse)(nil), // 233: openshell.v1.ApproveDraftChunkResponse - (*RejectDraftChunkRequest)(nil), // 234: openshell.v1.RejectDraftChunkRequest - (*RejectDraftChunkResponse)(nil), // 235: openshell.v1.RejectDraftChunkResponse - (*DraftChunkApproval)(nil), // 236: openshell.v1.DraftChunkApproval - (*ApproveAllDraftChunksRequest)(nil), // 237: openshell.v1.ApproveAllDraftChunksRequest - (*ApproveAllDraftChunksResponse)(nil), // 238: openshell.v1.ApproveAllDraftChunksResponse - (*EditDraftChunkRequest)(nil), // 239: openshell.v1.EditDraftChunkRequest - (*EditDraftChunkResponse)(nil), // 240: openshell.v1.EditDraftChunkResponse - (*UndoDraftChunkRequest)(nil), // 241: openshell.v1.UndoDraftChunkRequest - (*UndoDraftChunkResponse)(nil), // 242: openshell.v1.UndoDraftChunkResponse - (*ClearDraftChunksRequest)(nil), // 243: openshell.v1.ClearDraftChunksRequest - (*ClearDraftChunksResponse)(nil), // 244: openshell.v1.ClearDraftChunksResponse - (*GetDraftHistoryRequest)(nil), // 245: openshell.v1.GetDraftHistoryRequest - (*DraftHistoryEntry)(nil), // 246: openshell.v1.DraftHistoryEntry - (*GetDraftHistoryResponse)(nil), // 247: openshell.v1.GetDraftHistoryResponse - (*CreateWorkspaceRequest)(nil), // 248: openshell.v1.CreateWorkspaceRequest - (*CreateWorkspaceResponse)(nil), // 249: openshell.v1.CreateWorkspaceResponse - (*GetWorkspaceRequest)(nil), // 250: openshell.v1.GetWorkspaceRequest - (*GetWorkspaceResponse)(nil), // 251: openshell.v1.GetWorkspaceResponse - (*ListWorkspacesRequest)(nil), // 252: openshell.v1.ListWorkspacesRequest - (*ListWorkspacesResponse)(nil), // 253: openshell.v1.ListWorkspacesResponse - (*DeleteWorkspaceRequest)(nil), // 254: openshell.v1.DeleteWorkspaceRequest - (*DeleteWorkspaceResponse)(nil), // 255: openshell.v1.DeleteWorkspaceResponse - (*WorkspaceMember)(nil), // 256: openshell.v1.WorkspaceMember - (*AddWorkspaceMemberRequest)(nil), // 257: openshell.v1.AddWorkspaceMemberRequest - (*AddWorkspaceMemberResponse)(nil), // 258: openshell.v1.AddWorkspaceMemberResponse - (*RemoveWorkspaceMemberRequest)(nil), // 259: openshell.v1.RemoveWorkspaceMemberRequest - (*RemoveWorkspaceMemberResponse)(nil), // 260: openshell.v1.RemoveWorkspaceMemberResponse - (*ListWorkspaceMembersRequest)(nil), // 261: openshell.v1.ListWorkspaceMembersRequest - (*ListWorkspaceMembersResponse)(nil), // 262: openshell.v1.ListWorkspaceMembersResponse - (*ExtensionServiceCredential)(nil), // 263: openshell.v1.ExtensionServiceCredential - (*EndpointObservation)(nil), // 264: openshell.v1.EndpointObservation - (*ReportEndpointStatusRequest)(nil), // 265: openshell.v1.ReportEndpointStatusRequest - (*TokenGrantStatus)(nil), // 266: openshell.v1.TokenGrantStatus - (*TokenGrantFailureObservation)(nil), // 267: openshell.v1.TokenGrantFailureObservation - (*ReportEndpointStatusResponse)(nil), // 268: openshell.v1.ReportEndpointStatusResponse - (*EndpointStatus)(nil), // 269: openshell.v1.EndpointStatus - (*SandboxProvisioning)(nil), // 270: openshell.v1.SandboxProvisioning - (*SandboxServiceExposure)(nil), // 271: openshell.v1.SandboxServiceExposure - (*EndpointFailure)(nil), // 272: openshell.v1.EndpointFailure - nil, // 273: openshell.v1.SandboxSpec.EnvironmentEntry - nil, // 274: openshell.v1.SandboxTemplate.LabelsEntry - nil, // 275: openshell.v1.SandboxTemplate.AnnotationsEntry - nil, // 276: openshell.v1.SandboxTemplate.EnvironmentEntry - nil, // 277: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - nil, // 278: openshell.v1.PlatformEvent.MetadataEntry - nil, // 279: openshell.v1.CreateSandboxRequest.LabelsEntry - nil, // 280: openshell.v1.CreateSandboxRequest.AnnotationsEntry - nil, // 281: openshell.v1.SandboxResponse.ServiceUrlsEntry - nil, // 282: openshell.v1.ExecSandboxRequest.EnvironmentEntry - nil, // 283: openshell.v1.SandboxLogLine.FieldsEntry - nil, // 284: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry - nil, // 285: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - nil, // 286: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - nil, // 287: openshell.v1.ProviderProfile.AnnotationsEntry - nil, // 288: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - nil, // 289: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - nil, // 290: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - nil, // 291: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - nil, // 292: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - nil, // 293: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry - nil, // 294: openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - nil, // 295: openshell.v1.UpdateConfigRequest.AnnotationsEntry - nil, // 296: openshell.v1.UpdateConfigResponse.AnnotationsEntry - nil, // 297: openshell.v1.SandboxPolicyRevision.ProvenanceEntry - nil, // 298: openshell.v1.CreateWorkspaceRequest.LabelsEntry - (*timestamppb.Timestamp)(nil), // 299: google.protobuf.Timestamp - (*datamodelv1.ObjectMeta)(nil), // 300: openshell.datamodel.v1.ObjectMeta - (*sandboxv1.SandboxPolicy)(nil), // 301: openshell.sandbox.v1.SandboxPolicy - (*structpb.Struct)(nil), // 302: google.protobuf.Struct - (*durationpb.Duration)(nil), // 303: google.protobuf.Duration - (*datamodelv1.WorkspaceSelector)(nil), // 304: openshell.datamodel.v1.WorkspaceSelector - (*datamodelv1.Provider)(nil), // 305: openshell.datamodel.v1.Provider - (sandboxv1.PolicySource)(0), // 306: openshell.sandbox.v1.PolicySource - (*sandboxv1.NetworkEndpoint)(nil), // 307: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 308: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 309: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 310: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 311: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 312: openshell.sandbox.v1.L7Rule - (*sandboxv1.SandboxConfigSnapshot)(nil), // 313: openshell.sandbox.v1.SandboxConfigSnapshot - (*datamodelv1.Workspace)(nil), // 314: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 315: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 316: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 317: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 318: openshell.sandbox.v1.GetGatewayConfigResponse + (*SandboxImageUpdate)(nil), // 52: openshell.v1.SandboxImageUpdate + (*SandboxCondition)(nil), // 53: openshell.v1.SandboxCondition + (*PlatformEvent)(nil), // 54: openshell.v1.PlatformEvent + (*CreateSandboxRequest)(nil), // 55: openshell.v1.CreateSandboxRequest + (*UpdateSandboxRequest)(nil), // 56: openshell.v1.UpdateSandboxRequest + (*CreateSandboxTemplateRequest)(nil), // 57: openshell.v1.CreateSandboxTemplateRequest + (*GetSandboxTemplateRequest)(nil), // 58: openshell.v1.GetSandboxTemplateRequest + (*ListSandboxTemplatesRequest)(nil), // 59: openshell.v1.ListSandboxTemplatesRequest + (*DeleteSandboxTemplateRequest)(nil), // 60: openshell.v1.DeleteSandboxTemplateRequest + (*SandboxTemplateResponse)(nil), // 61: openshell.v1.SandboxTemplateResponse + (*ListSandboxTemplatesResponse)(nil), // 62: openshell.v1.ListSandboxTemplatesResponse + (*DeleteSandboxTemplateResponse)(nil), // 63: openshell.v1.DeleteSandboxTemplateResponse + (*BeginRootfsTarStagingRequest)(nil), // 64: openshell.v1.BeginRootfsTarStagingRequest + (*BeginRootfsTarStagingResponse)(nil), // 65: openshell.v1.BeginRootfsTarStagingResponse + (*GetSandboxRequest)(nil), // 66: openshell.v1.GetSandboxRequest + (*ListSandboxesRequest)(nil), // 67: openshell.v1.ListSandboxesRequest + (*ListSandboxProvidersRequest)(nil), // 68: openshell.v1.ListSandboxProvidersRequest + (*AttachSandboxProviderRequest)(nil), // 69: openshell.v1.AttachSandboxProviderRequest + (*DetachSandboxProviderRequest)(nil), // 70: openshell.v1.DetachSandboxProviderRequest + (*DeleteSandboxRequest)(nil), // 71: openshell.v1.DeleteSandboxRequest + (*StopSandboxRequest)(nil), // 72: openshell.v1.StopSandboxRequest + (*StartSandboxRequest)(nil), // 73: openshell.v1.StartSandboxRequest + (*SuspendSandboxRequest)(nil), // 74: openshell.v1.SuspendSandboxRequest + (*ResumeSandboxRequest)(nil), // 75: openshell.v1.ResumeSandboxRequest + (*SandboxResponse)(nil), // 76: openshell.v1.SandboxResponse + (*ListSandboxesResponse)(nil), // 77: openshell.v1.ListSandboxesResponse + (*ListSandboxProvidersResponse)(nil), // 78: openshell.v1.ListSandboxProvidersResponse + (*AttachSandboxProviderResponse)(nil), // 79: openshell.v1.AttachSandboxProviderResponse + (*DetachSandboxProviderResponse)(nil), // 80: openshell.v1.DetachSandboxProviderResponse + (*ProviderDesiredIdentity)(nil), // 81: openshell.v1.ProviderDesiredIdentity + (*ConfigSnapshotRevision)(nil), // 82: openshell.v1.ConfigSnapshotRevision + (*SandboxConfigRevision)(nil), // 83: openshell.v1.SandboxConfigRevision + (*ConfigUpdateOperation)(nil), // 84: openshell.v1.ConfigUpdateOperation + (*ProviderMutationReceipt)(nil), // 85: openshell.v1.ProviderMutationReceipt + (*ProviderReadinessObservation)(nil), // 86: openshell.v1.ProviderReadinessObservation + (*ProviderReadinessStatus)(nil), // 87: openshell.v1.ProviderReadinessStatus + (*GetSandboxProviderStatusRequest)(nil), // 88: openshell.v1.GetSandboxProviderStatusRequest + (*GetSandboxProviderStatusResponse)(nil), // 89: openshell.v1.GetSandboxProviderStatusResponse + (*ReportProviderReadinessRequest)(nil), // 90: openshell.v1.ReportProviderReadinessRequest + (*ReportProviderReadinessResponse)(nil), // 91: openshell.v1.ReportProviderReadinessResponse + (*DeleteSandboxResponse)(nil), // 92: openshell.v1.DeleteSandboxResponse + (*CreateSshSessionRequest)(nil), // 93: openshell.v1.CreateSshSessionRequest + (*CreateSshSessionResponse)(nil), // 94: openshell.v1.CreateSshSessionResponse + (*ExposeServiceRequest)(nil), // 95: openshell.v1.ExposeServiceRequest + (*GetServiceRequest)(nil), // 96: openshell.v1.GetServiceRequest + (*ListServicesRequest)(nil), // 97: openshell.v1.ListServicesRequest + (*ListServicesResponse)(nil), // 98: openshell.v1.ListServicesResponse + (*DeleteServiceRequest)(nil), // 99: openshell.v1.DeleteServiceRequest + (*DeleteServiceResponse)(nil), // 100: openshell.v1.DeleteServiceResponse + (*ServiceEndpoint)(nil), // 101: openshell.v1.ServiceEndpoint + (*ServiceEndpointResponse)(nil), // 102: openshell.v1.ServiceEndpointResponse + (*RevokeSshSessionRequest)(nil), // 103: openshell.v1.RevokeSshSessionRequest + (*RevokeSshSessionResponse)(nil), // 104: openshell.v1.RevokeSshSessionResponse + (*ExecSandboxRequest)(nil), // 105: openshell.v1.ExecSandboxRequest + (*ExecSandboxStdout)(nil), // 106: openshell.v1.ExecSandboxStdout + (*ExecSandboxStderr)(nil), // 107: openshell.v1.ExecSandboxStderr + (*ExecSandboxExit)(nil), // 108: openshell.v1.ExecSandboxExit + (*ExecSandboxEvent)(nil), // 109: openshell.v1.ExecSandboxEvent + (*TcpForwardInit)(nil), // 110: openshell.v1.TcpForwardInit + (*TcpForwardFrame)(nil), // 111: openshell.v1.TcpForwardFrame + (*ExecSandboxInput)(nil), // 112: openshell.v1.ExecSandboxInput + (*ExecSandboxWindowResize)(nil), // 113: openshell.v1.ExecSandboxWindowResize + (*SshSession)(nil), // 114: openshell.v1.SshSession + (*WatchSandboxRequest)(nil), // 115: openshell.v1.WatchSandboxRequest + (*SandboxStreamEvent)(nil), // 116: openshell.v1.SandboxStreamEvent + (*SandboxLogLine)(nil), // 117: openshell.v1.SandboxLogLine + (*SandboxStreamWarning)(nil), // 118: openshell.v1.SandboxStreamWarning + (*CreateProviderRequest)(nil), // 119: openshell.v1.CreateProviderRequest + (*GetProviderRequest)(nil), // 120: openshell.v1.GetProviderRequest + (*GetProviderCredentialsRequest)(nil), // 121: openshell.v1.GetProviderCredentialsRequest + (*ProviderCredentialValue)(nil), // 122: openshell.v1.ProviderCredentialValue + (*GetProviderCredentialsResponse)(nil), // 123: openshell.v1.GetProviderCredentialsResponse + (*ListProvidersRequest)(nil), // 124: openshell.v1.ListProvidersRequest + (*UpdateProviderRequest)(nil), // 125: openshell.v1.UpdateProviderRequest + (*DeleteProviderRequest)(nil), // 126: openshell.v1.DeleteProviderRequest + (*ProviderResponse)(nil), // 127: openshell.v1.ProviderResponse + (*ListProvidersResponse)(nil), // 128: openshell.v1.ListProvidersResponse + (*ListProviderProfilesRequest)(nil), // 129: openshell.v1.ListProviderProfilesRequest + (*GetProviderProfileRequest)(nil), // 130: openshell.v1.GetProviderProfileRequest + (*ProviderProfileImportItem)(nil), // 131: openshell.v1.ProviderProfileImportItem + (*ProviderProfileDiagnostic)(nil), // 132: openshell.v1.ProviderProfileDiagnostic + (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 133: openshell.v1.ProviderCredentialTokenGrantAudienceOverride + (*ProviderCredentialTokenGrantSubjectToken)(nil), // 134: openshell.v1.ProviderCredentialTokenGrantSubjectToken + (*ProviderCredentialTokenGrant)(nil), // 135: openshell.v1.ProviderCredentialTokenGrant + (*ProviderProfileCredential)(nil), // 136: openshell.v1.ProviderProfileCredential + (*ProviderCredentialRefreshMaterial)(nil), // 137: openshell.v1.ProviderCredentialRefreshMaterial + (*ProviderCredentialRefreshOutput)(nil), // 138: openshell.v1.ProviderCredentialRefreshOutput + (*ProviderCredentialRefresh)(nil), // 139: openshell.v1.ProviderCredentialRefresh + (*ProviderCredentialRefreshStatus)(nil), // 140: openshell.v1.ProviderCredentialRefreshStatus + (*ProviderProfileDiscovery)(nil), // 141: openshell.v1.ProviderProfileDiscovery + (*GetProviderRefreshStatusRequest)(nil), // 142: openshell.v1.GetProviderRefreshStatusRequest + (*GetProviderRefreshStatusResponse)(nil), // 143: openshell.v1.GetProviderRefreshStatusResponse + (*ConfigureProviderRefreshRequest)(nil), // 144: openshell.v1.ConfigureProviderRefreshRequest + (*ConfigureProviderRefreshResponse)(nil), // 145: openshell.v1.ConfigureProviderRefreshResponse + (*RotateProviderCredentialRequest)(nil), // 146: openshell.v1.RotateProviderCredentialRequest + (*RotateProviderCredentialResponse)(nil), // 147: openshell.v1.RotateProviderCredentialResponse + (*DeleteProviderRefreshRequest)(nil), // 148: openshell.v1.DeleteProviderRefreshRequest + (*DeleteProviderRefreshResponse)(nil), // 149: openshell.v1.DeleteProviderRefreshResponse + (*ProviderProfile)(nil), // 150: openshell.v1.ProviderProfile + (*ProviderProfileFile)(nil), // 151: openshell.v1.ProviderProfileFile + (*ProviderProfileResponse)(nil), // 152: openshell.v1.ProviderProfileResponse + (*ListProviderProfilesResponse)(nil), // 153: openshell.v1.ListProviderProfilesResponse + (*ImportProviderProfilesRequest)(nil), // 154: openshell.v1.ImportProviderProfilesRequest + (*ImportProviderProfilesResponse)(nil), // 155: openshell.v1.ImportProviderProfilesResponse + (*UpdateProviderProfilesRequest)(nil), // 156: openshell.v1.UpdateProviderProfilesRequest + (*UpdateProviderProfilesResponse)(nil), // 157: openshell.v1.UpdateProviderProfilesResponse + (*LintProviderProfilesRequest)(nil), // 158: openshell.v1.LintProviderProfilesRequest + (*LintProviderProfilesResponse)(nil), // 159: openshell.v1.LintProviderProfilesResponse + (*DeleteProviderResponse)(nil), // 160: openshell.v1.DeleteProviderResponse + (*DeleteProviderProfileRequest)(nil), // 161: openshell.v1.DeleteProviderProfileRequest + (*DeleteProviderProfileResponse)(nil), // 162: openshell.v1.DeleteProviderProfileResponse + (*GetSandboxProviderEnvironmentRequest)(nil), // 163: openshell.v1.GetSandboxProviderEnvironmentRequest + (*StaticCredentialEndpointBinding)(nil), // 164: openshell.v1.StaticCredentialEndpointBinding + (*StaticCredentialBinding)(nil), // 165: openshell.v1.StaticCredentialBinding + (*GetSandboxProviderEnvironmentResponse)(nil), // 166: openshell.v1.GetSandboxProviderEnvironmentResponse + (*ProviderEnvironmentValue)(nil), // 167: openshell.v1.ProviderEnvironmentValue + (*ProviderEnvironmentSnapshot)(nil), // 168: openshell.v1.ProviderEnvironmentSnapshot + (*ExchangeProviderSubjectTokenRequest)(nil), // 169: openshell.v1.ExchangeProviderSubjectTokenRequest + (*ExchangeProviderSubjectTokenResponse)(nil), // 170: openshell.v1.ExchangeProviderSubjectTokenResponse + (*UpdateConfigRequest)(nil), // 171: openshell.v1.UpdateConfigRequest + (*PolicyMergeOperation)(nil), // 172: openshell.v1.PolicyMergeOperation + (*AddNetworkRule)(nil), // 173: openshell.v1.AddNetworkRule + (*RemoveNetworkEndpoint)(nil), // 174: openshell.v1.RemoveNetworkEndpoint + (*RemoveNetworkRule)(nil), // 175: openshell.v1.RemoveNetworkRule + (*L7RuleTarget)(nil), // 176: openshell.v1.L7RuleTarget + (*AddDenyRules)(nil), // 177: openshell.v1.AddDenyRules + (*AddAllowRules)(nil), // 178: openshell.v1.AddAllowRules + (*RemoveNetworkBinary)(nil), // 179: openshell.v1.RemoveNetworkBinary + (*UpdateConfigResponse)(nil), // 180: openshell.v1.UpdateConfigResponse + (*GetSandboxPolicyStatusRequest)(nil), // 181: openshell.v1.GetSandboxPolicyStatusRequest + (*GetSandboxPolicyStatusResponse)(nil), // 182: openshell.v1.GetSandboxPolicyStatusResponse + (*ListSandboxPoliciesRequest)(nil), // 183: openshell.v1.ListSandboxPoliciesRequest + (*ListSandboxPoliciesResponse)(nil), // 184: openshell.v1.ListSandboxPoliciesResponse + (*ReportPolicyStatusRequest)(nil), // 185: openshell.v1.ReportPolicyStatusRequest + (*ReportPolicyStatusResponse)(nil), // 186: openshell.v1.ReportPolicyStatusResponse + (*SandboxConfigurationAdmission)(nil), // 187: openshell.v1.SandboxConfigurationAdmission + (*ReportSandboxConfigurationRequest)(nil), // 188: openshell.v1.ReportSandboxConfigurationRequest + (*ReportSandboxConfigurationResponse)(nil), // 189: openshell.v1.ReportSandboxConfigurationResponse + (*SandboxPolicyRevision)(nil), // 190: openshell.v1.SandboxPolicyRevision + (*GetSandboxLogsRequest)(nil), // 191: openshell.v1.GetSandboxLogsRequest + (*PushSandboxLogsRequest)(nil), // 192: openshell.v1.PushSandboxLogsRequest + (*PushSandboxLogsResponse)(nil), // 193: openshell.v1.PushSandboxLogsResponse + (*GetSandboxLogsResponse)(nil), // 194: openshell.v1.GetSandboxLogsResponse + (*SupervisorMessage)(nil), // 195: openshell.v1.SupervisorMessage + (*GatewayMessage)(nil), // 196: openshell.v1.GatewayMessage + (*SupervisorHello)(nil), // 197: openshell.v1.SupervisorHello + (*SessionAccepted)(nil), // 198: openshell.v1.SessionAccepted + (*ConfigUpdate)(nil), // 199: openshell.v1.ConfigUpdate + (*ConfigApplyFailure)(nil), // 200: openshell.v1.ConfigApplyFailure + (*ConfigUpdateResult)(nil), // 201: openshell.v1.ConfigUpdateResult + (*PolicyLoadResult)(nil), // 202: openshell.v1.PolicyLoadResult + (*SessionRejected)(nil), // 203: openshell.v1.SessionRejected + (*SessionRedirect)(nil), // 204: openshell.v1.SessionRedirect + (*SupervisorHeartbeat)(nil), // 205: openshell.v1.SupervisorHeartbeat + (*GatewayHeartbeat)(nil), // 206: openshell.v1.GatewayHeartbeat + (*ReportMainProcessExitRequest)(nil), // 207: openshell.v1.ReportMainProcessExitRequest + (*ReportMainProcessExitResponse)(nil), // 208: openshell.v1.ReportMainProcessExitResponse + (*FinalizeMainProcessExitRequest)(nil), // 209: openshell.v1.FinalizeMainProcessExitRequest + (*FinalizeMainProcessExitResponse)(nil), // 210: openshell.v1.FinalizeMainProcessExitResponse + (*RelayOpen)(nil), // 211: openshell.v1.RelayOpen + (*SshRelayTarget)(nil), // 212: openshell.v1.SshRelayTarget + (*TcpRelayTarget)(nil), // 213: openshell.v1.TcpRelayTarget + (*RelayInit)(nil), // 214: openshell.v1.RelayInit + (*RelayFrame)(nil), // 215: openshell.v1.RelayFrame + (*PeerRelayInit)(nil), // 216: openshell.v1.PeerRelayInit + (*PeerRelayFrame)(nil), // 217: openshell.v1.PeerRelayFrame + (*PeerConfigSandboxTarget)(nil), // 218: openshell.v1.PeerConfigSandboxTarget + (*PeerConfigProviderTarget)(nil), // 219: openshell.v1.PeerConfigProviderTarget + (*PeerNotifyConfigUpdateRequest)(nil), // 220: openshell.v1.PeerNotifyConfigUpdateRequest + (*PeerNotifyConfigUpdateResponse)(nil), // 221: openshell.v1.PeerNotifyConfigUpdateResponse + (*RelayOpenResult)(nil), // 222: openshell.v1.RelayOpenResult + (*RelayClose)(nil), // 223: openshell.v1.RelayClose + (*L7RequestSample)(nil), // 224: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 225: openshell.v1.DenialSummary + (*DenialGroupCount)(nil), // 226: openshell.v1.DenialGroupCount + (*NetworkActivitySummary)(nil), // 227: openshell.v1.NetworkActivitySummary + (*PolicyChunk)(nil), // 228: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 229: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 230: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 231: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 232: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 233: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 234: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 235: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 236: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 237: openshell.v1.RejectDraftChunkResponse + (*DraftChunkApproval)(nil), // 238: openshell.v1.DraftChunkApproval + (*ApproveAllDraftChunksRequest)(nil), // 239: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 240: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 241: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 242: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 243: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 244: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 245: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 246: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 247: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 248: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 249: openshell.v1.GetDraftHistoryResponse + (*CreateWorkspaceRequest)(nil), // 250: openshell.v1.CreateWorkspaceRequest + (*CreateWorkspaceResponse)(nil), // 251: openshell.v1.CreateWorkspaceResponse + (*GetWorkspaceRequest)(nil), // 252: openshell.v1.GetWorkspaceRequest + (*GetWorkspaceResponse)(nil), // 253: openshell.v1.GetWorkspaceResponse + (*ListWorkspacesRequest)(nil), // 254: openshell.v1.ListWorkspacesRequest + (*ListWorkspacesResponse)(nil), // 255: openshell.v1.ListWorkspacesResponse + (*DeleteWorkspaceRequest)(nil), // 256: openshell.v1.DeleteWorkspaceRequest + (*DeleteWorkspaceResponse)(nil), // 257: openshell.v1.DeleteWorkspaceResponse + (*WorkspaceMember)(nil), // 258: openshell.v1.WorkspaceMember + (*AddWorkspaceMemberRequest)(nil), // 259: openshell.v1.AddWorkspaceMemberRequest + (*AddWorkspaceMemberResponse)(nil), // 260: openshell.v1.AddWorkspaceMemberResponse + (*RemoveWorkspaceMemberRequest)(nil), // 261: openshell.v1.RemoveWorkspaceMemberRequest + (*RemoveWorkspaceMemberResponse)(nil), // 262: openshell.v1.RemoveWorkspaceMemberResponse + (*ListWorkspaceMembersRequest)(nil), // 263: openshell.v1.ListWorkspaceMembersRequest + (*ListWorkspaceMembersResponse)(nil), // 264: openshell.v1.ListWorkspaceMembersResponse + (*ExtensionServiceCredential)(nil), // 265: openshell.v1.ExtensionServiceCredential + (*EndpointObservation)(nil), // 266: openshell.v1.EndpointObservation + (*ReportEndpointStatusRequest)(nil), // 267: openshell.v1.ReportEndpointStatusRequest + (*TokenGrantStatus)(nil), // 268: openshell.v1.TokenGrantStatus + (*TokenGrantFailureObservation)(nil), // 269: openshell.v1.TokenGrantFailureObservation + (*ReportEndpointStatusResponse)(nil), // 270: openshell.v1.ReportEndpointStatusResponse + (*EndpointStatus)(nil), // 271: openshell.v1.EndpointStatus + (*SandboxProvisioning)(nil), // 272: openshell.v1.SandboxProvisioning + (*SandboxServiceExposure)(nil), // 273: openshell.v1.SandboxServiceExposure + (*EndpointFailure)(nil), // 274: openshell.v1.EndpointFailure + nil, // 275: openshell.v1.SandboxSpec.EnvironmentEntry + nil, // 276: openshell.v1.SandboxTemplate.LabelsEntry + nil, // 277: openshell.v1.SandboxTemplate.AnnotationsEntry + nil, // 278: openshell.v1.SandboxTemplate.EnvironmentEntry + nil, // 279: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + nil, // 280: openshell.v1.PlatformEvent.MetadataEntry + nil, // 281: openshell.v1.CreateSandboxRequest.LabelsEntry + nil, // 282: openshell.v1.CreateSandboxRequest.AnnotationsEntry + nil, // 283: openshell.v1.SandboxResponse.ServiceUrlsEntry + nil, // 284: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 285: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 286: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry + nil, // 287: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + nil, // 288: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + nil, // 289: openshell.v1.ProviderProfile.AnnotationsEntry + nil, // 290: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + nil, // 291: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + nil, // 292: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + nil, // 293: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + nil, // 294: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + nil, // 295: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + nil, // 296: openshell.v1.ProviderEnvironmentSnapshot.FilesEntry + nil, // 297: openshell.v1.UpdateConfigRequest.AnnotationsEntry + nil, // 298: openshell.v1.UpdateConfigResponse.AnnotationsEntry + nil, // 299: openshell.v1.SandboxPolicyRevision.ProvenanceEntry + nil, // 300: openshell.v1.CreateWorkspaceRequest.LabelsEntry + (*timestamppb.Timestamp)(nil), // 301: google.protobuf.Timestamp + (*datamodelv1.ObjectMeta)(nil), // 302: openshell.datamodel.v1.ObjectMeta + (*sandboxv1.SandboxPolicy)(nil), // 303: openshell.sandbox.v1.SandboxPolicy + (*structpb.Struct)(nil), // 304: google.protobuf.Struct + (*durationpb.Duration)(nil), // 305: google.protobuf.Duration + (*datamodelv1.WorkspaceSelector)(nil), // 306: openshell.datamodel.v1.WorkspaceSelector + (*datamodelv1.Provider)(nil), // 307: openshell.datamodel.v1.Provider + (sandboxv1.PolicySource)(0), // 308: openshell.sandbox.v1.PolicySource + (*sandboxv1.NetworkEndpoint)(nil), // 309: openshell.sandbox.v1.NetworkEndpoint + (*sandboxv1.NetworkBinary)(nil), // 310: openshell.sandbox.v1.NetworkBinary + (*sandboxv1.SettingValue)(nil), // 311: openshell.sandbox.v1.SettingValue + (*sandboxv1.NetworkPolicyRule)(nil), // 312: openshell.sandbox.v1.NetworkPolicyRule + (*sandboxv1.L7DenyRule)(nil), // 313: openshell.sandbox.v1.L7DenyRule + (*sandboxv1.L7Rule)(nil), // 314: openshell.sandbox.v1.L7Rule + (*sandboxv1.SandboxConfigSnapshot)(nil), // 315: openshell.sandbox.v1.SandboxConfigSnapshot + (*datamodelv1.Workspace)(nil), // 316: openshell.datamodel.v1.Workspace + (*sandboxv1.GetSandboxConfigRequest)(nil), // 317: openshell.sandbox.v1.GetSandboxConfigRequest + (*sandboxv1.GetGatewayConfigRequest)(nil), // 318: openshell.sandbox.v1.GetGatewayConfigRequest + (*sandboxv1.GetSandboxConfigResponse)(nil), // 319: openshell.sandbox.v1.GetSandboxConfigResponse + (*sandboxv1.GetGatewayConfigResponse)(nil), // 320: openshell.sandbox.v1.GetGatewayConfigResponse } var file_openshell_proto_depIdxs = []int32{ - 299, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 299, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 263, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential - 299, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp + 301, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 301, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 265, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential + 301, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp 14, // 4: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus 14, // 5: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus 33, // 6: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo @@ -21678,530 +21869,534 @@ var file_openshell_proto_depIdxs = []int32{ 36, // 11: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities 37, // 12: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities 38, // 13: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities - 300, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 302, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 40, // 15: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec 51, // 16: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus 50, // 17: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance - 273, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry + 275, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry 43, // 19: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate - 301, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 303, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy 41, // 21: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements 17, // 22: openshell.v1.SandboxSpec.restart_policy:type_name -> openshell.v1.SandboxRestartPolicy 42, // 23: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements - 274, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry - 275, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry - 276, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry - 302, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct - 302, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct - 300, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 276, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry + 277, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry + 278, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry + 304, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 304, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct + 302, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 45, // 30: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec 46, // 31: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig - 302, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct + 304, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct 48, // 33: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel - 277, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + 279, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry 47, // 35: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources 42, // 36: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements 49, // 37: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup - 303, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration - 52, // 39: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition + 305, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 53, // 39: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition 1, // 40: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 269, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus - 185, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 270, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning - 299, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp - 299, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp - 267, // 46: openshell.v1.SandboxStatus.last_token_grant_failure:type_name -> openshell.v1.TokenGrantFailureObservation - 299, // 47: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp - 299, // 48: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp - 278, // 49: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 304, // 50: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 40, // 51: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 279, // 52: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 280, // 53: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 271, // 54: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure - 304, // 55: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 44, // 56: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 304, // 57: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 58: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 59: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 44, // 60: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 44, // 61: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate - 18, // 62: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 304, // 63: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 299, // 64: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp - 304, // 65: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 66: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 67: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 68: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 69: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 70: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 71: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 72: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 73: openshell.v1.SuspendSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 74: openshell.v1.ResumeSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 39, // 75: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 281, // 76: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry - 39, // 77: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 305, // 78: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 39, // 79: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 83, // 80: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 39, // 81: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 83, // 82: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 81, // 83: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision - 79, // 84: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity - 306, // 85: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource - 5, // 86: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent - 80, // 87: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision - 7, // 88: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState - 6, // 89: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 299, // 90: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp - 299, // 91: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp - 299, // 92: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp - 2, // 93: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind - 79, // 94: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity - 299, // 95: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp - 4, // 96: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason - 83, // 97: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 3, // 98: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState - 4, // 99: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason - 84, // 100: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation - 299, // 101: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp - 299, // 102: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp - 82, // 103: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation - 304, // 104: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 85, // 105: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus - 84, // 106: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation - 303, // 107: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration - 303, // 108: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration - 18, // 109: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 304, // 110: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 299, // 111: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp - 304, // 112: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 20, // 113: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 304, // 114: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 115: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 100, // 116: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 304, // 117: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 118: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 300, // 119: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 20, // 120: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 99, // 121: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint - 18, // 122: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 304, // 123: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 282, // 124: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 303, // 125: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration - 104, // 126: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout - 105, // 127: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr - 106, // 128: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 210, // 129: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 211, // 130: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget - 108, // 131: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit - 103, // 132: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest - 111, // 133: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 300, // 134: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 299, // 135: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp - 304, // 136: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 299, // 137: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp - 39, // 138: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox - 115, // 139: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine - 53, // 140: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent - 116, // 141: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 227, // 142: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 299, // 143: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp - 283, // 144: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 304, // 145: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 146: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 304, // 147: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 148: openshell.v1.GetProviderCredentialsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 303, // 149: openshell.v1.GetProviderCredentialsRequest.minimum_remaining_lifetime:type_name -> google.protobuf.Duration - 299, // 150: openshell.v1.ProviderCredentialValue.expiration_time:type_name -> google.protobuf.Timestamp - 284, // 151: openshell.v1.GetProviderCredentialsResponse.credentials:type_name -> openshell.v1.GetProviderCredentialsResponse.CredentialsEntry - 304, // 152: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 153: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 154: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 285, // 155: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - 304, // 156: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 157: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider - 83, // 158: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt - 305, // 159: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 304, // 160: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 161: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 148, // 162: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 303, // 163: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration - 131, // 164: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride - 8, // 165: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType - 132, // 166: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken - 137, // 167: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh - 133, // 168: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant - 9, // 169: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 303, // 170: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration - 303, // 171: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration - 135, // 172: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial - 136, // 173: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput - 9, // 174: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 299, // 175: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp - 299, // 176: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp - 299, // 177: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp - 16, // 178: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 299, // 179: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp - 304, // 180: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 138, // 181: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 304, // 182: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 9, // 183: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 286, // 184: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 299, // 185: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp - 138, // 186: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 304, // 187: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 138, // 188: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 304, // 189: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 190: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 10, // 191: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory - 134, // 192: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 307, // 193: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 308, // 194: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 139, // 195: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 287, // 196: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 149, // 197: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile - 148, // 198: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 148, // 199: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 304, // 200: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 129, // 201: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 130, // 202: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 148, // 203: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 304, // 204: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 129, // 205: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 130, // 206: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 148, // 207: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 304, // 208: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 129, // 209: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 130, // 210: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 18, // 211: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 304, // 212: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 213: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 162, // 214: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 288, // 215: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 289, // 216: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - 290, // 217: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 291, // 218: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 4, // 219: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 292, // 220: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - 11, // 221: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification - 163, // 222: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding - 299, // 223: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp - 165, // 224: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue - 293, // 225: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry - 4, // 226: openshell.v1.ProviderEnvironmentSnapshot.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 294, // 227: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - 303, // 228: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration - 304, // 229: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 301, // 230: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 309, // 231: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 170, // 232: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 295, // 233: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 171, // 234: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 172, // 235: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 173, // 236: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 175, // 237: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 176, // 238: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 177, // 239: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 310, // 240: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 308, // 241: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 311, // 242: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 174, // 243: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget - 312, // 244: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 174, // 245: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget - 296, // 246: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 304, // 247: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 188, // 248: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 304, // 249: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 188, // 250: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 13, // 251: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 12, // 252: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState - 185, // 253: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 13, // 254: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 299, // 255: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp - 299, // 256: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp - 301, // 257: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 297, // 258: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 304, // 259: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 299, // 260: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp - 115, // 261: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 115, // 262: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 195, // 263: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 203, // 264: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 220, // 265: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 221, // 266: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 199, // 267: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult - 196, // 268: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 201, // 269: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 204, // 270: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 209, // 271: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 221, // 272: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 202, // 273: openshell.v1.GatewayMessage.session_redirect:type_name -> openshell.v1.SessionRedirect - 197, // 274: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate - 197, // 275: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigUpdate - 303, // 276: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration - 313, // 277: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot - 166, // 278: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot - 6, // 279: openshell.v1.ConfigUpdateResult.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 198, // 280: openshell.v1.ConfigUpdateResult.failure:type_name -> openshell.v1.ConfigApplyFailure - 185, // 281: openshell.v1.ConfigUpdateResult.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 200, // 282: openshell.v1.ConfigUpdateResult.policy_load:type_name -> openshell.v1.PolicyLoadResult - 210, // 283: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 211, // 284: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 212, // 285: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 209, // 286: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen - 214, // 287: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit - 216, // 288: openshell.v1.PeerNotifyConfigUpdateRequest.sandbox:type_name -> openshell.v1.PeerConfigSandboxTarget - 217, // 289: openshell.v1.PeerNotifyConfigUpdateRequest.provider:type_name -> openshell.v1.PeerConfigProviderTarget - 299, // 290: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp - 299, // 291: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp - 222, // 292: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 224, // 293: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 310, // 294: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 299, // 295: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp - 299, // 296: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp - 299, // 297: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp - 299, // 298: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp - 301, // 299: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 301, // 300: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 304, // 301: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 223, // 302: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 226, // 303: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 225, // 304: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 304, // 305: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 226, // 306: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 299, // 307: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp - 304, // 308: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 309: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 310: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 236, // 311: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval - 304, // 312: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 310, // 313: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 304, // 314: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 315: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 316: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 299, // 317: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp - 246, // 318: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 298, // 319: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 314, // 320: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 314, // 321: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 314, // 322: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 18, // 323: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 300, // 324: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 15, // 325: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 304, // 326: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 15, // 327: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 256, // 328: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 304, // 329: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 330: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 304, // 331: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 256, // 332: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 299, // 333: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp - 19, // 334: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult - 272, // 335: openshell.v1.EndpointObservation.failure:type_name -> openshell.v1.EndpointFailure - 264, // 336: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation - 266, // 337: openshell.v1.ReportEndpointStatusRequest.token_grant_status:type_name -> openshell.v1.TokenGrantStatus - 267, // 338: openshell.v1.TokenGrantStatus.last_failure:type_name -> openshell.v1.TokenGrantFailureObservation - 272, // 339: openshell.v1.TokenGrantFailureObservation.failure:type_name -> openshell.v1.EndpointFailure - 19, // 340: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult - 299, // 341: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp - 272, // 342: openshell.v1.EndpointStatus.last_failure:type_name -> openshell.v1.EndpointFailure - 299, // 343: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp - 299, // 344: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp - 299, // 345: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp - 299, // 346: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp - 299, // 347: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp - 299, // 348: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp - 299, // 349: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp - 299, // 350: openshell.v1.SandboxProvisioning.preparation_deadline:type_name -> google.protobuf.Timestamp - 299, // 351: openshell.v1.SandboxProvisioning.admission_start_time:type_name -> google.protobuf.Timestamp - 20, // 352: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 21, // 353: openshell.v1.EndpointFailure.domain:type_name -> openshell.v1.EndpointFailureDomain - 16, // 354: openshell.v1.EndpointFailure.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 120, // 355: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry.value:type_name -> openshell.v1.ProviderCredentialValue - 299, // 356: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 299, // 357: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 134, // 358: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 163, // 359: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 134, // 360: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 26, // 361: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 28, // 362: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 30, // 363: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 54, // 364: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 62, // 365: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest - 64, // 366: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 65, // 367: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 55, // 368: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 56, // 369: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 57, // 370: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 58, // 371: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 66, // 372: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 67, // 373: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 68, // 374: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 86, // 375: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 69, // 376: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 70, // 377: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 71, // 378: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 72, // 379: openshell.v1.OpenShell.SuspendSandbox:input_type -> openshell.v1.SuspendSandboxRequest - 73, // 380: openshell.v1.OpenShell.ResumeSandbox:input_type -> openshell.v1.ResumeSandboxRequest - 91, // 381: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 93, // 382: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 94, // 383: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 95, // 384: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 97, // 385: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 101, // 386: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 103, // 387: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 109, // 388: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 110, // 389: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 117, // 390: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 118, // 391: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 119, // 392: openshell.v1.OpenShell.GetProviderCredentials:input_type -> openshell.v1.GetProviderCredentialsRequest - 122, // 393: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 127, // 394: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 128, // 395: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 152, // 396: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 154, // 397: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 156, // 398: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 123, // 399: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 140, // 400: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 142, // 401: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 144, // 402: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 146, // 403: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 124, // 404: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 159, // 405: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 315, // 406: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 316, // 407: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 169, // 408: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 179, // 409: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 181, // 410: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 183, // 411: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 265, // 412: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 88, // 413: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 186, // 414: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest - 161, // 415: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 167, // 416: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest - 189, // 417: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 190, // 418: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 193, // 419: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 205, // 420: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest - 207, // 421: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest - 213, // 422: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 215, // 423: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame - 88, // 424: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 265, // 425: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 86, // 426: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 218, // 427: openshell.v1.OpenShell.PeerNotifyConfigUpdate:input_type -> openshell.v1.PeerNotifyConfigUpdateRequest - 113, // 428: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 228, // 429: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 230, // 430: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 232, // 431: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 234, // 432: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 237, // 433: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 239, // 434: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 241, // 435: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 243, // 436: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 245, // 437: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 22, // 438: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 24, // 439: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 248, // 440: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 250, // 441: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 252, // 442: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 254, // 443: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 257, // 444: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 259, // 445: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 261, // 446: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 27, // 447: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 29, // 448: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 31, // 449: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 74, // 450: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 63, // 451: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse - 74, // 452: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 75, // 453: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 59, // 454: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 59, // 455: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 60, // 456: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 61, // 457: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 76, // 458: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 77, // 459: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 78, // 460: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 87, // 461: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 90, // 462: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 74, // 463: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 74, // 464: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 74, // 465: openshell.v1.OpenShell.SuspendSandbox:output_type -> openshell.v1.SandboxResponse - 74, // 466: openshell.v1.OpenShell.ResumeSandbox:output_type -> openshell.v1.SandboxResponse - 92, // 467: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 100, // 468: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 100, // 469: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 96, // 470: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 98, // 471: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 102, // 472: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 107, // 473: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 109, // 474: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 107, // 475: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 125, // 476: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 125, // 477: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 121, // 478: openshell.v1.OpenShell.GetProviderCredentials:output_type -> openshell.v1.GetProviderCredentialsResponse - 126, // 479: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 151, // 480: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 150, // 481: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 153, // 482: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 155, // 483: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 157, // 484: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 125, // 485: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 141, // 486: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 143, // 487: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 145, // 488: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 147, // 489: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 158, // 490: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 160, // 491: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 317, // 492: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 318, // 493: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 178, // 494: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 180, // 495: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 182, // 496: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 184, // 497: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 268, // 498: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 89, // 499: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 187, // 500: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse - 164, // 501: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 168, // 502: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse - 192, // 503: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 191, // 504: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 194, // 505: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 206, // 506: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse - 208, // 507: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse - 213, // 508: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 215, // 509: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame - 89, // 510: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 268, // 511: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 87, // 512: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 219, // 513: openshell.v1.OpenShell.PeerNotifyConfigUpdate:output_type -> openshell.v1.PeerNotifyConfigUpdateResponse - 114, // 514: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 229, // 515: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 231, // 516: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 233, // 517: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 235, // 518: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 238, // 519: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 240, // 520: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 242, // 521: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 244, // 522: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 247, // 523: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 23, // 524: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 25, // 525: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 249, // 526: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 251, // 527: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 253, // 528: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 255, // 529: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 258, // 530: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 260, // 531: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 262, // 532: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 447, // [447:533] is the sub-list for method output_type - 361, // [361:447] is the sub-list for method input_type - 361, // [361:361] is the sub-list for extension type_name - 361, // [361:361] is the sub-list for extension extendee - 0, // [0:361] is the sub-list for field type_name + 271, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus + 187, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 272, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning + 301, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp + 301, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp + 269, // 46: openshell.v1.SandboxStatus.last_token_grant_failure:type_name -> openshell.v1.TokenGrantFailureObservation + 52, // 47: openshell.v1.SandboxStatus.image_update:type_name -> openshell.v1.SandboxImageUpdate + 301, // 48: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp + 301, // 49: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp + 280, // 50: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 306, // 51: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 40, // 52: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec + 281, // 53: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 282, // 54: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 273, // 55: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure + 306, // 56: openshell.v1.UpdateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 57: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 44, // 58: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 306, // 59: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 60: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 61: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 44, // 62: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 44, // 63: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate + 18, // 64: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 306, // 65: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 301, // 66: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp + 306, // 67: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 68: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 69: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 70: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 71: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 72: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 73: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 74: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 75: openshell.v1.SuspendSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 76: openshell.v1.ResumeSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 39, // 77: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox + 283, // 78: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry + 39, // 79: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox + 307, // 80: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 39, // 81: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 85, // 82: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 39, // 83: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 85, // 84: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 83, // 85: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision + 81, // 86: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity + 308, // 87: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 5, // 88: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent + 82, // 89: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision + 7, // 90: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState + 6, // 91: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome + 301, // 92: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp + 301, // 93: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp + 301, // 94: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp + 2, // 95: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind + 81, // 96: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity + 301, // 97: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp + 4, // 98: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason + 85, // 99: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 3, // 100: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState + 4, // 101: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason + 86, // 102: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation + 301, // 103: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp + 301, // 104: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp + 84, // 105: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation + 306, // 106: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 87, // 107: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus + 86, // 108: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation + 305, // 109: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration + 305, // 110: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration + 18, // 111: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 306, // 112: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 301, // 113: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp + 306, // 114: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 20, // 115: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 306, // 116: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 117: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 102, // 118: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse + 306, // 119: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 120: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 302, // 121: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 20, // 122: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 101, // 123: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint + 18, // 124: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 306, // 125: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 284, // 126: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 305, // 127: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration + 106, // 128: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout + 107, // 129: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr + 108, // 130: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit + 212, // 131: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget + 213, // 132: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget + 110, // 133: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit + 105, // 134: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest + 113, // 135: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize + 302, // 136: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 301, // 137: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp + 306, // 138: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 301, // 139: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp + 39, // 140: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox + 117, // 141: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine + 54, // 142: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent + 118, // 143: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning + 229, // 144: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 301, // 145: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp + 285, // 146: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 306, // 147: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 307, // 148: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 306, // 149: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 150: openshell.v1.GetProviderCredentialsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 151: openshell.v1.GetProviderCredentialsRequest.minimum_remaining_lifetime:type_name -> google.protobuf.Duration + 301, // 152: openshell.v1.ProviderCredentialValue.expiration_time:type_name -> google.protobuf.Timestamp + 286, // 153: openshell.v1.GetProviderCredentialsResponse.credentials:type_name -> openshell.v1.GetProviderCredentialsResponse.CredentialsEntry + 306, // 154: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 155: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 307, // 156: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 287, // 157: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + 306, // 158: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 307, // 159: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 85, // 160: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt + 307, // 161: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 306, // 162: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 163: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 150, // 164: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile + 305, // 165: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration + 133, // 166: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride + 8, // 167: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType + 134, // 168: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken + 139, // 169: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh + 135, // 170: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant + 9, // 171: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 305, // 172: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration + 305, // 173: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration + 137, // 174: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial + 138, // 175: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput + 9, // 176: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 301, // 177: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp + 301, // 178: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp + 301, // 179: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp + 16, // 180: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 301, // 181: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp + 306, // 182: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 140, // 183: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 306, // 184: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 9, // 185: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 288, // 186: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 301, // 187: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp + 140, // 188: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 306, // 189: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 140, // 190: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 306, // 191: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 192: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 10, // 193: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory + 136, // 194: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential + 309, // 195: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 310, // 196: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 141, // 197: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery + 289, // 198: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 151, // 199: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile + 150, // 200: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile + 150, // 201: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 306, // 202: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 131, // 203: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 132, // 204: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 150, // 205: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 306, // 206: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 131, // 207: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem + 132, // 208: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 150, // 209: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile + 306, // 210: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 131, // 211: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 132, // 212: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 18, // 213: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 306, // 214: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 215: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 164, // 216: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding + 290, // 217: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 291, // 218: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + 292, // 219: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 293, // 220: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 4, // 221: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason + 294, // 222: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + 11, // 223: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification + 165, // 224: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding + 301, // 225: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp + 167, // 226: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue + 295, // 227: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + 4, // 228: openshell.v1.ProviderEnvironmentSnapshot.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason + 296, // 229: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry + 305, // 230: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration + 306, // 231: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 303, // 232: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 311, // 233: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 172, // 234: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation + 297, // 235: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 173, // 236: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule + 174, // 237: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint + 175, // 238: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule + 177, // 239: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules + 178, // 240: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules + 179, // 241: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary + 312, // 242: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 310, // 243: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 313, // 244: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 176, // 245: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget + 314, // 246: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 176, // 247: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget + 298, // 248: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 306, // 249: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 190, // 250: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 306, // 251: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 190, // 252: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 13, // 253: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 12, // 254: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState + 187, // 255: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 13, // 256: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 301, // 257: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp + 301, // 258: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp + 303, // 259: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 299, // 260: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 306, // 261: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 301, // 262: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp + 117, // 263: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 117, // 264: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 197, // 265: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello + 205, // 266: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat + 222, // 267: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 223, // 268: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 201, // 269: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult + 198, // 270: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted + 203, // 271: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected + 206, // 272: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat + 211, // 273: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen + 223, // 274: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 204, // 275: openshell.v1.GatewayMessage.session_redirect:type_name -> openshell.v1.SessionRedirect + 199, // 276: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate + 199, // 277: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigUpdate + 305, // 278: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration + 315, // 279: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot + 168, // 280: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot + 6, // 281: openshell.v1.ConfigUpdateResult.outcome:type_name -> openshell.v1.ConfigApplyOutcome + 200, // 282: openshell.v1.ConfigUpdateResult.failure:type_name -> openshell.v1.ConfigApplyFailure + 187, // 283: openshell.v1.ConfigUpdateResult.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 202, // 284: openshell.v1.ConfigUpdateResult.policy_load:type_name -> openshell.v1.PolicyLoadResult + 212, // 285: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget + 213, // 286: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget + 214, // 287: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit + 211, // 288: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen + 216, // 289: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit + 218, // 290: openshell.v1.PeerNotifyConfigUpdateRequest.sandbox:type_name -> openshell.v1.PeerConfigSandboxTarget + 219, // 291: openshell.v1.PeerNotifyConfigUpdateRequest.provider:type_name -> openshell.v1.PeerConfigProviderTarget + 301, // 292: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp + 301, // 293: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp + 224, // 294: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 226, // 295: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 312, // 296: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 301, // 297: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp + 301, // 298: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp + 301, // 299: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp + 301, // 300: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp + 303, // 301: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 303, // 302: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 306, // 303: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 225, // 304: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 228, // 305: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 227, // 306: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 306, // 307: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 228, // 308: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 301, // 309: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp + 306, // 310: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 311: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 312: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 238, // 313: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval + 306, // 314: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 312, // 315: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 306, // 316: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 317: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 318: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 301, // 319: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp + 248, // 320: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 300, // 321: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 316, // 322: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 316, // 323: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 316, // 324: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 18, // 325: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 302, // 326: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 15, // 327: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 306, // 328: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 15, // 329: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 258, // 330: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 306, // 331: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 332: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 306, // 333: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 258, // 334: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 301, // 335: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp + 19, // 336: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult + 274, // 337: openshell.v1.EndpointObservation.failure:type_name -> openshell.v1.EndpointFailure + 266, // 338: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation + 268, // 339: openshell.v1.ReportEndpointStatusRequest.token_grant_status:type_name -> openshell.v1.TokenGrantStatus + 269, // 340: openshell.v1.TokenGrantStatus.last_failure:type_name -> openshell.v1.TokenGrantFailureObservation + 274, // 341: openshell.v1.TokenGrantFailureObservation.failure:type_name -> openshell.v1.EndpointFailure + 19, // 342: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult + 301, // 343: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp + 274, // 344: openshell.v1.EndpointStatus.last_failure:type_name -> openshell.v1.EndpointFailure + 301, // 345: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp + 301, // 346: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp + 301, // 347: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp + 301, // 348: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp + 301, // 349: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp + 301, // 350: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp + 301, // 351: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp + 301, // 352: openshell.v1.SandboxProvisioning.preparation_deadline:type_name -> google.protobuf.Timestamp + 301, // 353: openshell.v1.SandboxProvisioning.admission_start_time:type_name -> google.protobuf.Timestamp + 20, // 354: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 21, // 355: openshell.v1.EndpointFailure.domain:type_name -> openshell.v1.EndpointFailureDomain + 16, // 356: openshell.v1.EndpointFailure.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 122, // 357: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry.value:type_name -> openshell.v1.ProviderCredentialValue + 301, // 358: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 301, // 359: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 136, // 360: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 165, // 361: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 136, // 362: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 26, // 363: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 28, // 364: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 30, // 365: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 55, // 366: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 56, // 367: openshell.v1.OpenShell.UpdateSandbox:input_type -> openshell.v1.UpdateSandboxRequest + 64, // 368: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest + 66, // 369: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 67, // 370: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 57, // 371: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 58, // 372: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 59, // 373: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 60, // 374: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 68, // 375: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 69, // 376: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 70, // 377: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 88, // 378: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 71, // 379: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 72, // 380: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 73, // 381: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 74, // 382: openshell.v1.OpenShell.SuspendSandbox:input_type -> openshell.v1.SuspendSandboxRequest + 75, // 383: openshell.v1.OpenShell.ResumeSandbox:input_type -> openshell.v1.ResumeSandboxRequest + 93, // 384: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 95, // 385: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 96, // 386: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 97, // 387: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 99, // 388: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 103, // 389: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 105, // 390: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 111, // 391: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 112, // 392: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 119, // 393: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 120, // 394: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 121, // 395: openshell.v1.OpenShell.GetProviderCredentials:input_type -> openshell.v1.GetProviderCredentialsRequest + 124, // 396: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 129, // 397: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 130, // 398: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 154, // 399: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 156, // 400: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 158, // 401: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 125, // 402: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 142, // 403: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 144, // 404: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 146, // 405: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 148, // 406: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 126, // 407: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 161, // 408: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 317, // 409: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 318, // 410: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 171, // 411: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 181, // 412: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 183, // 413: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 185, // 414: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 267, // 415: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 90, // 416: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 188, // 417: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest + 163, // 418: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 169, // 419: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest + 191, // 420: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 192, // 421: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 195, // 422: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 207, // 423: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest + 209, // 424: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest + 215, // 425: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 217, // 426: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame + 90, // 427: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 267, // 428: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 88, // 429: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 220, // 430: openshell.v1.OpenShell.PeerNotifyConfigUpdate:input_type -> openshell.v1.PeerNotifyConfigUpdateRequest + 115, // 431: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 230, // 432: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 232, // 433: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 234, // 434: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 236, // 435: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 239, // 436: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 241, // 437: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 243, // 438: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 245, // 439: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 247, // 440: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 22, // 441: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 24, // 442: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 250, // 443: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 252, // 444: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 254, // 445: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 256, // 446: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 259, // 447: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 261, // 448: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 263, // 449: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 27, // 450: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 29, // 451: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 31, // 452: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 76, // 453: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 76, // 454: openshell.v1.OpenShell.UpdateSandbox:output_type -> openshell.v1.SandboxResponse + 65, // 455: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse + 76, // 456: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 77, // 457: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 61, // 458: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 61, // 459: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 62, // 460: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 63, // 461: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 78, // 462: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 79, // 463: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 80, // 464: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 89, // 465: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 92, // 466: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 76, // 467: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 76, // 468: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 76, // 469: openshell.v1.OpenShell.SuspendSandbox:output_type -> openshell.v1.SandboxResponse + 76, // 470: openshell.v1.OpenShell.ResumeSandbox:output_type -> openshell.v1.SandboxResponse + 94, // 471: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 102, // 472: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 102, // 473: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 98, // 474: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 100, // 475: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 104, // 476: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 109, // 477: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 111, // 478: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 109, // 479: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 127, // 480: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 127, // 481: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 123, // 482: openshell.v1.OpenShell.GetProviderCredentials:output_type -> openshell.v1.GetProviderCredentialsResponse + 128, // 483: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 153, // 484: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 152, // 485: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 155, // 486: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 157, // 487: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 159, // 488: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 127, // 489: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 143, // 490: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 145, // 491: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 147, // 492: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 149, // 493: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 160, // 494: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 162, // 495: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 319, // 496: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 320, // 497: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 180, // 498: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 182, // 499: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 184, // 500: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 186, // 501: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 270, // 502: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 91, // 503: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 189, // 504: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse + 166, // 505: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 170, // 506: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse + 194, // 507: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 193, // 508: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 196, // 509: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 208, // 510: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse + 210, // 511: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse + 215, // 512: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 217, // 513: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame + 91, // 514: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 270, // 515: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 89, // 516: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 221, // 517: openshell.v1.OpenShell.PeerNotifyConfigUpdate:output_type -> openshell.v1.PeerNotifyConfigUpdateResponse + 116, // 518: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 231, // 519: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 233, // 520: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 235, // 521: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 237, // 522: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 240, // 523: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 242, // 524: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 244, // 525: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 246, // 526: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 249, // 527: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 23, // 528: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 25, // 529: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 251, // 530: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 253, // 531: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 255, // 532: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 257, // 533: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 260, // 534: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 262, // 535: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 264, // 536: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 450, // [450:537] is the sub-list for method output_type + 363, // [363:450] is the sub-list for method input_type + 363, // [363:363] is the sub-list for extension type_name + 363, // [363:363] is the sub-list for extension extendee + 0, // [0:363] is the sub-list for field type_name } func init() { file_openshell_proto_init() } @@ -22212,37 +22407,37 @@ func file_openshell_proto_init() { file_openshell_proto_msgTypes[20].OneofWrappers = []any{} file_openshell_proto_msgTypes[21].OneofWrappers = []any{} file_openshell_proto_msgTypes[29].OneofWrappers = []any{} - file_openshell_proto_msgTypes[58].OneofWrappers = []any{ + file_openshell_proto_msgTypes[60].OneofWrappers = []any{ (*ConfigSnapshotRevision_SandboxConfig)(nil), (*ConfigSnapshotRevision_ProviderEnvironment)(nil), (*ConfigSnapshotRevision_ProviderTarget)(nil), } - file_openshell_proto_msgTypes[85].OneofWrappers = []any{ + file_openshell_proto_msgTypes[87].OneofWrappers = []any{ (*ExecSandboxEvent_Stdout)(nil), (*ExecSandboxEvent_Stderr)(nil), (*ExecSandboxEvent_Exit)(nil), } - file_openshell_proto_msgTypes[86].OneofWrappers = []any{ + file_openshell_proto_msgTypes[88].OneofWrappers = []any{ (*TcpForwardInit_Ssh)(nil), (*TcpForwardInit_Tcp)(nil), } - file_openshell_proto_msgTypes[87].OneofWrappers = []any{ + file_openshell_proto_msgTypes[89].OneofWrappers = []any{ (*TcpForwardFrame_Init)(nil), (*TcpForwardFrame_Data)(nil), } - file_openshell_proto_msgTypes[88].OneofWrappers = []any{ + file_openshell_proto_msgTypes[90].OneofWrappers = []any{ (*ExecSandboxInput_Start)(nil), (*ExecSandboxInput_Stdin)(nil), (*ExecSandboxInput_Resize)(nil), } - file_openshell_proto_msgTypes[92].OneofWrappers = []any{ + file_openshell_proto_msgTypes[94].OneofWrappers = []any{ (*SandboxStreamEvent_Sandbox)(nil), (*SandboxStreamEvent_Log)(nil), (*SandboxStreamEvent_Event)(nil), (*SandboxStreamEvent_Warning)(nil), (*SandboxStreamEvent_DraftPolicyUpdate)(nil), } - file_openshell_proto_msgTypes[148].OneofWrappers = []any{ + file_openshell_proto_msgTypes[150].OneofWrappers = []any{ (*PolicyMergeOperation_AddRule)(nil), (*PolicyMergeOperation_RemoveEndpoint)(nil), (*PolicyMergeOperation_RemoveRule)(nil), @@ -22250,15 +22445,15 @@ func file_openshell_proto_init() { (*PolicyMergeOperation_AddAllowRules)(nil), (*PolicyMergeOperation_RemoveBinary)(nil), } - file_openshell_proto_msgTypes[152].OneofWrappers = []any{} - file_openshell_proto_msgTypes[171].OneofWrappers = []any{ + file_openshell_proto_msgTypes[154].OneofWrappers = []any{} + file_openshell_proto_msgTypes[173].OneofWrappers = []any{ (*SupervisorMessage_Hello)(nil), (*SupervisorMessage_Heartbeat)(nil), (*SupervisorMessage_RelayOpenResult)(nil), (*SupervisorMessage_RelayClose)(nil), (*SupervisorMessage_ConfigUpdateResult)(nil), } - file_openshell_proto_msgTypes[172].OneofWrappers = []any{ + file_openshell_proto_msgTypes[174].OneofWrappers = []any{ (*GatewayMessage_SessionAccepted)(nil), (*GatewayMessage_SessionRejected)(nil), (*GatewayMessage_Heartbeat)(nil), @@ -22267,32 +22462,32 @@ func file_openshell_proto_init() { (*GatewayMessage_SessionRedirect)(nil), (*GatewayMessage_ConfigUpdate)(nil), } - file_openshell_proto_msgTypes[187].OneofWrappers = []any{ + file_openshell_proto_msgTypes[189].OneofWrappers = []any{ (*RelayOpen_Ssh)(nil), (*RelayOpen_Tcp)(nil), } - file_openshell_proto_msgTypes[191].OneofWrappers = []any{ + file_openshell_proto_msgTypes[193].OneofWrappers = []any{ (*RelayFrame_Init)(nil), (*RelayFrame_Data)(nil), } - file_openshell_proto_msgTypes[193].OneofWrappers = []any{ + file_openshell_proto_msgTypes[195].OneofWrappers = []any{ (*PeerRelayFrame_Init)(nil), (*PeerRelayFrame_Data)(nil), } - file_openshell_proto_msgTypes[196].OneofWrappers = []any{ + file_openshell_proto_msgTypes[198].OneofWrappers = []any{ (*PeerNotifyConfigUpdateRequest_Sandbox)(nil), (*PeerNotifyConfigUpdateRequest_Workspace)(nil), (*PeerNotifyConfigUpdateRequest_AllConnected)(nil), (*PeerNotifyConfigUpdateRequest_Provider)(nil), } - file_openshell_proto_msgTypes[250].OneofWrappers = []any{} + file_openshell_proto_msgTypes[252].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_openshell_proto_rawDesc), len(file_openshell_proto_rawDesc)), NumEnums: 22, - NumMessages: 277, + NumMessages: 279, NumExtensions: 0, NumServices: 1, }, diff --git a/sdk/go/proto/openshellv1/openshell_grpc.pb.go b/sdk/go/proto/openshellv1/openshell_grpc.pb.go index 2f13a80383..2c5b89f076 100644 --- a/sdk/go/proto/openshellv1/openshell_grpc.pb.go +++ b/sdk/go/proto/openshellv1/openshell_grpc.pb.go @@ -27,6 +27,7 @@ const ( OpenShell_GetCurrentUser_FullMethodName = "/openshell.v1.OpenShell/GetCurrentUser" OpenShell_GetGatewayInfo_FullMethodName = "/openshell.v1.OpenShell/GetGatewayInfo" OpenShell_CreateSandbox_FullMethodName = "/openshell.v1.OpenShell/CreateSandbox" + OpenShell_UpdateSandbox_FullMethodName = "/openshell.v1.OpenShell/UpdateSandbox" OpenShell_BeginRootfsTarStaging_FullMethodName = "/openshell.v1.OpenShell/BeginRootfsTarStaging" OpenShell_GetSandbox_FullMethodName = "/openshell.v1.OpenShell/GetSandbox" OpenShell_ListSandboxes_FullMethodName = "/openshell.v1.OpenShell/ListSandboxes" @@ -132,6 +133,9 @@ type OpenShellClient interface { GetGatewayInfo(ctx context.Context, in *GetGatewayInfoRequest, opts ...grpc.CallOption) (*GetGatewayInfoResponse, error) // Create a new sandbox. CreateSandbox(ctx context.Context, in *CreateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) + // Update only the workload image of a stopped sandbox without deleting its + // identity or retained storage. Requires compute-driver image-update support. + UpdateSandbox(ctx context.Context, in *UpdateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) // Allocate a gateway-owned staging slot for a local rootfs tar archive. // // The gateway creates a request-scoped directory inside the compute driver's @@ -407,6 +411,16 @@ func (c *openShellClient) CreateSandbox(ctx context.Context, in *CreateSandboxRe return out, nil } +func (c *openShellClient) UpdateSandbox(ctx context.Context, in *UpdateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SandboxResponse) + err := c.cc.Invoke(ctx, OpenShell_UpdateSandbox_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *openShellClient) BeginRootfsTarStaging(ctx context.Context, in *BeginRootfsTarStagingRequest, opts ...grpc.CallOption) (*BeginRootfsTarStagingResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(BeginRootfsTarStagingResponse) @@ -1284,6 +1298,9 @@ type OpenShellServer interface { GetGatewayInfo(context.Context, *GetGatewayInfoRequest) (*GetGatewayInfoResponse, error) // Create a new sandbox. CreateSandbox(context.Context, *CreateSandboxRequest) (*SandboxResponse, error) + // Update only the workload image of a stopped sandbox without deleting its + // identity or retained storage. Requires compute-driver image-update support. + UpdateSandbox(context.Context, *UpdateSandboxRequest) (*SandboxResponse, error) // Allocate a gateway-owned staging slot for a local rootfs tar archive. // // The gateway creates a request-scoped directory inside the compute driver's @@ -1531,6 +1548,9 @@ func (UnimplementedOpenShellServer) GetGatewayInfo(context.Context, *GetGatewayI func (UnimplementedOpenShellServer) CreateSandbox(context.Context, *CreateSandboxRequest) (*SandboxResponse, error) { return nil, status.Error(codes.Unimplemented, "method CreateSandbox not implemented") } +func (UnimplementedOpenShellServer) UpdateSandbox(context.Context, *UpdateSandboxRequest) (*SandboxResponse, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateSandbox not implemented") +} func (UnimplementedOpenShellServer) BeginRootfsTarStaging(context.Context, *BeginRootfsTarStagingRequest) (*BeginRootfsTarStagingResponse, error) { return nil, status.Error(codes.Unimplemented, "method BeginRootfsTarStaging not implemented") } @@ -1870,6 +1890,24 @@ func _OpenShell_CreateSandbox_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _OpenShell_UpdateSandbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSandboxRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).UpdateSandbox(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_UpdateSandbox_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).UpdateSandbox(ctx, req.(*UpdateSandboxRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _OpenShell_BeginRootfsTarStaging_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(BeginRootfsTarStagingRequest) if err := dec(in); err != nil { @@ -3289,6 +3327,10 @@ var OpenShell_ServiceDesc = grpc.ServiceDesc{ MethodName: "CreateSandbox", Handler: _OpenShell_CreateSandbox_Handler, }, + { + MethodName: "UpdateSandbox", + Handler: _OpenShell_UpdateSandbox_Handler, + }, { MethodName: "BeginRootfsTarStaging", Handler: _OpenShell_BeginRootfsTarStaging_Handler, diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index f87e06fdff..d10370b329 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -554,6 +554,32 @@ state cannot be restored; use `sandbox start` for an explicit clean boot. `sandb `sandbox stop`, and `sandbox delete` on a suspended sandbox discard the retained memory state. +### Change a stopped sandbox's workload image + +Do not invent a `sandbox update` command or use delete/create to change an +existing sandbox's image. The raw `UpdateSandbox` RPC initially supports only +stopped Kubernetes sandboxes; other drivers return `UNIMPLEMENTED`. Stop and +wait for `Stopped`, read the sandbox's current resource version through +`GetSandbox`, call raw `UpdateSandbox` with the named workspace, sandbox name, +OCI image, and required nonzero `expected_resource_version`, then start after +success. There is no curated SDK update method. The sandbox identity, Kubernetes +custom resource, and persistent volume claim remain; the existing workspace is +not reseeded and trusted runtime images do not change. + +For an image that fails to start and reaches a provisioning timeout, wait for +cleanup completion and settlement of the original driver operation, then run +`sandbox stop` to obtain `Stopped` before correcting the image. This retains the +timeout diagnostic and storage and does not bypass pending cleanup. + +If raw `sandbox.status.image_update` is present after a failure, start is +blocked. Read a fresh version and retry that same pending image. An optional +`request_id` with an unresolved admission does not execute again; inspect and +reconcile state before submitting a new conditional request with a fresh +version and new ID, or no ID. Never change the payload under the original ID or +blindly switch IDs after a timeout. See the published +[image update workflow](https://docs.nvidia.com/openshell/latest/how-it-works/sandboxes/overview#update-the-image-of-a-stopped-sandbox) +and [API errors](https://docs.nvidia.com/openshell/latest/sdk/api-errors). + --- ## Workflow 4: Policy Iteration Loop diff --git a/tasks/test.toml b/tasks/test.toml index 7714d14dd4..d4b16d5026 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -240,7 +240,10 @@ run = "e2e/rust/e2e-podman.sh" ["e2e:kubernetes"] description = "Run Rust CLI e2e tests against an OpenShell gateway deployed on Kubernetes via Helm (set OPENSHELL_E2E_KUBE_CONTEXT to reuse a cluster; otherwise creates a local k3d cluster when k3d is installed; set OPENSHELL_E2E_KUBE_TEST= to scope to one test)" -run = "e2e/rust/e2e-kubernetes.sh" +# The reusable CI workflow exports an empty feature input by default. Restore +# the normal Rust suite here, not in the runner: the external-driver task +# intentionally passes an empty feature set for conformance-only coverage. +run = 'OPENSHELL_E2E_KUBERNETES_FEATURES="${OPENSHELL_E2E_KUBERNETES_FEATURES:-e2e,e2e-host-gateway,e2e-kubernetes}" e2e/rust/e2e-kubernetes.sh' ["e2e:kubernetes:v1alpha1"] description = "Run Kubernetes e2e against Agent Sandbox v1alpha1" From 706fe35774cfd09ae3b604d2fb4427ca78f2c390 Mon Sep 17 00:00:00 2001 From: sjenning <493891+sjenning@users.noreply.github.com> Date: Thu, 15 Oct 2026 20:21:01 +0000 Subject: [PATCH 02/23] feat(gateway): add storage-preserving sandbox image updates OpenClaw-Publication: b2036b09-b697-4d65-aba9-5c96a3198f9c Signed-off-by: sjenning <493891+sjenning@users.noreply.github.com> From b8829eea33473496db5e3a0c63930381450774d7 Mon Sep 17 00:00:00 2001 From: sjenning <493891+sjenning@users.noreply.github.com> Date: Thu, 15 Oct 2026 19:34:06 -0500 Subject: [PATCH 03/23] fix(gateway): preserve image update patch-release compatibility Move image updates to a separate authenticated service and retain the baseline public sandbox status. Persist image intent and revisions independently with atomic baseline-known lifecycle fencing and explicit post-upgrade activation. Preserve concurrent provisioning clocks, fence replaced attempts and delayed callbacks, and verify private-state transactions plus both Kubernetes controller API lanes. Signed-off-by: sjenning <493891+sjenning@users.noreply.github.com> --- .agents/skills/helm-dev-environment/SKILL.md | 18 + .../tests/ensure_providers_integration.rs | 7 - .../openshell-cli/tests/mtls_integration.rs | 7 - .../tests/provider_commands_integration.rs | 7 - .../sandbox_create_lifecycle_integration.rs | 7 - .../sandbox_exec_streaming_integration.rs | 7 - .../sandbox_name_fallback_integration.rs | 7 - crates/openshell-core/src/config.rs | 6 + .../src/image_update_tests.rs | 1 + .../src/routes.rs | 95 +- crates/openshell-sdk/src/client.rs | 19 +- crates/openshell-sdk/src/raw.rs | 22 +- crates/openshell-sdk/tests/client_mock.rs | 92 +- .../tests/sandbox_status_compatibility.rs | 31 + crates/openshell-server/build.rs | 4 +- .../proto/sandbox_image.proto | 25 + crates/openshell-server/src/cli.rs | 49 + .../src/compute/image_update.rs | 644 +++- crates/openshell-server/src/compute/mod.rs | 12 +- crates/openshell-server/src/config_file.rs | 3 + .../openshell-server/src/gateway_members.rs | 4 + crates/openshell-server/src/grpc/mod.rs | 17 +- .../src/grpc/mutation_replay.rs | 5 +- .../src/grpc/mutation_replay/ordinary.rs | 12 +- .../src/grpc/sandbox/image_update_tests.rs | 94 +- crates/openshell-server/src/lib.rs | 3 +- crates/openshell-server/src/multiplex.rs | 64 +- .../src/persistence/image_activation.rs | 315 ++ .../openshell-server/src/persistence/mod.rs | 2 + .../src/persistence/postgres.rs | 15 +- .../src/persistence/sandbox_image.rs | 1369 ++++++++ .../src/persistence/sqlite.rs | 2 +- crates/openshell-server/src/reflection.rs | 2 +- crates/openshell-server/src/storage_proto.rs | 49 +- crates/openshell-server/tests/common/mod.rs | 7 - .../tests/supervisor_relay_integration.rs | 7 - docs/how-it-works/gateways/configuration.mdx | 40 +- docs/how-it-works/sandboxes/overview.mdx | 58 +- docs/kubernetes/high-availability.mdx | 45 + docs/sdk/api-errors.mdx | 24 +- e2e/rust/tests/kubernetes_image_update.rs | 72 +- e2e/with-kube-gateway.sh | 6 + proto/openshell.proto | 39 +- sdk/go/proto/openshellv1/openshell.pb.go | 3055 ++++++++--------- sdk/go/proto/openshellv1/openshell_grpc.pb.go | 156 +- .../compatibility/sandbox_updates_test.go | 121 + sdk/typescript/src/raw.test.ts | 49 +- sdk/typescript/src/raw.ts | 2 +- skills/debug-openshell-cluster/SKILL.md | 40 + skills/openshell-cli/SKILL.md | 21 +- 50 files changed, 4716 insertions(+), 2042 deletions(-) create mode 100644 crates/openshell-sdk/tests/sandbox_status_compatibility.rs create mode 100644 crates/openshell-server/proto/sandbox_image.proto create mode 100644 crates/openshell-server/src/persistence/image_activation.rs create mode 100644 crates/openshell-server/src/persistence/sandbox_image.rs create mode 100644 sdk/go/tests/compatibility/sandbox_updates_test.go diff --git a/.agents/skills/helm-dev-environment/SKILL.md b/.agents/skills/helm-dev-environment/SKILL.md index 52b1d0bd48..a6e7c3a0d5 100644 --- a/.agents/skills/helm-dev-environment/SKILL.md +++ b/.agents/skills/helm-dev-environment/SKILL.md @@ -425,6 +425,24 @@ Set `OPENSHELL_E2E_KUBE_TEST=kubernetes_image_update` to scope the Rust suite to image replacement with retained sandbox, SSH, and PVC identities. This target is included in both existing Agent Sandbox API-version lanes; unlike the Python Docker suite, it exercises the driver that supports image updates. + +Image updates default to disabled outside test fixtures. The e2e wrapper opts +in only for a fresh gateway fixture that it owns; set +`OPENSHELL_E2E_KUBE_IMAGE_UPDATES=0` to prevent that opt-in. Do not propagate +activation to an existing shared gateway or enable it during a mixed-version +rollout. For manual testing, follow the retirement and activation checklist in +`docs/kubernetes/high-availability.mdx` before setting +`gatewayConfig: {"openshell.gateway": {enable_sandbox_image_updates: true}}`. +The gateway process equivalents are `--enable-sandbox-image-updates true` and +`OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES=true`. Retire every old process and Job, +settle outstanding driver work, prevent old binaries returning, and do not +treat PostgreSQL connection markers or membership TTL expiry as retirement +proof. SQLite testing supports one gateway process only. Image-update clients +must call the separate `SandboxUpdates` service on the existing gateway +listener, not add a method to the baseline `OpenShell` service or inspect new +public `SandboxStatus` image fields. Pending-operation recovery uses the same +requested image with a fresh version and the documented request-ID semantics. + The kube e2e wrapper creates only one port-forward, to `svc/openshell`; it no longer forwards the unauthenticated health listener or runs a `/readyz` e2e target. `/readyz` remains covered by server unit/integration tests. diff --git a/crates/openshell-cli/tests/ensure_providers_integration.rs b/crates/openshell-cli/tests/ensure_providers_integration.rs index c74d95b03d..be3e4f2e49 100644 --- a/crates/openshell-cli/tests/ensure_providers_integration.rs +++ b/crates/openshell-cli/tests/ensure_providers_integration.rs @@ -87,13 +87,6 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } - async fn update_sandbox( - &self, - _request: tonic::Request, - ) -> Result, Status> { - Err(Status::unimplemented("not implemented by test service")) - } - async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/mtls_integration.rs b/crates/openshell-cli/tests/mtls_integration.rs index 3b130be446..1017712035 100644 --- a/crates/openshell-cli/tests/mtls_integration.rs +++ b/crates/openshell-cli/tests/mtls_integration.rs @@ -39,13 +39,6 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } - async fn update_sandbox( - &self, - _request: tonic::Request, - ) -> Result, Status> { - Err(Status::unimplemented("not implemented by test service")) - } - async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/provider_commands_integration.rs b/crates/openshell-cli/tests/provider_commands_integration.rs index 124ac62fab..89247ba718 100644 --- a/crates/openshell-cli/tests/provider_commands_integration.rs +++ b/crates/openshell-cli/tests/provider_commands_integration.rs @@ -242,13 +242,6 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } - async fn update_sandbox( - &self, - _request: tonic::Request, - ) -> Result, Status> { - Err(Status::unimplemented("not implemented by test service")) - } - async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs index 29dd638d70..db9c02ffaf 100644 --- a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs +++ b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs @@ -108,13 +108,6 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } - async fn update_sandbox( - &self, - _request: tonic::Request, - ) -> Result, Status> { - Err(Status::unimplemented("not implemented by test service")) - } - async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs b/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs index 2c463f2466..31e67baf0f 100644 --- a/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs +++ b/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs @@ -163,13 +163,6 @@ macro_rules! mock_gateway { ) => { #[tonic::async_trait] impl OpenShell for MockGateway { - async fn update_sandbox( - &self, - _request: Request, - ) -> Result, Status> { - Err(Status::unimplemented("not implemented by test service")) - } - $(async fn $method(&self, _: Request<$request>) -> Result, Status> { Err(Status::unimplemented("unused test RPC")) })* diff --git a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs index e6f38ec7af..497f3ce778 100644 --- a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs +++ b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs @@ -54,13 +54,6 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } - async fn update_sandbox( - &self, - _request: tonic::Request, - ) -> Result, Status> { - Err(Status::unimplemented("not implemented by test service")) - } - async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-core/src/config.rs b/crates/openshell-core/src/config.rs index 27e5b80dd9..add555778e 100644 --- a/crates/openshell-core/src/config.rs +++ b/crates/openshell-core/src/config.rs @@ -252,6 +252,11 @@ pub struct Config { /// Disabled for local gateways by default. pub enable_websocket_tunnel: bool, + /// Operator activation after all gateways and outstanding legacy driver + /// operations have been drained onto the image-update-compatible protocol. + /// Disabled by default; not a license to run mixed-version writers. + pub enable_sandbox_image_updates: bool, + /// Disabled-by-default gateway interceptor service configs. pub gateway_interceptors: Vec, @@ -999,6 +1004,7 @@ impl Config { oidc: None, auth: GatewayAuthConfig::default(), enable_websocket_tunnel: false, + enable_sandbox_image_updates: false, gateway_interceptors: Vec::new(), provider_profile_sources: vec![GatewayProviderProfileSourceConfig::User], mtls_auth: MtlsAuthConfig::default(), diff --git a/crates/openshell-driver-kubernetes/src/image_update_tests.rs b/crates/openshell-driver-kubernetes/src/image_update_tests.rs index ba1fa44185..25ca24364f 100644 --- a/crates/openshell-driver-kubernetes/src/image_update_tests.rs +++ b/crates/openshell-driver-kubernetes/src/image_update_tests.rs @@ -206,6 +206,7 @@ fn fixture( sandbox_api_version: Arc::new(api_version), lifecycle_gates: Arc::default(), shared_supervisor: None, + network_trust_bundle: None, config: KubernetesComputeConfig { allow_driver_config: true, workspace_mode: if operator { diff --git a/crates/openshell-gateway-interceptors/src/routes.rs b/crates/openshell-gateway-interceptors/src/routes.rs index c436563ef2..dcb98ec5bc 100644 --- a/crates/openshell-gateway-interceptors/src/routes.rs +++ b/crates/openshell-gateway-interceptors/src/routes.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Interceptable `OpenShell` route classification. +//! Interceptable public gateway route classification. use std::collections::{BTreeMap, BTreeSet}; @@ -10,13 +10,16 @@ use prost_reflect::DescriptorPool; use crate::{InterceptorError, Result}; const SERVICE_OPEN_SHELL: &str = "openshell.v1.OpenShell"; +const SERVICE_SANDBOX_UPDATES: &str = "openshell.v1.SandboxUpdates"; + +/// Unary sandbox-update methods that may be targeted by gateway interceptors. +pub const INTERCEPTABLE_SANDBOX_UPDATE_METHODS: &[&str] = &["UpdateSandbox"]; /// Unary `openshell.v1.OpenShell` methods that may be targeted by gateway /// interceptors. New methods are non-interceptable until deliberately added /// here. pub const INTERCEPTABLE_METHODS: &[&str] = &[ "CreateSandbox", - "UpdateSandbox", "AttachSandboxProvider", "DetachSandboxProvider", "DeleteSandbox", @@ -59,25 +62,25 @@ impl OpenShellRouteIndex { } pub(crate) fn from_descriptor_pool(pool: &DescriptorPool) -> Result { - let service = pool - .get_service_by_name(SERVICE_OPEN_SHELL) - .ok_or_else(|| { - InterceptorError::Config(format!( - "descriptor set does not contain service '{SERVICE_OPEN_SHELL}'" - )) - })?; let mut all_methods = BTreeSet::new(); let mut unary_methods = BTreeSet::new(); let mut input_types = BTreeMap::new(); let mut output_types = BTreeMap::new(); - for method in service.methods() { - let name = method.name().to_string(); - all_methods.insert(name.clone()); - if !method.is_client_streaming() && !method.is_server_streaming() { - unary_methods.insert(name.clone()); - input_types.insert(name.clone(), method.input().full_name().to_string()); - output_types.insert(name, method.output().full_name().to_string()); + for service_name in [SERVICE_OPEN_SHELL, SERVICE_SANDBOX_UPDATES] { + let service = pool.get_service_by_name(service_name).ok_or_else(|| { + InterceptorError::Config(format!( + "descriptor set does not contain service '{service_name}'" + )) + })?; + for method in service.methods() { + let route = format!("{service_name}/{}", method.name()); + all_methods.insert(route.clone()); + if !method.is_client_streaming() && !method.is_server_streaming() { + unary_methods.insert(route.clone()); + input_types.insert(route.clone(), method.input().full_name().to_string()); + output_types.insert(route, method.output().full_name().to_string()); + } } } @@ -93,37 +96,45 @@ impl OpenShellRouteIndex { #[must_use] pub fn is_interceptable(&self, service: &str, method: &str) -> bool { - service == SERVICE_OPEN_SHELL - && self.unary_methods.contains(method) - && INTERCEPTABLE_METHODS.contains(&method) + let allowed = match service { + SERVICE_OPEN_SHELL => INTERCEPTABLE_METHODS, + SERVICE_SANDBOX_UPDATES => INTERCEPTABLE_SANDBOX_UPDATE_METHODS, + _ => return false, + }; + allowed.contains(&method) && self.unary_methods.contains(&format!("{service}/{method}")) } #[must_use] pub fn input_type(&self, service: &str, method: &str) -> Option<&str> { - if service == SERVICE_OPEN_SHELL && self.unary_methods.contains(method) { - self.input_types.get(method).map(String::as_str) - } else { - None - } + self.input_types + .get(&format!("{service}/{method}")) + .map(String::as_str) } #[must_use] pub fn output_type(&self, service: &str, method: &str) -> Option<&str> { - if service == SERVICE_OPEN_SHELL && self.unary_methods.contains(method) { - self.output_types.get(method).map(String::as_str) - } else { - None - } + self.output_types + .get(&format!("{service}/{method}")) + .map(String::as_str) } fn validate_interceptable_list(&self) -> Result<()> { let mut stale = Vec::new(); let mut streaming = Vec::new(); - for method in INTERCEPTABLE_METHODS { - if !self.all_methods.contains(*method) { - stale.push((*method).to_string()); - } else if !self.unary_methods.contains(*method) { - streaming.push((*method).to_string()); + for (service, methods) in [ + (SERVICE_OPEN_SHELL, INTERCEPTABLE_METHODS), + ( + SERVICE_SANDBOX_UPDATES, + INTERCEPTABLE_SANDBOX_UPDATE_METHODS, + ), + ] { + for method in methods { + let route = format!("{service}/{method}"); + if !self.all_methods.contains(&route) { + stale.push(route); + } else if !self.unary_methods.contains(&route) { + streaming.push(route); + } } } if !stale.is_empty() { @@ -154,6 +165,22 @@ mod tests { let index = OpenShellRouteIndex::from_descriptor_set(openshell_core::FILE_DESCRIPTOR_SET).unwrap(); assert!(index.is_interceptable("openshell.v1.OpenShell", "CreateSandbox")); + assert!(index.is_interceptable(SERVICE_SANDBOX_UPDATES, "UpdateSandbox")); + assert!(!index.is_interceptable(SERVICE_OPEN_SHELL, "UpdateSandbox")); + assert!(!index.is_interceptable(SERVICE_SANDBOX_UPDATES, "CreateSandbox")); + assert_eq!( + index.input_type(SERVICE_SANDBOX_UPDATES, "UpdateSandbox"), + Some("openshell.v1.UpdateSandboxRequest") + ); + assert_eq!( + index.output_type(SERVICE_SANDBOX_UPDATES, "UpdateSandbox"), + Some("openshell.v1.SandboxResponse") + ); + assert!( + index + .input_type(SERVICE_OPEN_SHELL, "UpdateSandbox") + .is_none() + ); assert!(index.is_interceptable("openshell.v1.OpenShell", "UpdateConfig")); assert!(index.is_interceptable("openshell.v1.OpenShell", "SubmitPolicyAnalysis")); assert!(!index.is_interceptable("openshell.v1.OpenShell", "Health")); diff --git a/crates/openshell-sdk/src/client.rs b/crates/openshell-sdk/src/client.rs index 59f0dacb74..1f03916ef2 100644 --- a/crates/openshell-sdk/src/client.rs +++ b/crates/openshell-sdk/src/client.rs @@ -12,7 +12,7 @@ use crate::auth::{BearerSlot, EdgeAuthInterceptor, bearer_metadata}; use crate::config::{AuthConfig, ClientConfig}; use crate::error::{Result, SdkError}; use crate::pagination::{Page, Pager}; -use crate::raw::AuthedGrpcClient; +use crate::raw::{AuthedGrpcClient, AuthedSandboxUpdatesClient}; use crate::refresh::{RefreshedToken, TokenSource}; use crate::routing::OwnerCache; use crate::types::{ @@ -122,6 +122,23 @@ impl OpenShellClient { Ok(self.raw_grpc()) } + /// Authenticated client for the optional `SandboxUpdates` service, sharing + /// this client's channel and live bearer slot. Like [`Self::raw_grpc`], this + /// does not refresh or retry OIDC credentials by itself. + pub fn raw_sandbox_updates(&self) -> AuthedSandboxUpdatesClient { + proto::sandbox_updates_client::SandboxUpdatesClient::with_interceptor( + self.channel.clone(), + self.interceptor.clone(), + ) + } + + /// Like [`Self::raw_sandbox_updates`], but refreshes the bearer token first + /// when needed. Reactive retry remains the raw caller's responsibility. + pub async fn raw_sandbox_updates_fresh(&self) -> Result { + self.ensure_fresh().await?; + Ok(self.raw_sandbox_updates()) + } + /// Force an OIDC refresh and write the new token into the live bearer /// slot, regardless of expiry. Returns `true` when a refresher is wired /// and a fresh token was minted, `false` for static auth. Use after a diff --git a/crates/openshell-sdk/src/raw.rs b/crates/openshell-sdk/src/raw.rs index cbdf1d2b4a..a22e98cadb 100644 --- a/crates/openshell-sdk/src/raw.rs +++ b/crates/openshell-sdk/src/raw.rs @@ -20,6 +20,7 @@ pub use openshell_core::proto; pub use openshell_core::proto::open_shell_client::OpenShellClient as GrpcClient; +pub use openshell_core::proto::sandbox_updates_client::SandboxUpdatesClient; pub use openshell_core::proto::{ CreateSandboxRequest, CreateSandboxTemplateRequest, CreateWorkspaceRequest, DeleteSandboxRequest, DeleteSandboxTemplateRequest, DeleteWorkspaceRequest, ExecSandboxRequest, @@ -28,12 +29,12 @@ pub use openshell_core::proto::{ ListSandboxTemplatesRequest, ListSandboxesRequest, ListWorkspacesRequest, ProviderDesiredIdentity, ProviderMutationKind, ProviderMutationReceipt, ProviderReadinessObservation, ProviderReadinessReason, ProviderReadinessState, - ProviderReadinessStatus, ResumeSandboxRequest, Sandbox, SandboxImageUpdate, - SandboxPhase as ProtoSandboxPhase, SandboxResources, SandboxServiceLevel, - SandboxSpec as ProtoSandboxSpec, SandboxStartup, SandboxTemplate, SandboxTemplateResponse, - SandboxWorkloadConfig, SandboxWorkloadTemplate, SandboxWorkloadTemplateProvenance, - SandboxWorkloadTemplateSpec, ServiceStatus as ProtoServiceStatus, StartSandboxRequest, - StopSandboxRequest, SuspendSandboxRequest, UpdateSandboxRequest, Workspace, + ProviderReadinessStatus, ResumeSandboxRequest, Sandbox, SandboxPhase as ProtoSandboxPhase, + SandboxResources, SandboxServiceLevel, SandboxSpec as ProtoSandboxSpec, SandboxStartup, + SandboxTemplate, SandboxTemplateResponse, SandboxWorkloadConfig, SandboxWorkloadTemplate, + SandboxWorkloadTemplateProvenance, SandboxWorkloadTemplateSpec, + ServiceStatus as ProtoServiceStatus, StartSandboxRequest, StopSandboxRequest, + SuspendSandboxRequest, UpdateSandboxRequest, Workspace, }; /// Type alias for the gRPC client wrapped in the SDK's auth interceptor. @@ -43,3 +44,12 @@ pub type AuthedGrpcClient = GrpcClient< crate::EdgeAuthInterceptor, >, >; + +/// Sandbox-updates client using the same live auth slot and transport as the +/// main service client. +pub type AuthedSandboxUpdatesClient = SandboxUpdatesClient< + tonic::service::interceptor::InterceptedService< + tonic::transport::Channel, + crate::EdgeAuthInterceptor, + >, +>; diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index 21d524458a..4e50b95bb8 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -10,6 +10,7 @@ use openshell_core::proto; use openshell_core::proto::open_shell_server::{OpenShell, OpenShellServer}; +use openshell_core::proto::sandbox_updates_server::{SandboxUpdates, SandboxUpdatesServer}; use openshell_core::replica_routing; use openshell_sdk::{ AuthConfig, ClientConfig, ExecOptions, ListOptions, OpenShellClient, Refresh, RefreshError, @@ -60,6 +61,8 @@ struct MockState { last_start: Mutex>, last_suspend: Mutex>, last_resume: Mutex>, + + last_update: Mutex>, last_list_request: Mutex>, list_requests: Mutex>, last_exec_request: Mutex>, @@ -249,13 +252,6 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } - async fn update_sandbox( - &self, - _request: tonic::Request, - ) -> Result, Status> { - Err(Status::unimplemented("not implemented by test service")) - } - async fn peer_report_provider_readiness( &self, _request: tonic::Request, @@ -1179,16 +1175,40 @@ impl OpenShell for TestOpenShell { } } +#[tonic::async_trait] +impl SandboxUpdates for TestOpenShell { + async fn update_sandbox( + &self, + request: tonic::Request, + ) -> Result, Status> { + if let Some(expected) = &self.state.require_bearer { + let got = request + .metadata() + .get("authorization") + .and_then(|value| value.to_str().ok()); + if got != Some(expected.as_str()) { + return Err(Status::unauthenticated("invalid or missing bearer token")); + } + } + *self.state.last_update.lock().await = Some(request.into_inner()); + Ok(Response::new(proto::SandboxResponse::default())) + } +} + /// Spin up the mock gateway, return its endpoint URL. async fn start_mock(state: Arc) -> String { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); let addr = listener.local_addr().unwrap(); let endpoint = format!("http://{addr}"); let stream = TcpListenerStream::new(listener); + let updates = SandboxUpdatesServer::new(TestOpenShell { + state: state.clone(), + }); let svc = OpenShellServer::new(TestOpenShell { state }); tokio::spawn(async move { let _ = tonic::transport::Server::builder() .add_service(svc) + .add_service(updates) .serve_with_incoming(stream) .await; }); @@ -2378,6 +2398,64 @@ async fn raw_grpc_fresh_refreshes_before_raw_call() { ); } +#[tokio::test] +async fn raw_sandbox_updates_shares_transport_and_live_auth_slot() { + let state = Arc::new(MockState { + require_bearer: Some("Bearer fresh-token".to_string()), + ..Default::default() + }); + let endpoint = start_mock(state.clone()).await; + let calls = Arc::new(AtomicU32::new(0)); + let mut config = ClientConfig::new(&endpoint); + config.auth = Some(AuthConfig::Oidc { + token: "stale-token".to_string(), + expires_at: Some( + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() + + 5, + ), + refresh: Some(Arc::new(OneShotRefresher { + calls: calls.clone(), + })), + }); + let client = OpenShellClient::connect(config).await.unwrap(); + let mut updates = client.raw_sandbox_updates(); + let request = proto::UpdateSandboxRequest { + workspace_scope: Some(proto::workspace_selector("team")), + name: "sandbox".into(), + image: "example/workload:new".into(), + expected_resource_version: 42, + request_id: "550e8400-e29b-41d4-a716-446655440000".into(), + }; + assert_eq!( + updates + .update_sandbox(request.clone()) + .await + .unwrap_err() + .code(), + tonic::Code::Unauthenticated + ); + assert_eq!(calls.load(Ordering::SeqCst), 0); + client + .raw_sandbox_updates_fresh() + .await + .unwrap() + .update_sandbox(request.clone()) + .await + .unwrap(); + assert_eq!(calls.load(Ordering::SeqCst), 1); + // Previously created raw clients read the same refreshed bearer slot. + updates.update_sandbox(request.clone()).await.unwrap(); + client + .raw_grpc() + .health(proto::HealthRequest {}) + .await + .unwrap(); + assert_eq!(*state.last_update.lock().await, Some(request)); +} + #[tokio::test] async fn watch_logs_forwards_logs_and_warnings() { let state = Arc::new(MockState { diff --git a/crates/openshell-sdk/tests/sandbox_status_compatibility.rs b/crates/openshell-sdk/tests/sandbox_status_compatibility.rs new file mode 100644 index 0000000000..7a080a381f --- /dev/null +++ b/crates/openshell-sdk/tests/sandbox_status_compatibility.rs @@ -0,0 +1,31 @@ +// 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. + +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. + let status = SandboxStatus { + agent_pod: String::new(), + agent_fd: String::new(), + sandbox_fd: String::new(), + conditions: Vec::new(), + phase: 0, + current_policy_version: 0, + main_process_instance_id: String::new(), + exit_code: None, + endpoint_statuses: Vec::new(), + configuration_admission: None, + configuration_activated: None, + provisioning: None, + restart_count: 0, + next_restart_time: None, + main_process_started_time: None, + last_token_grant_failure: None, + }; + assert_eq!(status, SandboxStatus::default()); +} diff --git a/crates/openshell-server/build.rs b/crates/openshell-server/build.rs index c061cb0b6d..6230f8d259 100644 --- a/crates/openshell-server/build.rs +++ b/crates/openshell-server/build.rs @@ -30,8 +30,10 @@ fn main() -> Result<(), Box> { let storage_proto_dir = manifest_dir.join("proto"); let public_proto_dir = manifest_dir.join("../../proto"); let storage_proto = storage_proto_dir.join("storage.proto"); + let image_proto = storage_proto_dir.join("sandbox_image.proto"); println!("cargo:rerun-if-changed={}", storage_proto.display()); + println!("cargo:rerun-if-changed={}", image_proto.display()); for imported_proto in [ "datamodel.proto", "openshell.proto", @@ -71,7 +73,7 @@ fn main() -> Result<(), Box> { "::openshell_core::proto::sandbox::v1", ) .file_descriptor_set_path(&descriptor_path) - .compile_with_config(proto_config, &[storage_proto], &include_dirs)?; + .compile_with_config(proto_config, &[storage_proto, image_proto], &include_dirs)?; Ok(()) } diff --git a/crates/openshell-server/proto/sandbox_image.proto b/crates/openshell-server/proto/sandbox_image.proto new file mode 100644 index 0000000000..8d3e3f030d --- /dev/null +++ b/crates/openshell-server/proto/sandbox_image.proto @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +syntax = "proto3"; + +// A new private format; frozen openshell.storage.v1 remains unchanged. +package openshell.storage.image.v1; +import "openshell.proto"; + +// Gateway-private image mutation state. Never embed this in public SandboxStatus: +// older gateways may rewrite public protobufs without retaining unknown fields. +message StoredSandboxImageUpdate { + string operation_id = 1; + string previous_image = 2; + string image = 3; + uint64 revision = 4; +} + +message StoredSandboxImageState { + string sandbox_id = 1; + uint64 revision = 2; + StoredSandboxImageUpdate pending = 3; + // Original presence and attempt identity while the interlock is held. + // Completion preserves newer diagnostics and clock edits on the live record. + openshell.v1.SandboxProvisioning previous_provisioning = 4; +} diff --git a/crates/openshell-server/src/cli.rs b/crates/openshell-server/src/cli.rs index 9b16b53914..ae7fdfe560 100644 --- a/crates/openshell-server/src/cli.rs +++ b/crates/openshell-server/src/cli.rs @@ -313,6 +313,11 @@ struct RunArgs { action = ArgAction::Set )] enable_websocket_tunnel: bool, + + /// Activate image updates only after retiring every incompatible gateway + /// and settling its outstanding driver operations. See HA upgrade guidance. + #[arg(long, env = "OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES", default_value_t = false, action = ArgAction::Set)] + enable_sandbox_image_updates: bool, } pub fn command() -> Command { @@ -594,6 +599,8 @@ fn prepare_server_config_with_drivers( .service_routing .validate(&config.name) .map_err(|error| miette::miette!("invalid service routing configuration: {error}"))?; + + config.enable_sandbox_image_updates = args.enable_sandbox_image_updates; if let Some(sources) = file .as_ref() .and_then(|file| file.openshell.gateway.provider_profile_sources.clone()) @@ -1379,6 +1386,11 @@ fn merge_file_into_args(args: &mut RunArgs, file: &GatewayFileSection, matches: { args.enable_websocket_tunnel = enabled; } + if let Some(enabled) = file.enable_sandbox_image_updates + && arg_defaulted(matches, "enable_sandbox_image_updates") + { + args.enable_sandbox_image_updates = enabled; + } if let Some(mtls_auth) = &file.mtls_auth && arg_defaulted(matches, "enable_mtls_auth") { @@ -3095,6 +3107,43 @@ mod tests { toml::from_str(toml).expect("valid TOML in test fixture") } + #[test] + fn image_update_activation_defaults_off_and_file_requires_explicit_opt_in() { + Environment::new().remove("OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES").run(|| { + let (mut args, matches) = parse_with_args(&["openshell-gateway"]); + assert!(!args.enable_sandbox_image_updates); + assert!(!openshell_core::Config::new(None).enable_sandbox_image_updates); + let file = config_file_from_toml("[openshell]\nversion = 2\n[openshell.gateway]\nenable_sandbox_image_updates = true\n"); + merge_file_into_args(&mut args, &file.openshell.gateway, &matches); + assert!(args.enable_sandbox_image_updates); + }); + } + + #[test] + fn explicit_cli_or_environment_disable_overrides_file_activation() { + let file = config_file_from_toml( + "[openshell]\nversion = 2\n[openshell.gateway]\nenable_sandbox_image_updates = true\n", + ); + Environment::new() + .remove("OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES") + .run(|| { + let (mut args, matches) = parse_with_args(&[ + "openshell-gateway", + "--enable-sandbox-image-updates", + "false", + ]); + merge_file_into_args(&mut args, &file.openshell.gateway, &matches); + assert!(!args.enable_sandbox_image_updates); + }); + Environment::new() + .set("OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES", "false") + .run(|| { + let (mut args, matches) = parse_with_args(&["openshell-gateway"]); + merge_file_into_args(&mut args, &file.openshell.gateway, &matches); + assert!(!args.enable_sandbox_image_updates); + }); + } + #[test] fn rejects_legacy_drivers_flag() { let error = command() diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs index 5b48e93b87..3eb11f65f3 100644 --- a/crates/openshell-server/src/compute/image_update.rs +++ b/crates/openshell-server/src/compute/image_update.rs @@ -1,27 +1,47 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Stopped-only image changes. Persist intent before touching the driver so a -//! lost response cannot allow Start to run a different image than the gateway. +//! Stopped-only image changes with private durable intent and an operation +//! interlock understood by supported older gateways. -use super::{ - ComputeRuntime, START_PHASE_CAS_RETRY_LIMIT, provisioning_operation, - sandbox_compute_runtime_identity, -}; +use super::{ComputeRuntime, provisioning_operation, sandbox_compute_runtime_identity}; +use crate::storage_proto::StoredSandboxImageUpdate as SandboxImageUpdate; use openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE; use openshell_core::proto::compute::v1::UpdateSandboxImageRequest; -use openshell_core::proto::{Sandbox, SandboxImageUpdate, SandboxPhase}; +use openshell_core::proto::{Sandbox, SandboxPhase}; use openshell_core::{GetResourceVersion, ObjectId, ObjectName}; use tonic::{Request, Status}; use tracing::info; impl ComputeRuntime { + pub(crate) fn with_sandbox_image_updates(mut self, enabled: bool) -> Self { + self.image_updates_enabled = enabled; + self + } + pub(crate) async fn update_sandbox_image( &self, sandbox_id: &str, image: String, expected_resource_version: u64, ) -> Result { + // Explicit operator activation follows retirement of incompatible + // gateways and their outstanding driver work. Refuse before preflight + // or durable effects; a cached placement ring is not a version proof. + if !self.image_updates_enabled { + return Err(Status::failed_precondition( + "sandbox image updates are disabled; complete the compatible deployment rollout before activating them", + )); + } + self.store + .ensure_image_update_deployment_compatible() + .await + .map_err(|error| match error { + crate::persistence::PersistenceError::Config(message) => { + Status::failed_precondition(message) + } + _ => Status::unavailable("cannot verify image-update deployment compatibility"), + })?; if !self .driver_info .negotiated_extension @@ -39,7 +59,7 @@ impl ComputeRuntime { .store .get_message::(sandbox_id) .await - .map_err(|error| Status::internal(format!("fetch sandbox failed: {error}")))? + .map_err(|_| Status::internal("fetch sandbox failed"))? .ok_or_else(|| Status::not_found("sandbox not found"))?; ensure_image_update_stopped(¤t)?; if current.get_resource_version() != expected_resource_version { @@ -50,6 +70,22 @@ impl ComputeRuntime { "update sandbox image", )); } + let state = self + .store + .get_sandbox_image_state(sandbox_id) + .await + .map_err(|_| Status::internal("fetch private sandbox image state failed"))?; + let pending = state.as_ref().and_then(|state| state.pending.clone()); + if let Some(intent) = &pending { + ensure_image_update_interlock(¤t, intent)?; + if intent.image != image { + return Err(Status::failed_precondition( + "another image update is pending; retry that image before selecting a different image", + )); + } + } else { + provisioning_operation::ensure_operation_settled(¤t)?; + } let old_image = current .spec .as_ref() @@ -57,42 +93,24 @@ impl ComputeRuntime { .map(|template| template.image.clone()) .filter(|image| !image.is_empty()) .ok_or_else(|| Status::failed_precondition("sandbox has no workload image"))?; - let pending = current - .status - .as_ref() - .and_then(|status| status.image_update.clone()); - if pending - .as_ref() - .is_some_and(|pending| pending.image != image) - { - return Err(Status::failed_precondition( - "another image update is pending; retry that image before selecting a different image", - )); - } if pending.is_none() && old_image == image { return Ok(current); } - let intent = if let Some(intent) = pending { - intent + let revision = state.as_ref().map_or(0, |state| state.revision); + let intent = pending.clone().unwrap_or_else(|| SandboxImageUpdate { + operation_id: uuid::Uuid::new_v4().to_string(), + previous_image: old_image, + image, + revision: revision.saturating_add(1), + }); + if pending.is_none() && revision == u64::MAX { + return Err(Status::resource_exhausted( + "sandbox image revision exhausted", + )); + } + let accepted = if pending.is_some() { + current } else { - let revision = current - .status - .as_ref() - .map_or(0, |status| status.image_revision) - .checked_add(1) - .ok_or_else(|| Status::resource_exhausted("sandbox image revision exhausted"))?; - SandboxImageUpdate { - operation_id: uuid::Uuid::new_v4().to_string(), - previous_image: old_image, - image: image.clone(), - revision, - } - }; - if current - .status - .as_ref() - .is_none_or(|status| status.image_update.is_none()) - { let request = image_update_driver_request(¤t, &intent, true); self.driver .call_owned( @@ -103,52 +121,32 @@ impl ComputeRuntime { }, ) .await?; - } - let pending = if current - .status - .as_ref() - .is_some_and(|status| status.image_update.is_some()) - { - current - } else { - let intent_for_write = intent.clone(); + // The private intent, desired image, and OLD-understood pending + // operation flag commit in one version-fenced transaction. self.store - .update_message_cas::( + .begin_sandbox_image_update( sandbox_id, expected_resource_version, - move |sandbox| { - sandbox - .spec - .as_mut() - .expect("validated spec") - .template - .as_mut() - .expect("validated template") - .image - .clone_from(&image); - let status = sandbox.status.get_or_insert_with(Default::default); - status.image_revision = intent_for_write.revision; - status.image_update = Some(intent_for_write.clone()); - }, + revision, + &intent, ) .await .map_err(|error| { crate::grpc::persistence_error_to_status(error, "record sandbox image update") })? }; - self.sandbox_index.update_from_sandbox(&pending); + self.sandbox_index.update_from_sandbox(&accepted); self.sandbox_watch_bus.notify(sandbox_id); drop(sandbox_guard); - - // The durable intent commits ownership. Cancellation of the public RPC - // must not release the lifecycle gate while the driver can still apply. let runtime = self.clone(); tokio::spawn(async move { let _lifecycle_guard = lifecycle_guard; - runtime.complete_image_update(pending, intent).await + runtime.complete_image_update(accepted, intent).await }) .await - .map_err(|error| Status::internal(format!("sandbox image update worker failed: {error}")))? + .map_err(|_| { + Status::internal("sandbox image update worker failed; intent remains pending") + })? } async fn complete_image_update( @@ -156,66 +154,62 @@ impl ComputeRuntime { pending: Sandbox, intent: SandboxImageUpdate, ) -> Result { + ensure_image_update_interlock(&pending, &intent)?; let request = image_update_driver_request(&pending, &intent, false); - self.driver - .call_owned(openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, Some(pending.object_id()), move |driver| async move { - driver.update_sandbox_image(Request::new(request)).await - }) - .await?; - - // Watchers may have advanced the resource version. Never restore an old - // record or overwrite a concurrent deletion to acknowledge the driver. + self.driver.call_owned(openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, Some(pending.object_id()), + move |driver| async move { driver.update_sandbox_image(Request::new(request)).await }).await?; let _guard = self.lock_sandbox_local(pending.object_id()).await; - for _ in 0..START_PHASE_CAS_RETRY_LIMIT { - let current = self - .store - .get_message::(pending.object_id()) - .await - .map_err(|error| Status::internal(format!("reload image update failed: {error}")))? - .ok_or_else(|| Status::not_found("sandbox was deleted"))?; - ensure_image_update_stopped(¤t)?; - if current - .status - .as_ref() - .and_then(|status| status.image_update.as_ref()) - != Some(&intent) - { - return Err(Status::aborted("sandbox image update intent changed")); - } - match self - .store - .update_message_cas::( - pending.object_id(), - current.get_resource_version(), - |sandbox| { - sandbox - .status - .as_mut() - .expect("pending status") - .image_update = None; - }, - ) - .await - { - Ok(updated) => { - self.sandbox_index.update_from_sandbox(&updated); - self.sandbox_watch_bus.notify(updated.object_id()); - info!(sandbox_id = %updated.object_id(), operation_id = %intent.operation_id, "Sandbox workload image updated; sandbox remains stopped"); - return Ok(updated); - } - Err(crate::persistence::PersistenceError::Conflict { .. }) => {} - Err(error) => { - return Err(crate::grpc::persistence_error_to_status( - error, - "complete sandbox image update", - )); - } - } + // An ambiguous error NEVER clears either the private intent or the + // public operation interlock. Only exact successful reconciliation can. + let updated = self + .store + .complete_sandbox_image_update(pending.object_id(), &intent) + .await + .map_err(|error| { + crate::grpc::persistence_error_to_status(error, "complete sandbox image update") + })?; + self.sandbox_index.update_from_sandbox(&updated); + self.sandbox_watch_bus.notify(updated.object_id()); + info!(sandbox_id = %updated.object_id(), operation_id = %intent.operation_id, + "Sandbox workload image updated; sandbox remains stopped"); + Ok(updated) + } + + pub(super) async fn ensure_no_pending_image_update( + &self, + sandbox: &Sandbox, + ) -> Result<(), Status> { + let state = self + .store + .get_sandbox_image_state(sandbox.object_id()) + .await + .map_err(|_| Status::unavailable("cannot read private sandbox image state"))?; + if state.as_ref().is_some_and(|state| state.pending.is_some()) { + return Err(Status::failed_precondition( + "sandbox image update is pending; read the current resource version and retry UpdateSandbox with the same image before starting", + )); } - Err(Status::aborted( - "sandbox changed while acknowledging image update; read and retry the pending image", - )) + Ok(()) + } +} + +fn ensure_image_update_interlock( + sandbox: &Sandbox, + intent: &SandboxImageUpdate, +) -> Result<(), Status> { + if sandbox + .status + .as_ref() + .and_then(|status| status.provisioning.as_ref()) + .is_none_or(|record| { + !record.driver_operation_pending || record.driver_operation_id != intent.operation_id + }) + { + return Err(Status::aborted( + "sandbox image-update operation interlock changed", + )); } + Ok(()) } fn image_update_driver_request( @@ -236,7 +230,6 @@ fn image_update_driver_request( } fn ensure_image_update_stopped(sandbox: &Sandbox) -> Result<(), Status> { - provisioning_operation::ensure_operation_settled(sandbox)?; if sandbox.phase() != SandboxPhase::Stopped as i32 || sandbox .metadata @@ -250,22 +243,6 @@ fn ensure_image_update_stopped(sandbox: &Sandbox) -> Result<(), Status> { Ok(()) } -/// Checked both before and after lifecycle locking by Start. A failed driver -/// response does not prove it had no effects, so only a successful retry clears -/// the durable intent. Ordinary stop and deletion never clear it. -pub(super) fn ensure_no_pending_image_update(sandbox: &Sandbox) -> Result<(), Status> { - if sandbox - .status - .as_ref() - .is_some_and(|status| status.image_update.is_some()) - { - return Err(Status::failed_precondition( - "sandbox image update is pending; read the current resource version and retry UpdateSandbox with the same image before starting", - )); - } - Ok(()) -} - #[cfg(test)] mod tests { use super::*; @@ -300,6 +277,7 @@ mod tests { ) .await .unwrap(); + runtime.image_updates_enabled = true; if supported { runtime .driver_info @@ -380,8 +358,15 @@ mod tests { original.metadata.as_ref().unwrap().labels ); assert_eq!(updated.phase(), SandboxPhase::Stopped as i32); - assert!(updated.status.as_ref().unwrap().image_update.is_none()); - assert_eq!(updated.status.as_ref().unwrap().image_revision, 1); + let state = runtime + .store + .get_sandbox_image_state(updated.object_id()) + .await + .unwrap() + .unwrap(); + assert!(state.pending.is_none()); + assert_eq!(state.revision, 1); + assert_eq!(updated.status, original.status); let calls = image_calls(&driver); assert_eq!(calls.len(), 1); assert_eq!(calls[0].expected_image, "example/workload:old"); @@ -416,7 +401,16 @@ mod tests { ) .await .unwrap(); - assert_eq!(back.status.as_ref().unwrap().image_revision, 2); + assert_eq!( + runtime + .store + .get_sandbox_image_state(back.object_id()) + .await + .unwrap() + .unwrap() + .revision, + 2 + ); assert_eq!(image_calls(&driver)[1].revision, 2); } @@ -575,6 +569,13 @@ mod tests { ) .await .unwrap(); + let upgraded_revision = runtime + .store + .get_sandbox_image_state(upgraded.object_id()) + .await + .unwrap() + .unwrap() + .revision; let starting = runtime .start_sandbox("default", original.object_name()) .await @@ -669,8 +670,14 @@ mod tests { .await .unwrap(); assert_eq!( - corrected.status.as_ref().unwrap().image_revision, - upgraded.status.as_ref().unwrap().image_revision + 1 + runtime + .store + .get_sandbox_image_state(corrected.object_id()) + .await + .unwrap() + .unwrap() + .revision, + upgraded_revision + 1 ); assert_eq!(corrected.object_id(), original.object_id()); assert_eq!( @@ -729,7 +736,16 @@ mod tests { .await .unwrap() .unwrap(); - assert!(pending.status.as_ref().unwrap().image_update.is_some()); + assert!( + runtime + .store + .get_sandbox_image_state(pending.object_id()) + .await + .unwrap() + .unwrap() + .pending + .is_some() + ); assert_eq!( runtime .start_sandbox("default", original.object_name()) @@ -759,44 +775,336 @@ mod tests { ) .await .unwrap(); - assert!(complete.status.as_ref().unwrap().image_update.is_none()); + assert!( + runtime + .store + .get_sandbox_image_state(complete.object_id()) + .await + .unwrap() + .unwrap() + .pending + .is_none() + ); let calls = image_calls(&driver); assert_eq!(calls.len(), 2); assert_eq!(calls[0], calls[1]); } - #[test] - fn image_update_intent_survives_driver_status_replacement() { - let intent = SandboxImageUpdate { - operation_id: "operation".into(), - previous_image: "old".into(), - image: "new".into(), - revision: 1, - }; + #[tokio::test] + async fn image_update_intent_survives_driver_status_replacement() { + let (runtime, driver, original) = fixture(true).await; + driver.set_image_update_error(Some(Code::Unavailable)); + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + let expected = runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap(); + let mut sandbox = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); let grant_failure = Box::new(openshell_core::proto::TokenGrantFailureObservation { destination_host: "api.example.com".into(), ..Default::default() }); - let mut sandbox = Sandbox::default(); - sandbox.set_phase(SandboxPhase::Stopped as i32); - let status = sandbox.status.as_mut().unwrap(); - status.image_update = Some(intent.clone()); - status.image_revision = 1; - status.last_token_grant_failure = Some(grant_failure.clone()); + sandbox.status.as_mut().unwrap().last_token_grant_failure = Some(grant_failure.clone()); let incoming = DriverSandbox { - name: "test".into(), + id: original.object_id().into(), + name: original.object_name().into(), status: Some(DriverSandboxStatus::default()), ..Default::default() }; apply_driver_snapshot(&mut sandbox, &incoming, false, false); + runtime.store.put_message(&sandbox).await.unwrap(); assert_eq!( - sandbox.status.as_ref().unwrap().image_update.as_ref(), - Some(&intent) + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap(), + expected + ); + assert!( + sandbox + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .unwrap() + .driver_operation_pending ); - assert_eq!(sandbox.status.as_ref().unwrap().image_revision, 1); assert_eq!( sandbox.status.as_ref().unwrap().last_token_grant_failure, Some(grant_failure) ); + assert_eq!( + runtime + .start_sandbox("default", original.object_name()) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + } + + #[tokio::test] + async fn image_update_activation_is_disabled_by_default_without_effects() { + let (mut runtime, driver, original) = fixture(true).await; + runtime.image_updates_enabled = false; + assert_eq!( + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + original.get_resource_version() + ) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + assert!( + !driver + .calls() + .iter() + .any(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxImage { .. })) + ); + assert_eq!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(), + original + ); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_none() + ); + } + // These are the relevant pre-feature wire fields: no image-update fields + // exist in public status. Older readers already understand provisioning. + #[derive(Clone, PartialEq, prost::Message)] + struct LegacyStatus014 { + #[prost(int32, tag = "6")] + phase: i32, + #[prost(message, optional, tag = "13")] + provisioning: Option, + } + + #[tokio::test] + async fn legacy_status_roundtrip_cannot_erase_intent_or_bypass_lifecycle_interlock() { + use prost::Message; + let (runtime, driver, original) = fixture(true).await; + driver.set_image_update_error(Some(Code::Unavailable)); + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + let private_before = runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap(); + let mut pending = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + let legacy = + LegacyStatus014::decode(pending.status.as_ref().unwrap().encode_to_vec().as_slice()) + .unwrap(); + assert!( + legacy + .provisioning + .as_ref() + .unwrap() + .driver_operation_pending + ); + pending.status = Some( + openshell_core::proto::SandboxStatus::decode(legacy.encode_to_vec().as_slice()) + .unwrap(), + ); + runtime.store.put_message(&pending).await.unwrap(); + let rewritten = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + assert_eq!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap(), + private_before + ); + // This existing guard is also present in v0.1.4, unlike our private check. + assert_eq!( + provisioning_operation::ensure_operation_settled(&rewritten) + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + assert_eq!( + runtime + .start_sandbox("default", original.object_name()) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + assert_eq!( + runtime + .stop_sandbox("default", original.object_name()) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + assert_eq!( + runtime + .delete_sandbox("default", original.object_name()) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + runtime + .recover_persisted_lifecycle_transitions() + .await + .unwrap(); + assert!(!driver.calls().iter().any(|call| matches!( + call, + FakeComputeDriverCall::StartSandbox { .. } + | FakeComputeDriverCall::StopSandbox { .. } + | FakeComputeDriverCall::DeleteSandbox { .. } + ))); + driver.set_image_update_error(None); + let complete = runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + rewritten.get_resource_version(), + ) + .await + .unwrap(); + assert!(provisioning_operation::ensure_operation_settled(&complete).is_ok()); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap() + .pending + .is_none() + ); + } + + #[tokio::test] + async fn stale_legacy_start_cas_loses_to_atomic_image_acceptance() { + let (runtime, driver, original) = fixture(true).await; + // Model an old Start paused after reading Stopped but before its CAS. + driver.set_image_update_error(Some(Code::Unavailable)); + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + let stale_start = runtime + .store + .update_message_cas::( + original.object_id(), + original.get_resource_version(), + |sandbox| sandbox.set_phase(SandboxPhase::Starting as i32), + ) + .await; + assert!(matches!( + stale_start, + Err(crate::persistence::PersistenceError::Conflict { .. }) + )); + let current = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + assert!(provisioning_operation::ensure_operation_settled(¤t).is_err()); + assert!( + !driver + .calls() + .iter() + .any(|call| matches!(call, FakeComputeDriverCall::StartSandbox { .. })) + ); + } + + #[tokio::test] + async fn image_acceptance_loses_if_legacy_start_already_claimed_starting() { + let (runtime, driver, original) = fixture(true).await; + let starting = runtime + .store + .update_message_cas::( + original.object_id(), + original.get_resource_version(), + |sandbox| sandbox.set_phase(SandboxPhase::Starting as i32), + ) + .await + .unwrap(); + assert_eq!( + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + starting.get_resource_version() + ) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_none() + ); + assert!( + !driver + .calls() + .iter() + .any(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxImage { .. })) + ); } } diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index 32bfd0b064..e41c9a04ff 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -900,6 +900,7 @@ pub struct ComputeRuntime { driver_process: Option>, default_image: String, image_preparation_timeout_seconds: u32, + image_updates_enabled: bool, store: Arc, sandbox_index: SandboxIndex, sandbox_watch_bus: SandboxWatchBus, @@ -1016,6 +1017,7 @@ impl ComputeRuntime { driver_process, default_image, image_preparation_timeout_seconds: 1800, + image_updates_enabled: false, store, sandbox_index, sandbox_watch_bus, @@ -2301,7 +2303,7 @@ impl ComputeRuntime { self.validate_launch_signer_configured(authority.is_some())?; } provisioning_operation::ensure_operation_settled(&candidate)?; - image_update::ensure_no_pending_image_update(&candidate)?; + self.ensure_no_pending_image_update(&candidate).await?; if provisioning_deadline::timed_out(&candidate) && candidate .status @@ -2339,7 +2341,7 @@ impl ComputeRuntime { let mut attempts = 0; let (previous, starting, launch_authentication) = loop { provisioning_operation::ensure_operation_settled(¤t)?; - image_update::ensure_no_pending_image_update(¤t)?; + self.ensure_no_pending_image_update(¤t).await?; let phase = SandboxPhase::try_from(current.phase()).unwrap_or(SandboxPhase::Unknown); if let StartIntent::Resume { .. } = intent { // Resume restores only retained state. A Starting record may @@ -7390,8 +7392,6 @@ fn public_status_from_driver( next_restart_time: None, main_process_started_time: None, last_token_grant_failure: None, - image_update: None, - image_revision: 0, } } @@ -7478,8 +7478,6 @@ fn apply_driver_snapshot( new_status.restart_count = old_status.restart_count; new_status.next_restart_time = old_status.next_restart_time; new_status.main_process_started_time = old_status.main_process_started_time; - new_status.image_update.clone_from(&old_status.image_update); - new_status.image_revision = old_status.image_revision; } phase = match old_phase { @@ -8458,6 +8456,7 @@ pub fn new_test_runtime_with_driver( driver_process: None, default_image: "openshell/sandbox:test".to_string(), image_preparation_timeout_seconds: 1800, + image_updates_enabled: false, store, sandbox_index: SandboxIndex::new(), sandbox_watch_bus: SandboxWatchBus::new(), @@ -9678,6 +9677,7 @@ mod tests { driver_process: None, default_image: "openshell/sandbox:test".to_string(), image_preparation_timeout_seconds: 1800, + image_updates_enabled: false, store, sandbox_index: SandboxIndex::new(), sandbox_watch_bus: SandboxWatchBus::new(), diff --git a/crates/openshell-server/src/config_file.rs b/crates/openshell-server/src/config_file.rs index cee598a992..9a25dfd7c8 100644 --- a/crates/openshell-server/src/config_file.rs +++ b/crates/openshell-server/src/config_file.rs @@ -143,6 +143,9 @@ pub struct GatewayFileSection { /// Absolute preparation budget for new attempts; existing deadlines persist. #[serde(default)] pub image_preparation_timeout_seconds: Option, + /// Explicit activation only after the compatible deployment rollout ends. + #[serde(default)] + pub enable_sandbox_image_updates: Option, #[serde(default)] pub grpc_rate_limit_requests: Option, #[serde(default)] diff --git a/crates/openshell-server/src/gateway_members.rs b/crates/openshell-server/src/gateway_members.rs index 33d68414df..6c122ded29 100644 --- a/crates/openshell-server/src/gateway_members.rs +++ b/crates/openshell-server/src/gateway_members.rs @@ -43,6 +43,9 @@ fn member_object_id(replica_id: &str) -> String { struct MemberPayload { replica_id: String, peer_endpoint: String, + /// Binary capability, not feature activation. Missing denotes old replicas. + #[serde(default)] + image_update_protocol: u32, } /// A gateway replica that was alive as of its last refresh. @@ -71,6 +74,7 @@ impl GatewayMemberIndex { let payload = MemberPayload { replica_id: replica_id.to_string(), peer_endpoint: peer_endpoint.to_string(), + image_update_protocol: 1, }; let bytes = serde_json::to_vec(&payload) .map_err(|err| PersistenceError::Encode(err.to_string()))?; diff --git a/crates/openshell-server/src/grpc/mod.rs b/crates/openshell-server/src/grpc/mod.rs index 84b2406fb8..d066845fa4 100644 --- a/crates/openshell-server/src/grpc/mod.rs +++ b/crates/openshell-server/src/grpc/mod.rs @@ -242,6 +242,16 @@ impl OpenShellService { // Trait impl — thin delegation to submodules // --------------------------------------------------------------------------- +#[tonic::async_trait] +impl openshell_core::proto::sandbox_updates_server::SandboxUpdates for OpenShellService { + async fn update_sandbox( + &self, + request: Request, + ) -> Result, Status> { + mutation_replay::run(&self.state, request).await + } +} + #[tonic::async_trait] impl OpenShell for OpenShellService { async fn health( @@ -322,13 +332,6 @@ impl OpenShell for OpenShellService { mutation_replay::run(&self.state, request).await } - async fn update_sandbox( - &self, - request: Request, - ) -> Result, Status> { - mutation_replay::run(&self.state, request).await - } - async fn begin_rootfs_tar_staging( &self, request: Request, diff --git a/crates/openshell-server/src/grpc/mutation_replay.rs b/crates/openshell-server/src/grpc/mutation_replay.rs index 1a39b3dea0..837d26466c 100644 --- a/crates/openshell-server/src/grpc/mutation_replay.rs +++ b/crates/openshell-server/src/grpc/mutation_replay.rs @@ -102,6 +102,9 @@ struct AuthorizationBarrier { pub(super) trait Mutation: Message + Default + Send + Sync + 'static { type Output: Send + 'static; const METHOD: &'static str; + /// Preserve legacy replay keys while allowing independent services to use + /// fully qualified identities for newly introduced methods. + const REPLAY_METHOD: &'static str = Self::METHOD; const PROTECTED: bool = false; // Streaming producers, not returned stream handles, confirm completion. const DEFERRED: bool = false; @@ -217,7 +220,7 @@ pub(super) async fn run( let bucket = format!("_mutation/{caller}"); let key = hash_json(&serde_json::json!([ caller, - M::METHOD, + M::REPLAY_METHOD, scope.name, request_id ]))?; diff --git a/crates/openshell-server/src/grpc/mutation_replay/ordinary.rs b/crates/openshell-server/src/grpc/mutation_replay/ordinary.rs index c0a5887728..a88c6abb9d 100644 --- a/crates/openshell-server/src/grpc/mutation_replay/ordinary.rs +++ b/crates/openshell-server/src/grpc/mutation_replay/ordinary.rs @@ -335,10 +335,11 @@ async fn profile_scope( } macro_rules! mutation { - ($req:ty, $resp:ty, $method:literal, $handler:path, $auth:expr, $capture:expr, $restore:expr) => { + ($req:ty, $resp:ty, $method:literal, $handler:path, $auth:expr, $capture:expr, $restore:expr $(, $replay_method:literal)?) => { impl Mutation for $req { type Output = $resp; const METHOD: &'static str = $method; + $(const REPLAY_METHOD: &'static str = $replay_method;)? const PROTECTED: bool = true; fn request_id(&self) -> &str { &self.request_id @@ -389,7 +390,7 @@ macro_rules! scoped_mutation { } macro_rules! sandbox_scoped_mutation { - ($req:ty, $resp:ty, $method:literal, $handler:path, $role:ident, $capture:expr, $restore:expr) => { + ($req:ty, $resp:ty, $method:literal, $handler:path, $role:ident, $capture:expr, $restore:expr $(, $replay_method:literal)?) => { mutation!( $req, $resp, @@ -406,6 +407,7 @@ macro_rules! sandbox_scoped_mutation { }, $capture, $restore + $(, $replay_method)? ); }; } @@ -423,7 +425,7 @@ fn sandbox_receipt( } macro_rules! sandbox_mutation { - ($req:ty, $method:literal, $handler:path) => { + ($req:ty, $method:literal, $handler:path $(, $replay_method:literal)?) => { sandbox_scoped_mutation!( $req, SandboxResponse, @@ -444,6 +446,7 @@ macro_rules! sandbox_mutation { service_urls: HashMap::new(), }) } + $(, $replay_method)? ); }; } @@ -474,7 +477,8 @@ scoped_mutation!( sandbox_mutation!( openshell_core::proto::UpdateSandboxRequest, "UpdateSandbox", - sandbox::handle_update_sandbox + sandbox::handle_update_sandbox, + "/openshell.v1.SandboxUpdates/UpdateSandbox" ); sandbox_mutation!( StartSandboxRequest, 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 b45259c88b..dbcf4c57cb 100644 --- a/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs +++ b/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs @@ -2,13 +2,76 @@ // SPDX-License-Identifier: Apache-2.0 use super::*; +use crate::auth::audit::ConnectionSource; use crate::grpc::test_support::{authed_request, test_server_state}; use crate::test_support::{FakeComputeDriver, FakeComputeDriverCall}; use openshell_core::proto::UpdateSandboxRequest; use openshell_core::proto::compute::v1::GetCapabilitiesResponse; use openshell_core::proto::datamodel::v1::ObjectMeta; +use openshell_core::proto::sandbox_updates_client::SandboxUpdatesClient; use tonic::Code; +struct RunningService(tokio::task::JoinHandle<()>); + +impl Drop for RunningService { + fn drop(&mut self) { + self.0.abort(); + } +} + +async fn wire_client( + state: Arc, +) -> ( + SandboxUpdatesClient, + RunningService, +) { + use crate::multiplex::MultiplexService; + use openshell_core::proto::open_shell_client::OpenShellClient; + + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let address = listener.local_addr().unwrap(); + // Use the production gateway multiplexer, not a standalone tonic server: + // this proves registration, routing and principal injection on the same + // listener as the unchanged OpenShell service. + let server = RunningService(tokio::spawn(async move { + let mut connections = tokio::task::JoinSet::new(); + loop { + let (stream, peer) = listener.accept().await.unwrap(); + let service = MultiplexService::new(state.clone()); + connections.spawn(async move { + service + .serve(stream, ConnectionSource::Peer(peer)) + .await + .unwrap(); + }); + } + })); + let channel = tonic::transport::Endpoint::from_shared(format!("http://{address}")) + .unwrap() + .connect() + .await + .unwrap(); + OpenShellClient::new(channel.clone()) + .health(openshell_core::proto::HealthRequest {}) + .await + .unwrap(); + (SandboxUpdatesClient::new(channel), server) +} + +#[test] +fn image_updates_have_their_own_authenticated_workspace_scoped_service() { + use crate::auth::method_authz::{AuthMode, lookup}; + use crate::grpc::mutation_replay::Mutation; + + let path = "/openshell.v1.SandboxUpdates/UpdateSandbox"; + let authorization = lookup(path).expect("new service must participate in gateway auth"); + assert_eq!(authorization.auth_mode, AuthMode::Bearer); + assert_eq!(authorization.scope.as_deref(), Some("sandbox:write")); + assert_eq!(authorization.workspace_role.as_deref(), Some("user")); + assert!(lookup("/openshell.v1.OpenShell/UpdateSandbox").is_none()); + assert_eq!(::REPLAY_METHOD, path); +} + fn request() -> UpdateSandboxRequest { UpdateSandboxRequest { workspace_scope: Some(openshell_core::proto::workspace_selector("default")), @@ -59,6 +122,10 @@ fn image_only_request_requires_target_image_and_conditional_version() { async fn state() -> (Arc, Arc, Sandbox) { let mut state = test_server_state().await; + Arc::get_mut(&mut state) + .unwrap() + .config + .enable_sandbox_image_updates = true; let driver = Arc::new( FakeComputeDriver::new().with_capabilities(GetCapabilitiesResponse { driver_name: "image-test".into(), @@ -83,7 +150,8 @@ async fn state() -> (Arc, Arc, Sandbox) { Arc::new(crate::supervisor_session::SupervisorSessionRegistry::new()), ) .await - .unwrap(); + .unwrap() + .with_sandbox_image_updates(true); Arc::get_mut(&mut state).unwrap().compute = compute; let mut sandbox = Sandbox { metadata: Some(ObjectMeta { @@ -145,6 +213,12 @@ async fn public_image_update_checks_workspace_and_missing_resource() { #[tokio::test] async fn public_image_update_replays_without_reapplying_or_touching_same_name_replacement() { let (mut state, driver, sandbox) = state().await; + // Exercise production routing with the explicit local developer identity. + Arc::get_mut(&mut state) + .unwrap() + .config + .auth + .allow_unauthenticated_users = true; let directory = tempfile::tempdir().unwrap(); let key = directory.path().join("private-key"); std::fs::write(&key, b"test-only stable private fingerprint material").unwrap(); @@ -156,12 +230,14 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re gateway_id: "test".into(), ttl_secs: None, }); + let (mut client, _server) = wire_client(state.clone()).await; let req = UpdateSandboxRequest { expected_resource_version: sandbox.get_resource_version(), request_id: uuid::Uuid::new_v4().to_string(), ..request() }; - let updated = super::super::mutation_replay::run(&state, authed_request(req.clone())) + let updated = client + .update_sandbox(req.clone()) .await .unwrap() .into_inner() @@ -179,9 +255,7 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re .image, req.image ); - let replay = super::super::mutation_replay::run(&state, authed_request(req.clone())) - .await - .unwrap(); + let replay = client.update_sandbox(req.clone()).await.unwrap(); assert_eq!(replay.metadata().get("openshell-replayed").unwrap(), "true"); assert_eq!(replay.get_ref().sandbox.as_ref().unwrap(), &updated); assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxImage { request } if !request.validate_only)).count(), 1); @@ -190,10 +264,7 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re ..req.clone() }; assert_eq!( - super::super::mutation_replay::run(&state, authed_request(changed)) - .await - .unwrap_err() - .code(), + client.update_sandbox(changed).await.unwrap_err().code(), Code::FailedPrecondition ); state @@ -207,10 +278,7 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re metadata.resource_version = 0; state.store.put_message(&replacement).await.unwrap(); assert_eq!( - super::super::mutation_replay::run(&state, authed_request(req)) - .await - .unwrap_err() - .code(), + client.update_sandbox(req).await.unwrap_err().code(), Code::FailedPrecondition ); let replacement = state diff --git a/crates/openshell-server/src/lib.rs b/crates/openshell-server/src/lib.rs index 06bbf42736..ab4af5b2d9 100644 --- a/crates/openshell-server/src/lib.rs +++ b/crates/openshell-server/src/lib.rs @@ -482,6 +482,7 @@ impl ServerState { credentials: credentials::CredentialRuntime, ) -> Self { let replica_id = compute::lease::replica_id(); + let compute = compute.with_sandbox_image_updates(config.enable_sandbox_image_updates); compute.configure_ssh_identities(credentials.clone()); let service_route_index = Arc::new(service_routing::ServiceRouteIndex::new( config.service_routing_discriminator().map(str::to_string), @@ -2701,7 +2702,7 @@ mod tests { .iter() .map(|service| service.name.as_str()) .collect::>(), - ["openshell.v1.OpenShell"] + ["openshell.v1.OpenShell", "openshell.v1.SandboxUpdates"] ); stop_listener(shutdown, handle).await; diff --git a/crates/openshell-server/src/multiplex.rs b/crates/openshell-server/src/multiplex.rs index d58192fba2..438b7d4bc6 100644 --- a/crates/openshell-server/src/multiplex.rs +++ b/crates/openshell-server/src/multiplex.rs @@ -18,6 +18,7 @@ use hyper_util::{ }; use metrics::{counter, histogram}; use openshell_core::proto::open_shell_server::OpenShellServer; +use openshell_core::proto::sandbox_updates_server::SandboxUpdatesServer; use openshell_core::proto::supervisor_host::v1::supervisor_host_server::SupervisorHostServer; use openshell_core::{ Config, @@ -305,6 +306,13 @@ impl MultiplexService { openshell, ); let reflection = self.state.reflection_service.clone(); + let sandbox_updates = SandboxUpdatesServer::new(OpenShellService::new(self.state.clone())) + .max_decoding_message_size(MAX_GRPC_DECODE_SIZE); + let sandbox_updates = GatewayInterceptorGrpcService::new( + sandbox_updates, + self.state.gateway_interceptors.clone(), + Some(self.state.clone()), + ); let authz_policy = self.state.config.oidc.as_ref().map(|oidc| AuthzPolicy { admin_role: oidc.admin_role.clone(), user_role: oidc.user_role.clone(), @@ -312,7 +320,7 @@ impl MultiplexService { }); let authenticator_chain = build_authenticator_chain(&self.state); let grpc_service = AuthGrpcRouter::with_peer_identity( - GrpcRouter::new(openshell, reflection), + GrpcRouter::new(openshell, reflection).with_sandbox_updates(sandbox_updates), authenticator_chain, authz_policy, self.state @@ -987,11 +995,12 @@ where } } -/// Combined gRPC service that routes between `OpenShell` and reflection. +/// Combined gRPC service for public gateway services and reflection. #[derive(Clone)] -pub struct GrpcRouter { +pub struct GrpcRouter { openshell: N, reflection: R, + sandbox_updates: Option, } impl GrpcRouter { @@ -999,13 +1008,22 @@ impl GrpcRouter { Self { openshell, reflection, + sandbox_updates: None, + } + } + + fn with_sandbox_updates(self, sandbox_updates: U) -> GrpcRouter { + GrpcRouter { + openshell: self.openshell, + reflection: self.reflection, + sandbox_updates: Some(sandbox_updates), } } } pub const REFLECTION_PATH_PREFIX: &str = "/grpc.reflection.v1."; -impl tower::Service> for GrpcRouter +impl tower::Service> for GrpcRouter where N: tower::Service> + Clone + Send + 'static, N::Response: Send, @@ -1016,6 +1034,11 @@ where + Send + 'static, R::Future: Send, + U: tower::Service, Response = N::Response, Error = N::Error> + + Clone + + Send + + 'static, + U::Future: Send, B: Send + 'static, { type Response = N::Response; @@ -1030,6 +1053,13 @@ where if req.uri().path().starts_with(REFLECTION_PATH_PREFIX) { let mut svc = self.reflection.clone(); Box::pin(async move { svc.ready().await?.call(req).await }) + } else if req + .uri() + .path() + .starts_with("/openshell.v1.SandboxUpdates/") + && let Some(mut svc) = self.sandbox_updates.clone() + { + Box::pin(async move { svc.ready().await?.call(req).await }) } else { let mut svc = self.openshell.clone(); Box::pin(async move { svc.ready().await?.call(req).await }) @@ -2836,6 +2866,13 @@ mod tests { otel_span_name(&http::Method::POST, "/openshell.v1.OpenShell/CreateSandbox"), "openshell.v1.OpenShell/CreateSandbox" ); + assert_eq!( + otel_span_name( + &http::Method::POST, + "/openshell.v1.SandboxUpdates/UpdateSandbox" + ), + "openshell.v1.SandboxUpdates/UpdateSandbox" + ); } /// Non-RPC paths use a low-cardinality method-only name because sandbox @@ -2905,10 +2942,12 @@ mod tests { name, calls: calls.clone(), }; - let mut router = GrpcRouter::new(service("openshell"), service("reflection")); + let mut router = GrpcRouter::new(service("openshell"), service("reflection")) + .with_sandbox_updates(service("sandbox_updates")); for path in [ "/openshell.v1.OpenShell/Health", + "/openshell.v1.SandboxUpdates/UpdateSandbox", "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo", ] { router @@ -2922,7 +2961,10 @@ mod tests { .unwrap(); } - assert_eq!(*calls.lock().unwrap(), vec!["openshell", "reflection"]); + assert_eq!( + *calls.lock().unwrap(), + vec!["openshell", "sandbox_updates", "reflection"] + ); } #[tokio::test] @@ -3018,7 +3060,10 @@ mod tests { .collect(); names.sort(); - assert_eq!(names, vec!["openshell.v1.OpenShell"]); + assert_eq!( + names, + vec!["openshell.v1.OpenShell", "openshell.v1.SandboxUpdates"] + ); let descriptor_response = responses.message().await.unwrap().unwrap(); let Some(MessageResponse::FileDescriptorResponse(response)) = @@ -3038,6 +3083,11 @@ mod tests { .is_some(), "a fresh descriptor pool must resolve the advertised service" ); + assert!( + reflected_pool + .get_service_by_name("openshell.v1.SandboxUpdates") + .is_some() + ); assert!( reflected_pool .get_message_by_name("openshell.v1.HealthRequest") diff --git a/crates/openshell-server/src/persistence/image_activation.rs b/crates/openshell-server/src/persistence/image_activation.rs new file mode 100644 index 0000000000..badbc0eb3f --- /dev/null +++ b/crates/openshell-server/src/persistence/image_activation.rs @@ -0,0 +1,315 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Additional, fail-closed deployment checks for operator-activated image updates. +//! +//! These snapshots are not a durable fence or proof that old processes have +//! stopped. Membership can expire, gateways need not advertise peer endpoints, +//! and a backend can connect after the check. The explicit operator activation +//! must attest that incompatible gateways have been drained and retired. The +//! old-understood pending-operation interlock, not these observations, protects +//! an accepted image mutation from a subsequent legacy Start. + +use super::{ObjectRecord, PersistenceError, PersistenceResult, Store, map_db_error}; +use crate::gateway_members::MEMBER_TTL; +use openshell_core::time::now_ms; + +/// Compatibility marker advertised by both gateway `PostgreSQL` connection pools. +/// +/// This marker describes a protocol, not an exact build version. It is neither +/// authentication nor a security boundary: database clients can set it too. +pub(super) const IMAGE_UPDATE_APPLICATION_NAME: &str = "openshell-image-update-v1"; + +const MEMBER_OBJECT_TYPE: &str = "gateway_member"; +const MEMBER_LIMIT: u32 = 1024; + +impl Store { + /// Reject observable incompatible or unknown gateway deployment participants. + /// + /// The caller separately enforces the default-off operator activation flag. + /// `SQLite` returns success under its supported single-gateway deployment + /// contract; this does not enforce process exclusion for a shared file. + /// `PostgreSQL` checks every client backend in this database, not merely + /// registered peers, and then strictly checks all fresh membership records. + /// Administrative clients without the marker also prevent activation. Any + /// database read failure propagates rather than granting compatibility. + pub async fn ensure_image_update_deployment_compatible(&self) -> PersistenceResult<()> { + let Self::Postgres(store) = self else { + return Ok(()); + }; + + let incompatible_backend: bool = sqlx::query_scalar( + r" +SELECT EXISTS ( + SELECT 1 FROM pg_stat_activity + WHERE datname = current_database() + AND (backend_type = 'client backend' OR backend_type IS NULL) + AND application_name IS DISTINCT FROM $1 +) +", + ) + .bind(IMAGE_UPDATE_APPLICATION_NAME) + .fetch_one(&store.pool) + .await + .map_err(|error| map_db_error(&error))?; + if incompatible_backend { + return Err(PersistenceError::Config( + "sandbox image updates require a uniformly compatible gateway deployment; \ + a PostgreSQL client backend has an unknown or legacy image-update protocol" + .into(), + )); + } + + // One extra row distinguishes a complete bounded snapshot from a + // truncated listing. Never silently treat uninspected rows as compatible. + let records = self + .list_by_type(MEMBER_OBJECT_TYPE, MEMBER_LIMIT + 1, 0) + .await?; + ensure_live_members_compatible(&records, now_ms()) + } +} + +fn ensure_live_members_compatible(records: &[ObjectRecord], now: i64) -> PersistenceResult<()> { + if records.len() > MEMBER_LIMIT as usize { + return Err(PersistenceError::Config( + "cannot establish image-update deployment compatibility: gateway membership listing exceeds its limit" + .into(), + )); + } + let ttl_ms = i64::try_from(MEMBER_TTL.as_millis()).unwrap_or(i64::MAX); + for record in records { + // Match membership liveness semantics, including clock-skew clamping. + // Ignoring expired records is not evidence that their processes stopped. + let age_ms = now.saturating_sub(record.updated_at_ms).max(0); + if age_ms >= ttl_ms { + continue; + } + let member: serde_json::Map = + serde_json::from_slice(&record.payload).map_err(|_| { + PersistenceError::Config( + "cannot establish image-update deployment compatibility: a live gateway membership record is not a valid JSON object" + .into(), + ) + })?; + let replica_id = member.get("replica_id").and_then(serde_json::Value::as_str); + let protocol = member + .get("image_update_protocol") + .and_then(serde_json::Value::as_u64); + if replica_id.is_none_or(|id| id.trim().is_empty()) || protocol != Some(1) { + return Err(PersistenceError::Config( + "sandbox image updates require every live gateway membership record to advertise image-update protocol 1 and a nonempty replica id" + .into(), + )); + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn record(payload: &[u8], updated_at_ms: i64) -> ObjectRecord { + ObjectRecord { + object_type: MEMBER_OBJECT_TYPE.into(), + id: "gateway-member:gw-0".into(), + name: "gw-0".into(), + workspace: String::new(), + payload: payload.to_vec(), + created_at_ms: updated_at_ms, + updated_at_ms, + labels: None, + resource_version: 1, + } + } + + #[tokio::test] + async fn sqlite_uses_the_supported_single_gateway_contract() { + let store = super::super::test_store().await; + store + .ensure_image_update_deployment_compatible() + .await + .unwrap(); + } + + #[tokio::test] + #[ignore = "requires a disposable PostgreSQL database and CREATEDB privileges in OPENSHELL_TEST_POSTGRES_URL; run mise run test:rust:postgres"] + async fn postgres_image_activation_checks_client_backends_and_live_members() { + use super::super::test_postgres::TEST_POSTGRES_URL_ENV; + use super::super::{MutationLockSet, WriteCondition}; + use sqlx::postgres::{PgConnectOptions, PgPoolOptions}; + use std::time::Duration; + + // This check intentionally includes every backend in a database. A + // disposable schema would share unmarked test-control/other-test + // sessions and make its positive assertions dependent on test order. + // Keep the unmarked control pool in the original database instead. + let base = std::env::var(TEST_POSTGRES_URL_ENV) + .expect("OPENSHELL_TEST_POSTGRES_URL must name a disposable PostgreSQL database"); + let admin = PgPoolOptions::new() + .max_connections(1) + .connect(&base) + .await + .expect("connect to the test-control database"); + let database = format!("image_activation_{}", uuid::Uuid::new_v4().simple()); + sqlx::query(sqlx::AssertSqlSafe(format!("CREATE DATABASE {database}"))) + .execute(&admin) + .await + .expect("create a dedicated activation-test database (requires CREATEDB)"); + let mut url = url::Url::parse(&base).expect("parse the test PostgreSQL URL"); + url.set_path(&format!("/{database}")); + let first = Store::connect(url.as_str()).await.unwrap(); + let second = Store::connect(url.as_str()).await.unwrap(); + + // Exercise both data pools and a lazily opened mutation-lock pool. + let guard = second + .acquire_distributed_mutation_guard( + &MutationLockSet::sandbox_lifecycle("activation-test-sandbox"), + tokio::time::Instant::now() + Duration::from_secs(10), + ) + .await + .unwrap(); + first + .ensure_image_update_deployment_compatible() + .await + .expect("compatible data and lock pools must pass despite the other database's control pool"); + drop(guard); + + // No membership record is needed to detect an old or administrative + // client. Do not weaken the production filter to exempt this session. + let legacy_options = url + .as_str() + .parse::() + .unwrap() + .application_name("legacy-image-activation-test"); + let legacy = PgPoolOptions::new() + .max_connections(1) + .connect_with(legacy_options) + .await + .unwrap(); + assert!(matches!( + first.ensure_image_update_deployment_compatible().await, + Err(PersistenceError::Config(_)) + )); + legacy.close().await; + + // SQLx closing its socket can precede the server removing the backend. + // Bound this wait instead of depending on a fixed scheduling delay. + tokio::time::timeout(Duration::from_secs(5), async { + loop { + match first.ensure_image_update_deployment_compatible().await { + Ok(()) => break, + Err(PersistenceError::Config(_)) => { + tokio::time::sleep(Duration::from_millis(20)).await; + } + Err(error) => panic!("compatibility read failed: {error}"), + } + } + }) + .await + .expect("closed legacy backend must disappear from pg_stat_activity"); + + let member = first + .put_if( + MEMBER_OBJECT_TYPE, + "gateway-member:legacy", + "legacy", + "", + br#"{"replica_id":"legacy"}"#, + None, + WriteCondition::MustCreate, + ) + .await + .unwrap(); + assert!(matches!( + first.ensure_image_update_deployment_compatible().await, + Err(PersistenceError::Config(_)) + )); + first + .put_if( + MEMBER_OBJECT_TYPE, + "gateway-member:legacy", + "legacy", + "", + br#"{"replica_id":"legacy","image_update_protocol":1}"#, + None, + WriteCondition::MatchResourceVersion(member.resource_version), + ) + .await + .unwrap(); + first + .ensure_image_update_deployment_compatible() + .await + .unwrap(); + + first.close().await; + assert!(matches!( + first.ensure_image_update_deployment_compatible().await, + Err(PersistenceError::Database(_)) + )); + second.close().await; + sqlx::query(sqlx::AssertSqlSafe(format!( + "DROP DATABASE {database} WITH (FORCE)" + ))) + .execute(&admin) + .await + .expect("drop the isolated activation-test database"); + admin.close().await; + } + + #[test] + fn compatible_live_members_and_empty_snapshot_pass() { + assert!(ensure_live_members_compatible(&[], 100).is_ok()); + let member = record( + br#"{"replica_id":"gw-0","peer_endpoint":"https://gw-0:8443","image_update_protocol":1}"#, + 100, + ); + assert!(ensure_live_members_compatible(&[member], 100).is_ok()); + } + + #[test] + fn malformed_missing_unknown_or_ill_typed_protocols_fail_closed() { + let invalid: &[&[u8]] = &[ + b"not JSON", + br"[]", + br#"["gw-0",1]"#, + br"null", + br#"{"replica_id":"gw-0"}"#, + br#"{"replica_id":"gw-0","image_update_protocol":0}"#, + br#"{"replica_id":"gw-0","image_update_protocol":2}"#, + br#"{"replica_id":"gw-0","image_update_protocol":"1"}"#, + br#"{"replica_id":"gw-0","image_update_protocol":true}"#, + br#"{"replica_id":"gw-0","image_update_protocol":1.0}"#, + br#"{"image_update_protocol":1}"#, + br#"{"replica_id":"","image_update_protocol":1}"#, + br#"{"replica_id":" ","image_update_protocol":1}"#, + ]; + for payload in invalid { + assert!(ensure_live_members_compatible(&[record(payload, 100)], 100).is_err()); + } + } + + #[test] + fn expired_records_are_not_considered_live_but_future_timestamps_are() { + let ttl_ms = i64::try_from(MEMBER_TTL.as_millis()).unwrap(); + assert!(ensure_live_members_compatible(&[record(b"legacy", 100)], 100 + ttl_ms).is_ok()); + assert!( + ensure_live_members_compatible(&[record(b"legacy", 100)], 100 + ttl_ms - 1).is_err() + ); + assert!(ensure_live_members_compatible(&[record(b"legacy", 200)], 100).is_err()); + } + + #[test] + fn any_incompatible_live_member_rejects_the_snapshot() { + let compatible = record(br#"{"replica_id":"gw-0","image_update_protocol":1}"#, 100); + let legacy = record(br#"{"replica_id":"gw-1"}"#, 100); + assert!(ensure_live_members_compatible(&[compatible, legacy], 100).is_err()); + } + + #[test] + fn listing_truncation_fails_closed_even_when_extra_rows_are_expired() { + let records = vec![record(b"legacy", 0); MEMBER_LIMIT as usize + 1]; + let now = i64::try_from(MEMBER_TTL.as_millis()).unwrap(); + assert!(ensure_live_members_compatible(&records, now).is_err()); + } +} diff --git a/crates/openshell-server/src/persistence/mod.rs b/crates/openshell-server/src/persistence/mod.rs index f14111b74d..30280b96bb 100644 --- a/crates/openshell-server/src/persistence/mod.rs +++ b/crates/openshell-server/src/persistence/mod.rs @@ -3,12 +3,14 @@ //! Persistence layer for `OpenShell` Server. +mod image_activation; mod legacy_time_wire; pub mod lock_order; pub mod mutation_lock; mod postgres; #[cfg(test)] mod refresh_lock_tests; +mod sandbox_image; mod sqlite; pub use crate::storage_proto::{ diff --git a/crates/openshell-server/src/persistence/postgres.rs b/crates/openshell-server/src/persistence/postgres.rs index a44f2399a7..caeae9c74c 100644 --- a/crates/openshell-server/src/persistence/postgres.rs +++ b/crates/openshell-server/src/persistence/postgres.rs @@ -20,7 +20,7 @@ use openshell_core::SetResourceVersion; use openshell_core::proto::Sandbox; use prost::Message; use sqlx::pool::PoolConnection; -use sqlx::postgres::PgPoolOptions; +use sqlx::postgres::{PgConnection, PgPoolOptions}; use sqlx::{Connection, PgPool, Postgres, QueryBuilder, Row}; use std::sync::Arc; use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; @@ -28,6 +28,15 @@ use std::time::Duration; static POSTGRES_MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate!("./migrations/postgres"); +/// A protocol capability, not an exact build version or an authorization +/// credential. Identify every pool connection, including after reconnect. +async fn identify_image_update_writer(connection: &mut PgConnection) -> Result<(), sqlx::Error> { + sqlx::query("SELECT set_config('application_name', 'openshell-image-update-v1', false)") + .execute(connection) + .await?; + Ok(()) +} + #[cfg(test)] pub(super) fn embedded_migration_sql(version: i64) -> Option<&'static str> { POSTGRES_MIGRATOR @@ -40,7 +49,7 @@ use super::{DELETE_MANY_BATCH_SIZE, DRAFT_CHUNK_OBJECT_TYPE, POLICY_OBJECT_TYPE} #[derive(Debug, Clone)] pub struct PostgresStore { - pool: PgPool, + pub(super) pool: PgPool, /// Dedicated connections for session-level mutation advisory locks. lock_pool: PgPool, /// How acquisitions and guards use the lock pool's connections. @@ -304,6 +313,7 @@ impl PostgresStore { ); let pool = PgPoolOptions::new() .max_connections(max_connections) + .after_connect(|connection, _| Box::pin(identify_image_update_writer(connection))) .connect(url) .await .map_err(|e| map_db_error(&e))?; @@ -320,6 +330,7 @@ impl PostgresStore { .bind(MUTATION_LOCK_TIMEOUT_SETTING) .execute(&mut *connection) .await?; + identify_image_update_writer(connection).await?; Ok(()) }) }) diff --git a/crates/openshell-server/src/persistence/sandbox_image.rs b/crates/openshell-server/src/persistence/sandbox_image.rs new file mode 100644 index 0000000000..88a2bc7d32 --- /dev/null +++ b/crates/openshell-server/src/persistence/sandbox_image.rs @@ -0,0 +1,1369 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Private, atomic image-update intent storage. +//! +//! The intent is deliberately not part of `Sandbox`: an older gateway decoding +//! and rewriting that public message must not erase an accepted update. Every +//! transaction locks the sandbox first, then its independent image-state row. + +use super::{PersistenceError, PersistenceResult, Store, current_time_ms, map_db_error}; +use crate::storage_proto::{StoredSandboxImageState, StoredSandboxImageUpdate}; +use openshell_core::SetResourceVersion; +use openshell_core::proto::{Sandbox, SandboxPhase, SandboxProvisioning}; +use prost::Message; +use sqlx::{Postgres, Sqlite, Transaction}; + +const IMAGE_STATE_OBJECT_TYPE: &str = "sandbox_image_state"; + +fn state_id(sandbox_id: &str) -> String { + format!("sandbox-image-state:{sandbox_id}") +} + +fn conflict(current_resource_version: Option) -> PersistenceError { + PersistenceError::Conflict { + current_resource_version, + } +} + +fn decode_state(sandbox_id: &str, payload: &[u8]) -> PersistenceResult { + let state = StoredSandboxImageState::decode(payload) + .map_err(|error| PersistenceError::Decode(error.to_string()))?; + if state.sandbox_id != sandbox_id + || state + .pending + .as_ref() + .is_some_and(|pending| pending.revision == 0 || pending.revision != state.revision) + || (state.pending.is_none() && state.previous_provisioning.is_some()) + || state + .previous_provisioning + .as_ref() + .is_some_and(|previous| previous.driver_operation_pending) + { + return Err(PersistenceError::Database( + "inconsistent stored sandbox image state".into(), + )); + } + Ok(state) +} + +fn decode_sandbox( + sandbox_id: &str, + payload: &[u8], + resource_version: i64, +) -> PersistenceResult { + if resource_version < 1 { + return Err(PersistenceError::Database( + "invalid sandbox resource version".into(), + )); + } + let payload = super::legacy_time_wire::migrate("sandbox", payload)?; + let mut sandbox = Sandbox::decode(payload.as_slice()) + .map_err(|error| PersistenceError::Decode(error.to_string()))?; + if sandbox + .metadata + .as_ref() + .is_none_or(|meta| meta.id != sandbox_id) + { + return Err(PersistenceError::Database( + "inconsistent stored sandbox identity".into(), + )); + } + // The SQL column, not a possibly stale protobuf field, is authoritative. + sandbox.set_resource_version(resource_version.cast_unsigned()); + Ok(sandbox) +} + +fn resource_version(sandbox: &Sandbox) -> u64 { + sandbox + .metadata + .as_ref() + .map_or(0, |meta| meta.resource_version) +} + +fn require_stopped(sandbox: &Sandbox) -> PersistenceResult<()> { + if sandbox + .metadata + .as_ref() + .is_none_or(|meta| meta.deletion_time.is_some()) + || sandbox + .status + .as_ref() + .is_none_or(|status| status.phase != SandboxPhase::Stopped as i32) + { + return Err(conflict(Some(resource_version(sandbox)))); + } + Ok(()) +} + +fn validate_intent(intent: &StoredSandboxImageUpdate) -> PersistenceResult<()> { + if intent.operation_id.is_empty() + || intent.previous_image.is_empty() + || intent.image.is_empty() + || intent.revision == 0 + { + return Err(PersistenceError::Encode( + "image update requires an operation id, both images, and a nonzero revision".into(), + )); + } + Ok(()) +} + +fn bump_resource_version(sandbox: &mut Sandbox) -> PersistenceResult<()> { + let next = resource_version(sandbox) + .checked_add(1) + .filter(|next| i64::try_from(*next).is_ok()) + .ok_or_else(|| PersistenceError::Encode("sandbox resource version exhausted".into()))?; + sandbox.set_resource_version(next); + Ok(()) +} + +/// Pure projection: all acceptance checks happen before either row is written. +fn project_begin( + mut sandbox: Sandbox, + state: Option, + expected_sandbox_resource_version: u64, + expected_revision: u64, + intent: &StoredSandboxImageUpdate, +) -> PersistenceResult<(Sandbox, StoredSandboxImageState)> { + let current_version = resource_version(&sandbox); + if expected_sandbox_resource_version == 0 + || expected_sandbox_resource_version != current_version + { + return Err(conflict(Some(current_version))); + } + require_stopped(&sandbox)?; + validate_intent(intent)?; + let mut state = state.unwrap_or_else(|| StoredSandboxImageState { + sandbox_id: sandbox + .metadata + .as_ref() + .map_or_else(String::new, |meta| meta.id.clone()), + revision: 0, + pending: None, + previous_provisioning: None, + }); + if state.revision != expected_revision || state.pending.is_some() { + return Err(conflict(Some(current_version))); + } + let next_revision = expected_revision + .checked_add(1) + .ok_or_else(|| PersistenceError::Encode("sandbox image revision exhausted".into()))?; + if intent.revision != next_revision { + return Err(conflict(Some(current_version))); + } + let previous_provisioning = sandbox + .status + .as_ref() + .and_then(|status| status.provisioning.clone()); + if previous_provisioning + .as_ref() + .is_some_and(|previous| previous.driver_operation_pending) + { + return Err(conflict(Some(current_version))); + } + let template = sandbox + .spec + .as_mut() + .and_then(|spec| spec.template.as_mut()) + .ok_or_else(|| conflict(Some(current_version)))?; + if template.image != intent.previous_image { + return Err(conflict(Some(current_version))); + } + template.image.clone_from(&intent.image); + state.revision = next_revision; + state.pending = Some(intent.clone()); + state.previous_provisioning = previous_provisioning; + let status = sandbox + .status + .as_mut() + .ok_or_else(|| conflict(Some(current_version)))?; + let operation = status + .provisioning + .get_or_insert_with(|| SandboxProvisioning { + attempt_id: format!("image-update:{}", intent.operation_id), + ..Default::default() + }); + // This is an existing, baseline-known lifecycle interlock. Old gateways + // retain it on ordinary status writes and refuse Start/Stop/Delete while + // it is pending. Do not settle it on an ambiguous driver error. + operation.driver_operation_pending = true; + operation + .driver_operation_id + .clone_from(&intent.operation_id); + bump_resource_version(&mut sandbox)?; + Ok((sandbox, state)) +} + +fn project_complete( + mut sandbox: Sandbox, + state: Option, + intent: &StoredSandboxImageUpdate, +) -> PersistenceResult<(Sandbox, StoredSandboxImageState)> { + let current_version = resource_version(&sandbox); + require_stopped(&sandbox)?; + validate_intent(intent)?; + let mut state = state.ok_or_else(|| conflict(Some(current_version)))?; + if state.revision != intent.revision || state.pending.as_ref() != Some(intent) { + return Err(conflict(Some(current_version))); + } + if sandbox + .spec + .as_ref() + .and_then(|spec| spec.template.as_ref()) + .is_none_or(|template| template.image != intent.image) + { + return Err(conflict(Some(current_version))); + } + let status = sandbox + .status + .as_mut() + .ok_or_else(|| conflict(Some(current_version)))?; + let expected_attempt = state.previous_provisioning.as_ref().map_or_else( + || format!("image-update:{}", intent.operation_id), + |previous| previous.attempt_id.clone(), + ); + let operation = status + .provisioning + .as_mut() + .ok_or_else(|| conflict(Some(current_version)))?; + if !operation.driver_operation_pending + || operation.driver_operation_id != intent.operation_id + || operation.attempt_id != expected_attempt + { + return Err(conflict(Some(current_version))); + } + // Retire only our flag on the CURRENT record. Restoring a saved snapshot + // would erase a concurrent provider attachment's accepted clock edit. + // Keep the newest operation ID to reject delayed older callbacks (ABA). + let unchanged_legacy_record = state.previous_provisioning.is_none() + && *operation + == SandboxProvisioning { + attempt_id: expected_attempt, + driver_operation_id: intent.operation_id.clone(), + driver_operation_pending: true, + ..Default::default() + }; + if unchanged_legacy_record { + status.provisioning = None; + } else { + operation.driver_operation_pending = false; + } + state.previous_provisioning = None; + state.pending = None; + // Completing an intent invalidates any Start CAS based on pending state. + bump_resource_version(&mut sandbox)?; + Ok((sandbox, state)) +} + +impl Store { + /// Read gateway-private image state by immutable sandbox identity. + pub async fn get_sandbox_image_state( + &self, + sandbox_id: &str, + ) -> PersistenceResult> { + let id = state_id(sandbox_id); + let payload = match self { + Self::Sqlite(store) => { + sqlx::query_scalar::<_, Vec>( + r#"SELECT "payload" FROM "objects" WHERE "object_type" = ?1 AND "id" = ?2"#, + ) + .bind(IMAGE_STATE_OBJECT_TYPE) + .bind(&id) + .fetch_optional(&store.pool) + .await + } + Self::Postgres(store) => { + sqlx::query_scalar::<_, Vec>( + "SELECT payload FROM objects WHERE object_type = $1 AND id = $2", + ) + .bind(IMAGE_STATE_OBJECT_TYPE) + .bind(&id) + .fetch_optional(&store.pool) + .await + } + } + .map_err(|error| map_db_error(&error))?; + payload + .map(|payload| decode_state(sandbox_id, &payload)) + .transpose() + } + + /// Atomically accept a stopped-sandbox image change and its private intent. + pub async fn begin_sandbox_image_update( + &self, + sandbox_id: &str, + expected_sandbox_resource_version: u64, + expected_revision: u64, + intent: &StoredSandboxImageUpdate, + ) -> PersistenceResult { + let mut tx = ImageTransaction::begin(self).await?; + let sandbox = tx.lock_sandbox(sandbox_id).await?; + let state = tx.lock_state(sandbox_id).await?; + let previous_version = resource_version(&sandbox); + let (sandbox, state) = project_begin( + sandbox, + state, + expected_sandbox_resource_version, + expected_revision, + intent, + )?; + tx.write_projection(sandbox_id, previous_version, &sandbox, &state) + .await?; + tx.commit().await?; + Ok(sandbox) + } + + /// Retire only the exact pending intent, retaining its monotonic revision. + pub async fn complete_sandbox_image_update( + &self, + sandbox_id: &str, + intent: &StoredSandboxImageUpdate, + ) -> PersistenceResult { + let mut tx = ImageTransaction::begin(self).await?; + let sandbox = tx.lock_sandbox(sandbox_id).await?; + let state = tx.lock_state(sandbox_id).await?; + let previous_version = resource_version(&sandbox); + let (sandbox, state) = project_complete(sandbox, state, intent)?; + tx.write_projection(sandbox_id, previous_version, &sandbox, &state) + .await?; + tx.commit().await?; + Ok(sandbox) + } +} + +/// Dropping an unfinished `SQLx` transaction rolls back both projections. +enum ImageTransaction { + Sqlite(Transaction<'static, Sqlite>), + Postgres(Transaction<'static, Postgres>), +} + +impl ImageTransaction { + async fn begin(store: &Store) -> PersistenceResult { + match store { + Store::Sqlite(store) => store + .pool + .begin_with("BEGIN IMMEDIATE") + .await + .map(Self::Sqlite), + Store::Postgres(store) => store.pool.begin().await.map(Self::Postgres), + } + .map_err(|error| map_db_error(&error)) + } + + async fn lock_sandbox(&mut self, sandbox_id: &str) -> PersistenceResult { + let row = match self { + Self::Sqlite(tx) => { + sqlx::query_as::<_, (Vec, i64)>( + r#"SELECT "payload", "resource_version" FROM "objects" +WHERE "object_type" = 'sandbox' AND "id" = ?1"#, + ) + .bind(sandbox_id) + .fetch_optional(&mut **tx) + .await + } + Self::Postgres(tx) => { + sqlx::query_as::<_, (Vec, i64)>( + "SELECT payload, resource_version FROM objects +WHERE object_type = 'sandbox' AND id = $1 FOR UPDATE", + ) + .bind(sandbox_id) + .fetch_optional(&mut **tx) + .await + } + } + .map_err(|error| map_db_error(&error))? + .ok_or_else(|| conflict(None))?; + decode_sandbox(sandbox_id, &row.0, row.1) + } + + async fn lock_state( + &mut self, + sandbox_id: &str, + ) -> PersistenceResult> { + let id = state_id(sandbox_id); + let payload = match self { + Self::Sqlite(tx) => { + sqlx::query_scalar::<_, Vec>( + r#"SELECT "payload" FROM "objects" WHERE "object_type" = ?1 AND "id" = ?2"#, + ) + .bind(IMAGE_STATE_OBJECT_TYPE) + .bind(&id) + .fetch_optional(&mut **tx) + .await + } + Self::Postgres(tx) => { + sqlx::query_scalar::<_, Vec>( + "SELECT payload FROM objects WHERE object_type = $1 AND id = $2 FOR UPDATE", + ) + .bind(IMAGE_STATE_OBJECT_TYPE) + .bind(&id) + .fetch_optional(&mut **tx) + .await + } + } + .map_err(|error| map_db_error(&error))?; + payload + .map(|payload| decode_state(sandbox_id, &payload)) + .transpose() + } + + async fn write_projection( + &mut self, + sandbox_id: &str, + previous_version: u64, + sandbox: &Sandbox, + state: &StoredSandboxImageState, + ) -> PersistenceResult<()> { + let previous_version_sql = i64::try_from(previous_version).map_err(|_| { + PersistenceError::Encode("sandbox resource version exceeds database range".into()) + })?; + let now_ms = current_time_ms(); + let sandbox_payload = sandbox.encode_to_vec(); + let affected = match self { + Self::Sqlite(tx) => sqlx::query( + r#"UPDATE "objects" +SET "payload" = ?2, "updated_at_ms" = ?3, "resource_version" = "resource_version" + 1 +WHERE "object_type" = 'sandbox' AND "id" = ?1 AND "resource_version" = ?4"#, + ) + .bind(sandbox_id) + .bind(&sandbox_payload) + .bind(now_ms) + .bind(previous_version_sql) + .execute(&mut **tx) + .await + .map(|result| result.rows_affected()), + Self::Postgres(tx) => sqlx::query( + "UPDATE objects +SET payload = $2, updated_at_ms = $3, resource_version = resource_version + 1 +WHERE object_type = 'sandbox' AND id = $1 AND resource_version = $4", + ) + .bind(sandbox_id) + .bind(&sandbox_payload) + .bind(now_ms) + .bind(previous_version_sql) + .execute(&mut **tx) + .await + .map(|result| result.rows_affected()), + } + .map_err(|error| map_db_error(&error))?; + if affected != 1 { + return Err(conflict(Some(previous_version))); + } + + let id = state_id(sandbox_id); + let state_payload = state.encode_to_vec(); + let affected = match self { + Self::Sqlite(tx) => sqlx::query( + r#"INSERT INTO "objects" ( + "object_type", "id", "name", "workspace", "payload", "created_at_ms", "updated_at_ms" +) VALUES (?1, ?2, NULL, '', ?3, ?4, ?4) +ON CONFLICT ("id") DO UPDATE +SET "payload" = excluded."payload", "updated_at_ms" = excluded."updated_at_ms", + "resource_version" = "objects"."resource_version" + 1 +WHERE "objects"."object_type" = ?1 AND "objects"."name" IS NULL AND "objects"."workspace" = ''"#, + ) + .bind(IMAGE_STATE_OBJECT_TYPE) + .bind(&id) + .bind(&state_payload) + .bind(now_ms) + .execute(&mut **tx) + .await + .map(|result| result.rows_affected()), + Self::Postgres(tx) => sqlx::query( + "INSERT INTO objects ( + object_type, id, name, workspace, payload, created_at_ms, updated_at_ms +) VALUES ($1, $2, NULL, '', $3, $4, $4) +ON CONFLICT (id) DO UPDATE +SET payload = EXCLUDED.payload, updated_at_ms = EXCLUDED.updated_at_ms, + resource_version = objects.resource_version + 1 +WHERE objects.object_type = $1 AND objects.name IS NULL AND objects.workspace = ''", + ) + .bind(IMAGE_STATE_OBJECT_TYPE) + .bind(&id) + .bind(&state_payload) + .bind(now_ms) + .execute(&mut **tx) + .await + .map(|result| result.rows_affected()), + } + .map_err(|error| map_db_error(&error))?; + if affected != 1 { + return Err(PersistenceError::Database( + "sandbox image state identity is already occupied".into(), + )); + } + Ok(()) + } + + async fn commit(self) -> PersistenceResult<()> { + match self { + Self::Sqlite(tx) => tx.commit().await, + Self::Postgres(tx) => tx.commit().await, + } + .map_err(|error| map_db_error(&error)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use openshell_core::proto::{ObjectMeta, SandboxSpec, SandboxStatus, SandboxTemplate}; + + fn sandbox() -> Sandbox { + Sandbox { + metadata: Some(ObjectMeta { + id: "sandbox-id".into(), + name: "sandbox-name".into(), + workspace: "default".into(), + resource_version: 5, + ..Default::default() + }), + spec: Some(SandboxSpec { + template: Some(SandboxTemplate { + image: "old-image".into(), + ..Default::default() + }), + ..Default::default() + }), + status: Some(SandboxStatus { + phase: SandboxPhase::Stopped as i32, + ..Default::default() + }), + ..Default::default() + } + } + + fn intent() -> StoredSandboxImageUpdate { + StoredSandboxImageUpdate { + operation_id: "operation-id".into(), + previous_image: "old-image".into(), + image: "new-image".into(), + revision: 1, + } + } + + fn image(sandbox: &Sandbox) -> &str { + &sandbox + .spec + .as_ref() + .unwrap() + .template + .as_ref() + .unwrap() + .image + } + + #[test] + fn begin_and_complete_project_image_and_baseline_known_interlock() { + let original = sandbox(); + let (accepted, state) = project_begin(original.clone(), None, 5, 0, &intent()).unwrap(); + assert_eq!(image(&accepted), "new-image"); + assert_eq!(resource_version(&accepted), 6); + let operation = accepted + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .unwrap(); + assert!(operation.driver_operation_pending); + assert_eq!(operation.driver_operation_id, intent().operation_id); + assert_eq!(operation.attempt_id, "image-update:operation-id"); + assert!(operation.deadline.is_none()); + assert!(operation.preparation_deadline.is_none()); + assert!(state.previous_provisioning.is_none()); + assert_eq!(state.pending, Some(intent())); + let (completed, state) = project_complete(accepted, Some(state), &intent()).unwrap(); + assert_eq!(resource_version(&completed), 7); + assert_eq!(completed.status, original.status); + assert_eq!(state.revision, 1); + assert!(state.pending.is_none()); + assert!(state.previous_provisioning.is_none()); + } + + #[test] + fn completion_restores_existing_provisioning_except_last_operation_identity() { + let mut original = sandbox(); + let previous = SandboxProvisioning { + attempt_id: "previous-attempt".into(), + driver_operation_id: "previous-settled-operation".into(), + timeout_time: Some(prost_types::Timestamp { + seconds: 123, + nanos: 456, + }), + cleanup_completed_time: Some(prost_types::Timestamp { + seconds: 124, + nanos: 0, + }), + cleanup_error: "retained diagnostic".into(), + ..Default::default() + }; + original.status.as_mut().unwrap().provisioning = Some(previous.clone()); + let (accepted, state) = project_begin(original.clone(), None, 5, 0, &intent()).unwrap(); + assert_eq!(state.previous_provisioning, Some(previous)); + let (completed, cleared) = project_complete(accepted, Some(state), &intent()).unwrap(); + original + .status + .as_mut() + .unwrap() + .provisioning + .as_mut() + .unwrap() + .driver_operation_id = intent().operation_id; + assert_eq!(completed.status, original.status); + assert!(cleared.previous_provisioning.is_none()); + assert!(cleared.pending.is_none()); + assert_eq!(cleared.revision, 1); + } + + #[test] + fn delayed_previous_operation_cannot_match_completed_image_operation() { + let mut original = sandbox(); + let previous = SandboxProvisioning { + attempt_id: "retained-attempt".into(), + driver_operation_id: "delayed-operation".into(), + timeout_time: Some(prost_types::Timestamp { + seconds: 456, + nanos: 0, + }), + cleanup_completed_time: Some(prost_types::Timestamp { + seconds: 457, + nanos: 0, + }), + ..Default::default() + }; + original.status.as_mut().unwrap().provisioning = Some(previous.clone()); + let (accepted, state) = project_begin(original, None, 5, 0, &intent()).unwrap(); + let (completed, _) = project_complete(accepted, Some(state), &intent()).unwrap(); + let current = completed + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .unwrap(); + // Baseline same_operation compares this pair. Preserve the attempt and + // timeout provenance without resurrecting the old callback's identity. + assert_ne!( + (¤t.attempt_id, ¤t.driver_operation_id), + (&previous.attempt_id, &previous.driver_operation_id) + ); + assert_eq!(current.attempt_id, previous.attempt_id); + assert_eq!(current.driver_operation_id, intent().operation_id); + assert!(!current.driver_operation_pending); + assert_eq!(current.timeout_time, previous.timeout_time); + assert_eq!( + current.cleanup_completed_time, + previous.cleanup_completed_time + ); + } + + #[test] + fn image_completion_preserves_concurrent_attachment_clock_edits() { + let mut original = sandbox(); + let mut previous = crate::compute::provisioning_deadline::new_preparation_record(0, 1800); + previous.driver_operation_id = "prior-operation".into(); + previous.attachment_change_id = "before-attachment".into(); + original.status.as_mut().unwrap().provisioning = Some(previous); + let (mut accepted, state) = project_begin(original, None, 5, 0, &intent()).unwrap(); + crate::compute::provisioning_deadline::attachments_changed(&mut accepted, 2_000); + let mut expected = accepted + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .unwrap() + .clone(); + assert_ne!(expected.attachment_change_id, "before-attachment"); + expected.driver_operation_pending = false; + let (completed, state) = project_complete(accepted, Some(state), &intent()).unwrap(); + assert_eq!(completed.status.unwrap().provisioning, Some(expected)); + assert!(state.previous_provisioning.is_none()); + } + + #[test] + fn image_completion_cannot_settle_a_replaced_provisioning_attempt() { + let (mut accepted, state) = project_begin(sandbox(), None, 5, 0, &intent()).unwrap(); + accepted + .status + .as_mut() + .unwrap() + .provisioning + .as_mut() + .unwrap() + .attempt_id = "replacement-attempt".into(); + assert!(matches!( + project_complete(accepted, Some(state), &intent()), + Err(PersistenceError::Conflict { .. }) + )); + } + + #[test] + fn pending_driver_operation_is_not_overwritten_and_completion_requires_its_fence() { + let mut occupied = sandbox(); + occupied.status.as_mut().unwrap().provisioning = Some(SandboxProvisioning { + attempt_id: "other-attempt".into(), + driver_operation_pending: true, + driver_operation_id: "other-operation".into(), + ..Default::default() + }); + assert!(project_begin(occupied, None, 5, 0, &intent()).is_err()); + let (accepted, state) = project_begin(sandbox(), None, 5, 0, &intent()).unwrap(); + let mut missing = accepted.clone(); + missing.status.as_mut().unwrap().provisioning = None; + assert!(project_complete(missing, Some(state.clone()), &intent()).is_err()); + let mut cleared = accepted.clone(); + cleared + .status + .as_mut() + .unwrap() + .provisioning + .as_mut() + .unwrap() + .driver_operation_pending = false; + assert!(project_complete(cleared, Some(state.clone()), &intent()).is_err()); + let mut other = accepted; + other + .status + .as_mut() + .unwrap() + .provisioning + .as_mut() + .unwrap() + .driver_operation_id = "other".into(); + assert!(project_complete(other, Some(state), &intent()).is_err()); + } + + #[test] + fn begin_rejects_stale_versions_revisions_and_pending_updates() { + for version in [0, 4, 6] { + assert!(matches!( + project_begin(sandbox(), None, version, 0, &intent()), + Err(PersistenceError::Conflict { .. }) + )); + } + assert!(project_begin(sandbox(), None, 5, 1, &intent()).is_err()); + let mut wrong = intent(); + wrong.revision = 2; + assert!(project_begin(sandbox(), None, 5, 0, &wrong).is_err()); + let (accepted, state) = project_begin(sandbox(), None, 5, 0, &intent()).unwrap(); + let next = StoredSandboxImageUpdate { + operation_id: "next-operation".into(), + previous_image: "new-image".into(), + image: "newer-image".into(), + revision: 2, + }; + assert!(project_begin(accepted, Some(state), 6, 1, &next).is_err()); + } + + #[test] + fn lifecycle_and_image_checks_apply_at_acceptance_and_completion() { + let mut running = sandbox(); + running.status.as_mut().unwrap().phase = SandboxPhase::Ready as i32; + assert!(project_begin(running, None, 5, 0, &intent()).is_err()); + let mut deleting = sandbox(); + deleting.metadata.as_mut().unwrap().deletion_time = Some(prost_types::Timestamp::default()); + assert!(project_begin(deleting, None, 5, 0, &intent()).is_err()); + let mut wrong_image = sandbox(); + wrong_image + .spec + .as_mut() + .unwrap() + .template + .as_mut() + .unwrap() + .image = "other".into(); + assert!(project_begin(wrong_image, None, 5, 0, &intent()).is_err()); + let (accepted, state) = project_begin(sandbox(), None, 5, 0, &intent()).unwrap(); + let mut stale_intent = intent(); + stale_intent.operation_id = "other-operation".into(); + assert!(project_complete(accepted.clone(), Some(state.clone()), &stale_intent).is_err()); + let mut changed = accepted.clone(); + changed + .spec + .as_mut() + .unwrap() + .template + .as_mut() + .unwrap() + .image = "other".into(); + assert!(project_complete(changed, Some(state.clone()), &intent()).is_err()); + let mut running = accepted.clone(); + running.status.as_mut().unwrap().phase = SandboxPhase::Starting as i32; + assert!(project_complete(running, Some(state.clone()), &intent()).is_err()); + let mut deleting = accepted.clone(); + deleting.metadata.as_mut().unwrap().deletion_time = Some(prost_types::Timestamp::default()); + assert!(project_complete(deleting, Some(state.clone()), &intent()).is_err()); + let mut wrong_revision = state; + wrong_revision.revision = 2; + assert!(project_complete(accepted.clone(), Some(wrong_revision), &intent()).is_err()); + assert!(project_complete(accepted, None, &intent()).is_err()); + } + + #[test] + fn sandbox_decode_uses_authoritative_column_and_rejects_invalid_identity() { + let original = sandbox(); + let decoded = decode_sandbox("sandbox-id", &original.encode_to_vec(), 12).unwrap(); + assert_eq!(resource_version(&decoded), 12); + assert!(decode_sandbox("other-id", &original.encode_to_vec(), 12).is_err()); + assert!(decode_sandbox("sandbox-id", &original.encode_to_vec(), 0).is_err()); + } + + #[test] + fn resource_version_overflow_and_invalid_intents_do_not_project() { + let mut exhausted = sandbox(); + exhausted.set_resource_version(i64::MAX.cast_unsigned()); + assert!(matches!( + project_begin(exhausted, None, i64::MAX.cast_unsigned(), 0, &intent()), + Err(PersistenceError::Encode(_)) + )); + let mut invalid = intent(); + invalid.operation_id.clear(); + assert!(matches!( + project_begin(sandbox(), None, 5, 0, &invalid), + Err(PersistenceError::Encode(_)) + )); + } + + async fn fixture() -> (Store, Sandbox) { + let store = super::super::test_store().await; + store.put_message(&sandbox()).await.unwrap(); + let stored = store + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(); + (store, stored) + } + + #[tokio::test] + async fn sqlite_accept_complete_and_legacy_rewrite_preserve_independent_state() { + let (store, original) = fixture().await; + let version = resource_version(&original); + let accepted = store + .begin_sandbox_image_update("sandbox-id", version, 0, &intent()) + .await + .unwrap(); + assert_eq!(resource_version(&accepted), version + 1); + assert_eq!(image(&accepted), "new-image"); + let pending = store + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .unwrap(); + assert_eq!(pending.pending, Some(intent())); + // Generic Sandbox decode/reencode cannot remove the separate intent. + let decoded = Sandbox::decode(accepted.encode_to_vec().as_slice()).unwrap(); + assert!( + decoded + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .unwrap() + .driver_operation_pending + ); + assert_eq!( + decoded + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .unwrap() + .driver_operation_id, + intent().operation_id + ); + store.put_message(&decoded).await.unwrap(); + assert_eq!( + store.get_sandbox_image_state("sandbox-id").await.unwrap(), + Some(pending) + ); + let before_complete = store + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(); + let completed = store + .complete_sandbox_image_update("sandbox-id", &intent()) + .await + .unwrap(); + assert_eq!( + resource_version(&completed), + resource_version(&before_complete) + 1 + ); + let retained = store + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .unwrap(); + assert_eq!(retained.revision, 1); + assert!(retained.pending.is_none()); + assert!(retained.previous_provisioning.is_none()); + assert_eq!(completed.status, original.status); + // A Start based on any pre-completion snapshot must lose its CAS. + let mut stale_start = before_complete.clone(); + stale_start.status.as_mut().unwrap().phase = SandboxPhase::Starting as i32; + assert!(matches!( + store + .put_if( + "sandbox", + "sandbox-id", + "sandbox-name", + "default", + &stale_start.encode_to_vec(), + None, + super::super::WriteCondition::MatchResourceVersion(resource_version( + &before_complete + )), + ) + .await, + Err(PersistenceError::Conflict { .. }) + )); + // Neither a completed operation nor an older generation can be replayed. + assert!( + store + .complete_sandbox_image_update("sandbox-id", &intent()) + .await + .is_err() + ); + let next = StoredSandboxImageUpdate { + operation_id: "next-operation".into(), + previous_image: "new-image".into(), + image: "newer-image".into(), + revision: 2, + }; + store + .begin_sandbox_image_update("sandbox-id", resource_version(&completed), 1, &next) + .await + .unwrap(); + assert!( + store + .complete_sandbox_image_update("sandbox-id", &intent()) + .await + .is_err() + ); + assert_eq!( + store + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .unwrap() + .pending, + Some(next) + ); + } + + #[tokio::test] + async fn sqlite_restores_prior_provisioning_and_wrong_completion_keeps_fence() { + let (store, mut original) = fixture().await; + let previous = SandboxProvisioning { + attempt_id: "timed-out-attempt".into(), + driver_operation_id: "settled-driver-operation".into(), + timeout_time: Some(prost_types::Timestamp { + seconds: 123, + nanos: 0, + }), + cleanup_completed_time: Some(prost_types::Timestamp { + seconds: 124, + nanos: 0, + }), + ..Default::default() + }; + original.status.as_mut().unwrap().provisioning = Some(previous.clone()); + store.put_message(&original).await.unwrap(); + let mut original = store + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(); + let accepted = store + .begin_sandbox_image_update("sandbox-id", resource_version(&original), 0, &intent()) + .await + .unwrap(); + let mut wrong = intent(); + wrong.operation_id = "stale-operation".into(); + assert!( + store + .complete_sandbox_image_update("sandbox-id", &wrong) + .await + .is_err() + ); + assert_eq!( + store + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(), + accepted + ); + let state = store + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .unwrap(); + assert_eq!(state.pending, Some(intent())); + assert_eq!(state.previous_provisioning, Some(previous.clone())); + let completed = store + .complete_sandbox_image_update("sandbox-id", &intent()) + .await + .unwrap(); + let mut expected = previous; + expected.driver_operation_id = intent().operation_id; + assert_eq!( + completed.status.as_ref().unwrap().provisioning, + Some(expected.clone()) + ); + original.status.as_mut().unwrap().provisioning = Some(expected); + assert_eq!(completed.status, original.status); + assert!( + store + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .unwrap() + .previous_provisioning + .is_none() + ); + } + + #[tokio::test] + async fn sqlite_failed_cas_has_no_private_write() { + let (store, original) = fixture().await; + for version in [0, resource_version(&original) + 1] { + assert!(matches!( + store + .begin_sandbox_image_update("sandbox-id", version, 0, &intent()) + .await, + Err(PersistenceError::Conflict { .. }) + )); + } + assert!( + store + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .is_none() + ); + assert_eq!( + store + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(), + original + ); + } + + #[tokio::test] + async fn sqlite_private_write_failure_rolls_back_sandbox_and_completion() { + let (store, original) = fixture().await; + let Store::Sqlite(sqlite) = &store else { + unreachable!() + }; + sqlx::query( + "CREATE TRIGGER fail_image_insert BEFORE INSERT ON objects +WHEN NEW.object_type = 'sandbox_image_state' +BEGIN SELECT RAISE(ABORT, 'injected image state write failure'); END", + ) + .execute(&sqlite.pool) + .await + .unwrap(); + assert!( + store + .begin_sandbox_image_update("sandbox-id", resource_version(&original), 0, &intent()) + .await + .is_err() + ); + assert_eq!( + store + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(), + original + ); + assert!( + store + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .is_none() + ); + sqlx::query("DROP TRIGGER fail_image_insert") + .execute(&sqlite.pool) + .await + .unwrap(); + let accepted = store + .begin_sandbox_image_update("sandbox-id", resource_version(&original), 0, &intent()) + .await + .unwrap(); + let pending = store.get_sandbox_image_state("sandbox-id").await.unwrap(); + sqlx::query( + "CREATE TRIGGER fail_image_update BEFORE UPDATE ON objects +WHEN NEW.object_type = 'sandbox_image_state' +BEGIN SELECT RAISE(ABORT, 'injected image state write failure'); END", + ) + .execute(&sqlite.pool) + .await + .unwrap(); + assert!( + store + .complete_sandbox_image_update("sandbox-id", &intent()) + .await + .is_err() + ); + assert_eq!( + store + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(), + accepted + ); + assert_eq!( + store.get_sandbox_image_state("sandbox-id").await.unwrap(), + pending + ); + } + + #[tokio::test] + #[ignore = "requires a disposable PostgreSQL database in OPENSHELL_TEST_POSTGRES_URL; run mise run test:rust:postgres"] + async fn postgres_sandbox_image_state_survives_legacy_writes_and_fences_concurrent_updates() { + use super::super::{WriteCondition, test_postgres::TestSchema}; + + let schema = TestSchema::create("sandbox_image").await; + let first = schema.connect_store().await; + let second = schema.connect_store().await; + crate::ensure_default_workspace(&first).await.unwrap(); + first.put_message(&sandbox()).await.unwrap(); + let original = second + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(); + let version = resource_version(&original); + let left = intent(); + let right = StoredSandboxImageUpdate { + operation_id: "competing-operation".into(), + image: "competing-image".into(), + ..intent() + }; + + // Independent pools contend on the same sandbox row; exactly one + // transaction may publish revision 1 and its matching operation fence. + let (left_result, right_result) = tokio::join!( + first.begin_sandbox_image_update("sandbox-id", version, 0, &left), + second.begin_sandbox_image_update("sandbox-id", version, 0, &right), + ); + let (accepted, winning_intent) = match (left_result, right_result) { + (Ok(accepted), Err(PersistenceError::Conflict { .. })) => (accepted, left), + (Err(PersistenceError::Conflict { .. }), Ok(accepted)) => (accepted, right), + results => panic!("expected one accepted image update and one conflict: {results:?}"), + }; + let visible = second + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(); + assert_eq!(visible, accepted); + assert_eq!(resource_version(&visible), version + 1); + assert_eq!(image(&visible), winning_intent.image); + let pending = second + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .unwrap(); + assert_eq!(pending.revision, 1); + assert_eq!(pending.pending, Some(winning_intent.clone())); + let operation = visible + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .unwrap(); + assert!(operation.driver_operation_pending); + assert_eq!(operation.driver_operation_id, winning_intent.operation_id); + + let mut stale_start = original; + stale_start.status.as_mut().unwrap().phase = SandboxPhase::Starting as i32; + assert!(matches!( + second + .put_if( + "sandbox", + "sandbox-id", + "sandbox-name", + "default", + &stale_start.encode_to_vec(), + None, + WriteCondition::MatchResourceVersion(version), + ) + .await, + Err(PersistenceError::Conflict { .. }) + )); + + // Model an old gateway's ordinary unrelated Sandbox-only SQL rewrite. + // All provisioning fields used here are baseline-known. The private + // state has no public Sandbox field for this roundtrip to overwrite. + let mut legacy_rewrite = Sandbox::decode(visible.encode_to_vec().as_slice()).unwrap(); + legacy_rewrite + .metadata + .as_mut() + .unwrap() + .annotations + .insert( + "test.openshell.dev/legacy-write".into(), + "unrelated-edit".into(), + ); + let Store::Postgres(legacy_store) = &second else { + unreachable!() + }; + let rewritten = sqlx::query( + "UPDATE objects SET payload = $2, resource_version = resource_version + 1, +updated_at_ms = $3 WHERE object_type = 'sandbox' AND id = $1 AND resource_version = $4", + ) + .bind("sandbox-id") + .bind(legacy_rewrite.encode_to_vec()) + .bind(current_time_ms()) + .bind(i64::try_from(resource_version(&visible)).unwrap()) + .execute(&legacy_store.pool) + .await + .unwrap(); + assert_eq!(rewritten.rows_affected(), 1); + assert_eq!( + first.get_sandbox_image_state("sandbox-id").await.unwrap(), + Some(pending) + ); + let rewritten = first + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(); + assert_eq!(resource_version(&rewritten), resource_version(&visible) + 1); + let operation = rewritten + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .unwrap(); + assert!(operation.driver_operation_pending); + assert_eq!(operation.driver_operation_id, winning_intent.operation_id); + let private_identity = sqlx::query_as::<_, (Option, String)>( + "SELECT name, workspace FROM objects WHERE object_type = $1 AND id = $2", + ) + .bind(IMAGE_STATE_OBJECT_TYPE) + .bind(state_id("sandbox-id")) + .fetch_one(&legacy_store.pool) + .await + .unwrap(); + assert_eq!(private_identity, (None, String::new())); + + let completed = first + .complete_sandbox_image_update("sandbox-id", &winning_intent) + .await + .unwrap(); + assert_eq!( + resource_version(&completed), + resource_version(&rewritten) + 1 + ); + assert!(completed.status.as_ref().unwrap().provisioning.is_none()); + let retained = second + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .unwrap(); + assert_eq!(retained.revision, 1); + assert!(retained.pending.is_none()); + assert!(retained.previous_provisioning.is_none()); + + let next = StoredSandboxImageUpdate { + operation_id: "next-generation-operation".into(), + previous_image: winning_intent.image.clone(), + image: "next-generation-image".into(), + revision: 2, + }; + let accepted_next = second + .begin_sandbox_image_update("sandbox-id", resource_version(&completed), 1, &next) + .await + .unwrap(); + assert_eq!(image(&accepted_next), next.image); + assert!(matches!( + first + .complete_sandbox_image_update("sandbox-id", &winning_intent) + .await, + Err(PersistenceError::Conflict { .. }) + )); + let still_pending = first + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .unwrap(); + assert_eq!(still_pending.revision, 2); + assert_eq!(still_pending.pending, Some(next.clone())); + assert_eq!( + first + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(), + accepted_next + ); + + let final_sandbox = first + .complete_sandbox_image_update("sandbox-id", &next) + .await + .unwrap(); + assert_eq!( + resource_version(&final_sandbox), + resource_version(&accepted_next) + 1 + ); + assert!( + final_sandbox + .status + .as_ref() + .unwrap() + .provisioning + .is_none() + ); + assert_eq!( + second + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(), + final_sandbox + ); + let retained = second + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .unwrap(); + assert_eq!(retained.revision, 2); + assert!(retained.pending.is_none()); + assert!(retained.previous_provisioning.is_none()); + // Completion also invalidates a Start CAS based on the pending snapshot. + assert!(matches!( + second + .put_if( + "sandbox", + "sandbox-id", + "sandbox-name", + "default", + &accepted_next.encode_to_vec(), + None, + WriteCondition::MatchResourceVersion(resource_version(&accepted_next)), + ) + .await, + Err(PersistenceError::Conflict { .. }) + )); + + first.close().await; + second.close().await; + schema.drop_schema().await; + } +} diff --git a/crates/openshell-server/src/persistence/sqlite.rs b/crates/openshell-server/src/persistence/sqlite.rs index 94d52a67f2..8c434dcaa4 100644 --- a/crates/openshell-server/src/persistence/sqlite.rs +++ b/crates/openshell-server/src/persistence/sqlite.rs @@ -48,7 +48,7 @@ pub const DEFAULT_MAX_CONNECTIONS: u32 = 5; #[derive(Debug, Clone)] pub struct SqliteStore { - pool: SqlitePool, + pub(super) pool: SqlitePool, /// Pool for writes whose loss after a crash is harmless; see /// [`SqliteStore::create_relaxed`]. On-disk stores open it with /// `synchronous=NORMAL`; in-memory stores share `pool`. diff --git a/crates/openshell-server/src/reflection.rs b/crates/openshell-server/src/reflection.rs index 140b53659e..d8eb12482e 100644 --- a/crates/openshell-server/src/reflection.rs +++ b/crates/openshell-server/src/reflection.rs @@ -28,7 +28,7 @@ use openshell_core::Config; use crate::multiplex::GrpcRateLimiter; const REFLECTED_PROTO_ROOTS: &[&str] = &["openshell.proto"]; -const ADVERTISED_SERVICES: &[&str] = &["openshell.v1.OpenShell"]; +const ADVERTISED_SERVICES: &[&str] = &["openshell.v1.OpenShell", "openshell.v1.SandboxUpdates"]; pub type GatewayReflectionServer = ServerReflectionServer; diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index 360c2dd2fa..9212dfeea6 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -15,6 +15,11 @@ include!(concat!(env!("OUT_DIR"), "/openshell.storage.v1.rs")); +mod sandbox_image { + include!(concat!(env!("OUT_DIR"), "/openshell.storage.image.v1.rs")); +} +pub(crate) use sandbox_image::{StoredSandboxImageState, StoredSandboxImageUpdate}; + pub(crate) const STORAGE_FILE_DESCRIPTOR_SET: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/storage_descriptor.bin")); @@ -164,17 +169,15 @@ mod tests { // SandboxPhase enum. Stored rows never carried those values, so prior // payloads decode unchanged. - // Image updates add UpdateSandboxRequest to the public inventory and - // SandboxImageUpdate to both the public and durable inventories through - // SandboxStatus. The pending intent and monotonic image revision follow the - // existing token-grant observation without reusing its wire tag. Legacy - // sandboxes decode absent/zero; revisions fence delayed driver retries. + // Image updates add a separate public service/request and a new private + // image-state format. Existing public status and frozen storage.v1 stay + // unchanged; only the private durable closure grows. const PUBLIC_RPC_SCHEMA_SHA256: &str = - "ad55008e162f4c0c759a047b12d4a8b30ffc04d02899edb2a5d7be44fa79fba5"; + "15367b833a8ef74b18f4b1d06d88e43a6f6751ebd52135b70cd095808ee8438d"; const DURABLE_SCHEMA_SHA256: &str = - "36eace7a0236872f5167913e53c5be19805b837f18d85b7f6a7dee05c25a896a"; + "74d934bb33cc275730f193927d709f932681e8821868cf9b2261d10eba9e1195"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = - "9997e51420f29542cefd99d394e211a8e5a21967f4f0fb9ac94aaf598a821b11"; + "ac1ffc4b5b81467de27270a4e33f6db1e31eeb2c52f79750dbaaf19515eadbb2"; // 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"; @@ -235,6 +238,7 @@ mod tests { ".openshell.storage.v1.StoredConfigUpdateOperation", ".openshell.storage.v1.StoredProviderCredentialRefreshStateV2", ".openshell.storage.v1.StoredProviderProfile", + ".openshell.storage.image.v1.StoredSandboxImageState", ".openshell.v1.Sandbox", ".openshell.v1.SandboxWorkloadTemplate", ".openshell.v1.ServiceEndpoint", @@ -477,7 +481,12 @@ mod tests { let public = FileDescriptorSet::decode(openshell_core::FILE_DESCRIPTOR_SET) .expect("public descriptor set must decode"); for file in public.file { - assert_ne!(file.package.as_deref(), Some("openshell.storage.v1")); + assert!( + !file + .package + .as_deref() + .is_some_and(|package| package.starts_with("openshell.storage.")) + ); for message in file.message_type { let name = message.name.expect("message name"); assert!( @@ -582,7 +591,8 @@ mod tests { } if !matches!( (package, service_name), - ("openshell.v1", "OpenShell") | ("openshell.inference.v1", "Inference") + ("openshell.v1", "OpenShell" | "SandboxUpdates") + | ("openshell.inference.v1", "Inference") ) { continue; } @@ -657,7 +667,7 @@ mod tests { .iter() .filter(|method| method.starts_with("openshell.v1.OpenShell/")) .count(), - 81 + PROVIDER_READINESS_RPC_SIGNATURES.len() + 80 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len() + PEER_CONFIG_RPC_SIGNATURES.len() ); @@ -708,9 +718,9 @@ mod tests { overlap_hash.as_str(), ), ( - (332, 31), - (96, 22), - (84, 22), + (331, 31), + (97, 22), + (83, 22), PUBLIC_RPC_SCHEMA_SHA256, DURABLE_SCHEMA_SHA256, PUBLIC_DURABLE_OVERLAP_SHA256 @@ -719,17 +729,6 @@ mod tests { ); } - #[test] - fn pre_image_update_sandbox_has_no_pending_image_intent() { - let sandbox = openshell_core::proto::Sandbox::decode( - legacy_bytes(SANDBOX_WITHOUT_ENDPOINT_STATUS).as_slice(), - ) - .expect("legacy sandbox must remain decodable"); - let status = sandbox.status.unwrap(); - assert!(status.image_update.is_none()); - assert_eq!(status.image_revision, 0); - } - #[test] fn service_endpoint_without_authorization_mode_decodes_as_strip() { use openshell_core::proto::{ServiceAuthorizationMode, ServiceEndpoint}; diff --git a/crates/openshell-server/tests/common/mod.rs b/crates/openshell-server/tests/common/mod.rs index 6296034d6b..dd91664d39 100644 --- a/crates/openshell-server/tests/common/mod.rs +++ b/crates/openshell-server/tests/common/mod.rs @@ -59,13 +59,6 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not used by this test server")) } - async fn update_sandbox( - &self, - _request: tonic::Request, - ) -> Result, Status> { - Err(Status::unimplemented("not implemented by test service")) - } - async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-server/tests/supervisor_relay_integration.rs b/crates/openshell-server/tests/supervisor_relay_integration.rs index 283bbca2b7..ceb2fa6bf8 100644 --- a/crates/openshell-server/tests/supervisor_relay_integration.rs +++ b/crates/openshell-server/tests/supervisor_relay_integration.rs @@ -57,13 +57,6 @@ impl OpenShell for RelayGateway { Err(Status::unimplemented("not used by this test server")) } - async fn update_sandbox( - &self, - _request: tonic::Request, - ) -> Result, Status> { - Err(Status::unimplemented("not implemented by test service")) - } - async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/docs/how-it-works/gateways/configuration.mdx b/docs/how-it-works/gateways/configuration.mdx index ef49f8ec86..bdc25b875b 100644 --- a/docs/how-it-works/gateways/configuration.mdx +++ b/docs/how-it-works/gateways/configuration.mdx @@ -255,6 +255,9 @@ metrics_bind_address = "0.0.0.0:9090" log_level = "info" +# Activate only after retiring incompatible gateways and outstanding driver work. +enable_sandbox_image_updates = false + # Connection ceiling for the gateway's database pool. Omit to use the backend # default: 10 for Postgres, 5 for on-disk SQLite. database_max_connections = 10 @@ -499,6 +502,41 @@ Changing the installation name, the hostname format, or both changes every hash URL issued before the change; previously issued URLs stop resolving until callers request a fresh URL. +## Sandbox Image Updates + +`[openshell.gateway] enable_sandbox_image_updates` defaults to `false`. It gates +the separate `openshell.v1.SandboxUpdates/UpdateSandbox` RPC on the existing +gateway listener. The equivalent gateway process flag and environment variable +are `--enable-sandbox-image-updates true` and +`OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES=true`. + +Enable it only after completing the +[activation checklist](/kubernetes/high-availability#activate-sandbox-image-updates). +Setting it to `true` attests that every gateway that can write the database is +compatible and incompatible gateways cannot return. Keep it false throughout a +rolling upgrade, including while outstanding operations from retired gateways +settle. Database and membership checks fail closed but do not prove retirement. + +For a schema-v2 file, set: + +```toml +[openshell.gateway] +enable_sandbox_image_updates = true +``` + +The canonical Helm values form uses a dotted table key: + +```yaml +gatewayConfig: + "openshell.gateway": + enable_sandbox_image_updates: true +``` + +This is not an automatic mixed-version migration switch. Do not downgrade while +an image update is pending or retained sandboxes require the private image +revision protocol. SQLite supports one gateway process only; activation attests +that the previous process has stopped, not that sharing a SQLite file enables HA. + ## Database Pool `[openshell.gateway] database_max_connections` sets the connection ceiling for the gateway's database pool. One pool is shared by every database-backed RPC, so this value is also the gateway's ceiling on concurrent database work. When the pool is saturated, callers queue on connection acquisition and sqlx logs that the time to acquire a connection exceeded its slow threshold. The background readiness monitor draws from the same pool, so sustained saturation can push its database ping past the check timeout and flip `/readyz` to not-ready while the gateway is otherwise serving. @@ -1648,7 +1686,7 @@ compute_driver = "kyma" socket_path = "/run/openshell/kyma-compute-driver.sock" ``` -## Preflight package configuration {#gateway-config-preflight} +

Preflight package configuration

Before starting a package-managed gateway, validate the selected file without changing it: diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index bfe19d6f27..2880287b09 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -1012,17 +1012,24 @@ For a provisioning timeout, wait for cleanup to finish, then run `sandbox start` ### Update the Image of a Stopped Sandbox -Use the raw `UpdateSandbox` RPC to change only a stopped sandbox's workload -image. This operation initially supports the Kubernetes compute driver only; -other drivers return `UNIMPLEMENTED`. There is no `sandbox update` CLI command -or curated SDK update method. +Use `openshell.v1.SandboxUpdates/UpdateSandbox` to change only a stopped +sandbox's workload image. This separate service uses the same gateway listener +and authentication as `OpenShell`; it requires `sandbox:write` and workspace +user access. This operation initially supports the Kubernetes compute driver +only; other drivers return `UNIMPLEMENTED` after activation. There is no +`sandbox update` CLI command or curated SDK update method. + +Image updates default to disabled. Ask the operator to complete the +[compatible deployment rollout](/kubernetes/high-availability#activate-sandbox-image-updates) +before enabling `enable_sandbox_image_updates` in the +[gateway configuration](/how-it-works/gateways/configuration#sandbox-image-updates). The update preserves the sandbox ID, Kubernetes custom resource, and persistent volume claim. It does not delete and recreate the sandbox, reseed its existing workspace from the new image, or change the trusted supervisor and sandbox -runtime images. Other create-time configuration remains unchanged. Submitting the -same image reference is a no-op; use a different tag or an immutable digest to -select new image content. +runtime images. Other create-time configuration remains unchanged. Without a +pending update, submitting the same image reference is a no-op. Use a different +tag or an immutable digest to select new image content. Follow this sequence through the CLI and a generated/raw RPC client. @@ -1035,6 +1042,25 @@ Follow this sequence through the CLI and a generated/raw RPC client. 4. After the update succeeds, run `openshell sandbox start my-sandbox` to launch the new image. +With an authenticated Rust SDK `OpenShellClient`, use the separate raw client +and the `current_resource_version` read in step 2: + +```rust +use openshell_sdk::raw::{UpdateSandboxRequest, proto}; + +let mut updates = client.raw_sandbox_updates_fresh().await?; +let response = updates.update_sandbox(UpdateSandboxRequest { + workspace_scope: Some(proto::workspace_selector("default")), + name: "my-sandbox".into(), + image: "registry.example.com/agents/my-agent:2.0".into(), + expected_resource_version: current_resource_version, + request_id: String::new(), +}).await?; +``` + +The helper shares the main client's transport and live authentication slot. +Generated clients use the `SandboxUpdates` service, not `OpenShell`. + If the new image fails to start and provisioning times out, wait until `provisioning.cleanup_completed_time` is present and `provisioning.driver_operation_pending` is false. Run `sandbox stop` to move the @@ -1044,17 +1070,21 @@ compute again. Cleanup that is still pending cannot be bypassed. An `ABORTED` version conflict requires another read before you construct a new conditional request. An update failure or disconnected response can leave a -persistent `sandbox.status.image_update` intent, even when -`sandbox.spec.template.image` already names the target image. While that intent -exists, start is blocked. Read the current version and retry `UpdateSandbox` -with the intent's same `image`; do not select a different image or delete the -sandbox to bypass reconciliation. Only a successful retry clears the intent. +pending operation, even when `sandbox.spec.template.image` already names the +target image. Start, stop, provisioning retry, and delete reject the pending +operation. +The public `SandboxStatus` shape is unchanged; image intent and revision remain +private. Use the operation-pending error to guide recovery, not a status image +field. Read the current version and retry `UpdateSandbox` with the same image +you originally requested. Do not select another image or delete the sandbox to +bypass reconciliation. Only a successful retry clears the pending operation. The optional `request_id` uses [durable request admission](/sdk/api-errors#durable-request-admission). A retry with the same ID must keep the original payload, including its expected version. An unresolved admission returns `REQUEST_OUTCOME_UNCERTAIN` rather than -executing again. Reconcile the sandbox and pending target first, then submit a -new conditional same-image request with a fresh version and a new ID, or no ID. +executing again. Reconcile against the sandbox state and your original requested +image, then submit a new conditional same-image request with a fresh version +and a new ID, or no ID. Do not change the expected version under the original ID or blindly switch IDs after a timeout. diff --git a/docs/kubernetes/high-availability.mdx b/docs/kubernetes/high-availability.mdx index 8ab09ceca3..ed7a6b0ce9 100644 --- a/docs/kubernetes/high-availability.mdx +++ b/docs/kubernetes/high-availability.mdx @@ -504,6 +504,51 @@ during the upgrade, the older replicas serialize every mutation across the fleet. Mutations can be slower and can briefly fail under load until the rollout finishes. +### Activate Sandbox Image Updates + +Sandbox image updates default to disabled. Setting +`[openshell.gateway] enable_sandbox_image_updates = true` is an operator +attestation that the deployment uniformly supports the image-update protocol. +Use this sequence before activating the +[separate update service](/how-it-works/sandboxes/overview#update-the-image-of-a-stopped-sandbox). + +1. Keep the setting false throughout the rolling upgrade. Drain and retire + every incompatible gateway, including unregistered processes and Jobs, and + settle all outstanding driver operations they started. A completed + Kubernetes rollout alone does not establish this. +2. Prevent incompatible gateways from returning. Pin compatible images and + retire old rollback targets, Jobs, and other launch configurations that could + reconnect to the database. +3. Check all PostgreSQL client backends in the same database. The new binary + sets `application_name` to `openshell-image-update-v1` on every data-pool and + lock-pool connection. Any unmarked client backend, including an + administrative session, blocks image updates. Close those sessions or use a + dedicated database. Do not relabel an old process to bypass this check. +4. Confirm live gateway membership records advertise image-update protocol 1. + Missing or incompatible capabilities, malformed records, and truncated + membership reads reject updates. These observations are not durable proof + of fleet compatibility. Expiry or absence of a membership record does not + prove that its process and driver work have stopped. +5. Activate the flag only after completing retirement and preventing old + gateways from returning. See the exact + [TOML, environment, process flag, and Helm forms](/how-it-works/gateways/configuration#sandbox-image-updates). + +A pending image update atomically sets the existing +`provisioning.driver_operation_pending` and `provisioning.driver_operation_id` +fields alongside private image intent. Baseline start, stop, delete, and +provisioning-retry paths honor this per-sandbox barrier, including after a +legacy public record round-trip. Successful reconciliation preserves current +provisioning diagnostics and clocks, clears the pending flag, and retains the +new operation ID to fence delayed callbacks. Previously absent provisioning +remains absent unless concurrent writes added diagnostics or clocks. This +barrier does not replace the deployment activation checklist. +Image intent and revision are not new public `SandboxStatus` fields. + +Do not downgrade while updates are pending or retained sandboxes require the +private revision protocol. SQLite supports one gateway process only. For a +SQLite gateway, activation attests that the old process has stopped; a shared +SQLite file is not an HA deployment. + ## (Experimental) Multi-tenant supervisor By default, the Kubernetes driver runs a supervisor Pod for each sandbox. With diff --git a/docs/sdk/api-errors.mdx b/docs/sdk/api-errors.mdx index 592cebbe2f..6efc52650b 100644 --- a/docs/sdk/api-errors.mdx +++ b/docs/sdk/api-errors.mdx @@ -105,6 +105,10 @@ Thirty-one user-callable unary RPCs accept an optional `request_id` in their pro | Provider profile | `ImportProviderProfiles`, `UpdateProviderProfiles`, `DeleteProviderProfile` | | Policy and config | `UpdateConfig`, `ApproveDraftChunk`, `RejectDraftChunk`, `EditDraftChunk`, `UndoDraftChunk`, `ApproveAllDraftChunks`, `ClearDraftChunks` | +`UpdateSandbox` belongs to the separate `openshell.v1.SandboxUpdates` service +on the same authenticated gateway listener. The other RPCs above remain on +`openshell.v1.OpenShell`. + Use a nonzero, hyphenated UUID of exactly 36 characters. Uppercase and lowercase forms identify the same request. An empty ID preserves the existing behavior without deduplication. This ID is separate from transport correlation metadata. @@ -194,23 +198,27 @@ before relying on IDs; older protobuf servers can silently ignore unknown fields ### Sandbox image update recovery -`UpdateSandbox` is an image-only conditional mutation for stopped Kubernetes -sandboxes. Other compute drivers return `UNIMPLEMENTED`. Supply a named +`SandboxUpdates.UpdateSandbox` is an image-only conditional mutation for stopped +Kubernetes sandboxes. It defaults to disabled and returns `FAILED_PRECONDITION` +until the operator [activates a compatible deployment](/kubernetes/high-availability#activate-sandbox-image-updates). +After activation, other compute drivers return `UNIMPLEMENTED`. Supply a named `workspace_scope`, sandbox `name`, nonempty OCI `image`, and a required nonzero `expected_resource_version` read from `sandbox.metadata.resource_version`. A stale version returns `ABORTED`; read fresh state before constructing another conditional request. The operation does not start compute. -A failed or interrupted update can leave durable `sandbox.status.image_update` -state. The desired spec image alone does not prove driver reconciliation -completed. Start returns `FAILED_PRECONDITION` until you successfully retry the -same pending image using the current resource version. A different target image -cannot replace a pending update. +A failed or interrupted update can leave a pending operation. The desired spec +image alone does not prove driver reconciliation completed. Start, stop, +provisioning retry, and delete return `FAILED_PRECONDITION` while that operation remains. +Image intent and revision are private; the public `SandboxStatus` shape does not +change. On an operation-pending error, read a fresh resource version and retry +the same image originally requested. A different target image cannot replace a +pending update. If the original request supplied `request_id`, an error leaves its admission unresolved. Reusing that ID with the original payload returns `REQUEST_OUTCOME_UNCERTAIN`; changing its expected version returns -`REQUEST_ID_PAYLOAD_MISMATCH`. Inspect and reconcile the pending image first, +`REQUEST_ID_PAYLOAD_MISMATCH`. Reconcile against the original requested image, then make a new conditional same-image request with the fresh version and a new ID, or without an ID. This is explicit recovery, not permission to blindly repeat uncertain mutations. A replay of a confirmed success returns the diff --git a/e2e/rust/tests/kubernetes_image_update.rs b/e2e/rust/tests/kubernetes_image_update.rs index 9077e66761..d04f42ff0e 100644 --- a/e2e/rust/tests/kubernetes_image_update.rs +++ b/e2e/rust/tests/kubernetes_image_update.rs @@ -13,7 +13,7 @@ use std::time::Duration; use openshell_bootstrap::{load_active_gateway, load_gateway_metadata}; use openshell_e2e::harness::cli::{run_cli, wait_for_sandbox_phase}; use openshell_e2e::harness::sandbox::SandboxGuard; -use openshell_sdk::raw::{AuthedGrpcClient, proto}; +use openshell_sdk::raw::{AuthedGrpcClient, AuthedSandboxUpdatesClient, proto}; use openshell_sdk::{ClientConfig, EdgeAuthInterceptor, OpenShellClient}; use serde_json::Value; use tonic::transport::{Certificate, ClientTlsConfig, Endpoint, Identity}; @@ -26,14 +26,14 @@ const SENTINEL_PATH: &str = "/sandbox/.image-update-sentinel"; /// Reuse the wrapper's registered endpoint (including its isolated XDG config). /// The SDK owns plaintext transport; the `OpenShift` wrapper registers an mTLS /// gateway, for which we attach its existing client bundle to a tonic channel. -async fn gateway_client() -> AuthedGrpcClient { +async fn gateway_client() -> OpenShellClient { let name = std::env::var("OPENSHELL_GATEWAY") .ok() .filter(|name| !name.trim().is_empty()) .or_else(load_active_gateway) .expect("Kubernetes E2E wrapper must register a gateway"); let metadata = load_gateway_metadata(&name).expect("load E2E gateway metadata"); - let client = if metadata.gateway_endpoint.starts_with("http://") { + if metadata.gateway_endpoint.starts_with("http://") { OpenShellClient::connect(ClientConfig::new(metadata.gateway_endpoint)) .await .expect("connect to E2E gateway") @@ -65,8 +65,7 @@ async fn gateway_client() -> AuthedGrpcClient { .await .expect("connect to E2E gateway over mTLS"); OpenShellClient::from_parts(channel, EdgeAuthInterceptor::noop()) - }; - client.raw_grpc() + } } fn request_id() -> String { @@ -248,8 +247,11 @@ fn assert_update_completed(original: &proto::Sandbox, updated: &proto::Sandbox) let status = updated.status.as_ref().expect("updated status"); assert_eq!(status.phase, proto::SandboxPhase::Stopped as i32); assert!( - status.image_update.is_none(), - "successful update must clear pending intent" + status + .provisioning + .as_ref() + .is_none_or(|record| !record.driver_operation_pending), + "successful image update must settle the old-understood operation interlock" ); assert_eq!( updated @@ -265,13 +267,28 @@ fn assert_update_completed(original: &proto::Sandbox, updated: &proto::Sandbox) } async fn assert_replay( - client: &mut AuthedGrpcClient, + client: &mut AuthedSandboxUpdatesClient, update: proto::UpdateSandboxRequest, updated: &proto::Sandbox, ) { - // Replay the exact old resource-version request. Sandbox replay returns its - // current state: ordinary watch observations may have advanced metadata and - // status since the original response, without applying the image again. + // Replay restores current resource state, not a captured transient status. + // Use retained driver evidence to prove that no new image operation ran. + let id = &updated.metadata.as_ref().expect("updated metadata").id; + let before = sandbox_resource(id).await; + let evidence = before["metadata"]["annotations"]["openshell.ai/sandbox-image-update"].clone(); + let operation: Value = + serde_json::from_str(evidence.as_str().expect("image operation evidence")) + .expect("parse image operation evidence"); + assert!( + operation["revision"] + .as_u64() + .is_some_and(|revision| revision > 0) + ); + assert!( + operation["operation_id"] + .as_str() + .is_some_and(|id| !id.is_empty()) + ); let replay = client .update_sandbox(rpc(update)) .await @@ -286,18 +303,11 @@ async fn assert_replay( let replayed = replay.into_inner().sandbox.expect("replayed Sandbox"); assert_update_completed(updated, &replayed); assert_eq!(replayed.spec, updated.spec); + let after = sandbox_resource(id).await; + assert_eq!(after["metadata"]["uid"], before["metadata"]["uid"]); assert_eq!( - replayed - .status - .as_ref() - .expect("replayed status") - .image_revision, - updated - .status - .as_ref() - .expect("updated status") - .image_revision, - "replay must not admit another image operation" + after["metadata"]["annotations"]["openshell.ai/sandbox-image-update"], evidence, + "replay must retain the exact driver operation identity and revision" ); assert!( replayed @@ -313,9 +323,7 @@ async fn assert_replay( ); } -#[tokio::test] -async fn image_update_retains_workspace_and_identity() { - let mut client = gateway_client().await; +async fn assert_image_update_supported(client: &mut AuthedGrpcClient) { // This test is Kubernetes-only: missing support is a regression, not a skip. let info = client .get_gateway_info(rpc(proto::GetGatewayInfoRequest {})) @@ -328,6 +336,14 @@ async fn image_update_retains_workspace_and_identity() { .iter() .any(|capability| capability == "openshell.compute.update-sandbox-image") })); +} + +#[tokio::test] +async fn image_update_retains_workspace_and_identity() { + let gateway = gateway_client().await; + let mut client = gateway.raw_grpc(); + let mut image_client = gateway.raw_sandbox_updates(); + assert_image_update_supported(&mut client).await; let mut sandbox = SandboxGuard::create(&["--from", ORIGINAL_IMAGE, "--no-auto-providers"]) .await @@ -363,7 +379,7 @@ async fn image_update_retains_workspace_and_identity() { .resource_version, request_id: String::new(), }; - let error = client + let error = image_client .update_sandbox(rpc(running_update.clone())) .await .expect_err("running update must be rejected"); @@ -385,7 +401,7 @@ async fn image_update_retains_workspace_and_identity() { request_id: request_id(), ..running_update }; - let updated = client + let updated = image_client .update_sandbox(rpc(update.clone())) .await .expect("update stopped sandbox image") @@ -395,7 +411,7 @@ async fn image_update_retains_workspace_and_identity() { assert_update_completed(&original, &updated); assert_resource_retained(&before, &sandbox_resource(id).await, UPDATED_IMAGE); - assert_replay(&mut client, update, &updated).await; + assert_replay(&mut image_client, update, &updated).await; let (output, code) = run_cli(&["sandbox", "start", &sandbox.name]).await; assert_eq!(code, 0, "sandbox start: {output}"); diff --git a/e2e/with-kube-gateway.sh b/e2e/with-kube-gateway.sh index 9ee8eec244..43d7ae5367 100755 --- a/e2e/with-kube-gateway.sh +++ b/e2e/with-kube-gateway.sh @@ -1319,6 +1319,12 @@ helm_extra_args+=(--set supervisor.sandboxRuntime.networkPolicyEnforced=true) if [ "${ADDITIONAL_CA_MODE}" = "1" ]; then helm_extra_args+=(--set "supervisor.network.additionalCaConfigMapName=${ADDITIONAL_CA_SOURCE_CONFIG_MAP}") fi +# This wrapper installs an isolated, uniformly built test gateway, not a +# production rolling upgrade. Explicitly activate the image-update scenario; +# callers can keep activation disabled for negative coverage. +if [ "${OPENSHELL_E2E_KUBE_IMAGE_UPDATES:-1}" = "1" ]; then + helm_extra_args+=(--set 'gatewayConfig.openshell\.gateway.enable_sandbox_image_updates=true') +fi if [ "${OPENSHELL_E2E_EXTERNAL_COMPUTE_DRIVER:-0}" = "1" ]; then if [ "${OPENSHELL_E2E_KUBE_BUILD_IMAGES}" != "1" ]; then echo "ERROR: external Kubernetes driver e2e requires OPENSHELL_E2E_KUBE_BUILD_IMAGES=1." >&2 diff --git a/proto/openshell.proto b/proto/openshell.proto index 71a0d66b69..e5cbd4651d 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -53,16 +53,6 @@ service OpenShell { }; } - // Update only the workload image of a stopped sandbox without deleting its - // identity or retained storage. Requires compute-driver image-update support. - rpc UpdateSandbox(UpdateSandboxRequest) returns (SandboxResponse) { - option (openshell.options.v1.authorization) = { - auth_mode: "bearer" - scope: "sandbox:write" - workspace_role: "user" - }; - } - // Allocate a gateway-owned staging slot for a local rootfs tar archive. // // The gateway creates a request-scoped directory inside the compute driver's @@ -868,6 +858,21 @@ service OpenShell { } } +// Optional sandbox mutations are separate from OpenShell so existing generated +// OpenShell server implementations remain source-compatible. +service SandboxUpdates { + // Update only the workload image of a stopped sandbox without deleting its + // identity or retained storage. Requires compute-driver image-update support + // and explicit gateway activation of sandbox image updates. + rpc UpdateSandbox(UpdateSandboxRequest) returns (SandboxResponse) { + option (openshell.options.v1.authorization) = { + auth_mode: "bearer" + scope: "sandbox:write" + workspace_role: "user" + }; + } +} + // IssueSandboxToken request. Empty body; identity is established by the // authentication credentials carried in the request headers (a projected // Kubernetes ServiceAccount JWT in the K8s driver path). @@ -1252,20 +1257,6 @@ 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; - // Durable pending image change. Start is blocked until the same image update - // is retried successfully. Absence means no image update is pending. - SandboxImageUpdate image_update = 18; - // Monotonic gateway-owned image intent revision. Never reset by restart. - uint64 image_revision = 19; -} - -// Gateway-owned intent retained across interrupted driver operations. -message SandboxImageUpdate { - string operation_id = 1; - string previous_image = 2; - string image = 3; - // Fences delayed operations, including image changes that return to an old tag. - uint64 revision = 4; } // User-facing sandbox condition derived from platform or gateway observations. diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index 2d8ee5ccd2..52474fd366 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -3253,13 +3253,8 @@ 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"` - // Durable pending image change. Start is blocked until the same image update - // is retried successfully. Absence means no image update is pending. - ImageUpdate *SandboxImageUpdate `protobuf:"bytes,18,opt,name=image_update,json=imageUpdate,proto3" json:"image_update,omitempty"` - // Monotonic gateway-owned image intent revision. Never reset by restart. - ImageRevision uint64 `protobuf:"varint,19,opt,name=image_revision,json=imageRevision,proto3" json:"image_revision,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SandboxStatus) Reset() { @@ -3404,90 +3399,6 @@ func (x *SandboxStatus) GetLastTokenGrantFailure() *TokenGrantFailureObservation return nil } -func (x *SandboxStatus) GetImageUpdate() *SandboxImageUpdate { - if x != nil { - return x.ImageUpdate - } - return nil -} - -func (x *SandboxStatus) GetImageRevision() uint64 { - if x != nil { - return x.ImageRevision - } - return 0 -} - -// Gateway-owned intent retained across interrupted driver operations. -type SandboxImageUpdate struct { - state protoimpl.MessageState `protogen:"open.v1"` - OperationId string `protobuf:"bytes,1,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` - PreviousImage string `protobuf:"bytes,2,opt,name=previous_image,json=previousImage,proto3" json:"previous_image,omitempty"` - Image string `protobuf:"bytes,3,opt,name=image,proto3" json:"image,omitempty"` - // Fences delayed operations, including image changes that return to an old tag. - Revision uint64 `protobuf:"varint,4,opt,name=revision,proto3" json:"revision,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *SandboxImageUpdate) Reset() { - *x = SandboxImageUpdate{} - mi := &file_openshell_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SandboxImageUpdate) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SandboxImageUpdate) ProtoMessage() {} - -func (x *SandboxImageUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[30] - 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 SandboxImageUpdate.ProtoReflect.Descriptor instead. -func (*SandboxImageUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{30} -} - -func (x *SandboxImageUpdate) GetOperationId() string { - if x != nil { - return x.OperationId - } - return "" -} - -func (x *SandboxImageUpdate) GetPreviousImage() string { - if x != nil { - return x.PreviousImage - } - return "" -} - -func (x *SandboxImageUpdate) GetImage() string { - if x != nil { - return x.Image - } - return "" -} - -func (x *SandboxImageUpdate) GetRevision() uint64 { - if x != nil { - return x.Revision - } - return 0 -} - // User-facing sandbox condition derived from platform or gateway observations. type SandboxCondition struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -3507,7 +3418,7 @@ type SandboxCondition struct { func (x *SandboxCondition) Reset() { *x = SandboxCondition{} - mi := &file_openshell_proto_msgTypes[31] + mi := &file_openshell_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3519,7 +3430,7 @@ func (x *SandboxCondition) String() string { func (*SandboxCondition) ProtoMessage() {} func (x *SandboxCondition) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[31] + mi := &file_openshell_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3532,7 +3443,7 @@ func (x *SandboxCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxCondition.ProtoReflect.Descriptor instead. func (*SandboxCondition) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{31} + return file_openshell_proto_rawDescGZIP(), []int{30} } func (x *SandboxCondition) GetType() string { @@ -3591,7 +3502,7 @@ type PlatformEvent struct { func (x *PlatformEvent) Reset() { *x = PlatformEvent{} - mi := &file_openshell_proto_msgTypes[32] + mi := &file_openshell_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3603,7 +3514,7 @@ func (x *PlatformEvent) String() string { func (*PlatformEvent) ProtoMessage() {} func (x *PlatformEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[32] + mi := &file_openshell_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3616,7 +3527,7 @@ func (x *PlatformEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use PlatformEvent.ProtoReflect.Descriptor instead. func (*PlatformEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{32} + return file_openshell_proto_rawDescGZIP(), []int{31} } func (x *PlatformEvent) GetEventTime() *timestamppb.Timestamp { @@ -3693,7 +3604,7 @@ type CreateSandboxRequest struct { func (x *CreateSandboxRequest) Reset() { *x = CreateSandboxRequest{} - mi := &file_openshell_proto_msgTypes[33] + mi := &file_openshell_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3705,7 +3616,7 @@ func (x *CreateSandboxRequest) String() string { func (*CreateSandboxRequest) ProtoMessage() {} func (x *CreateSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[33] + mi := &file_openshell_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3718,7 +3629,7 @@ func (x *CreateSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSandboxRequest.ProtoReflect.Descriptor instead. func (*CreateSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{33} + return file_openshell_proto_rawDescGZIP(), []int{32} } func (x *CreateSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3805,7 +3716,7 @@ type UpdateSandboxRequest struct { func (x *UpdateSandboxRequest) Reset() { *x = UpdateSandboxRequest{} - mi := &file_openshell_proto_msgTypes[34] + mi := &file_openshell_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3817,7 +3728,7 @@ func (x *UpdateSandboxRequest) String() string { func (*UpdateSandboxRequest) ProtoMessage() {} func (x *UpdateSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[34] + mi := &file_openshell_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3830,7 +3741,7 @@ func (x *UpdateSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateSandboxRequest.ProtoReflect.Descriptor instead. func (*UpdateSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{34} + return file_openshell_proto_rawDescGZIP(), []int{33} } func (x *UpdateSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3882,7 +3793,7 @@ type CreateSandboxTemplateRequest struct { func (x *CreateSandboxTemplateRequest) Reset() { *x = CreateSandboxTemplateRequest{} - mi := &file_openshell_proto_msgTypes[35] + mi := &file_openshell_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3894,7 +3805,7 @@ func (x *CreateSandboxTemplateRequest) String() string { func (*CreateSandboxTemplateRequest) ProtoMessage() {} func (x *CreateSandboxTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[35] + mi := &file_openshell_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3907,7 +3818,7 @@ func (x *CreateSandboxTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSandboxTemplateRequest.ProtoReflect.Descriptor instead. func (*CreateSandboxTemplateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{35} + return file_openshell_proto_rawDescGZIP(), []int{34} } func (x *CreateSandboxTemplateRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3942,7 +3853,7 @@ type GetSandboxTemplateRequest struct { func (x *GetSandboxTemplateRequest) Reset() { *x = GetSandboxTemplateRequest{} - mi := &file_openshell_proto_msgTypes[36] + mi := &file_openshell_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3954,7 +3865,7 @@ func (x *GetSandboxTemplateRequest) String() string { func (*GetSandboxTemplateRequest) ProtoMessage() {} func (x *GetSandboxTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[36] + mi := &file_openshell_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3967,7 +3878,7 @@ func (x *GetSandboxTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxTemplateRequest.ProtoReflect.Descriptor instead. func (*GetSandboxTemplateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{36} + return file_openshell_proto_rawDescGZIP(), []int{35} } func (x *GetSandboxTemplateRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4002,7 +3913,7 @@ type ListSandboxTemplatesRequest struct { func (x *ListSandboxTemplatesRequest) Reset() { *x = ListSandboxTemplatesRequest{} - mi := &file_openshell_proto_msgTypes[37] + mi := &file_openshell_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4014,7 +3925,7 @@ func (x *ListSandboxTemplatesRequest) String() string { func (*ListSandboxTemplatesRequest) ProtoMessage() {} func (x *ListSandboxTemplatesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[37] + mi := &file_openshell_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4027,7 +3938,7 @@ func (x *ListSandboxTemplatesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxTemplatesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxTemplatesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{37} + return file_openshell_proto_rawDescGZIP(), []int{36} } func (x *ListSandboxTemplatesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4074,7 +3985,7 @@ type DeleteSandboxTemplateRequest struct { func (x *DeleteSandboxTemplateRequest) Reset() { *x = DeleteSandboxTemplateRequest{} - mi := &file_openshell_proto_msgTypes[38] + mi := &file_openshell_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4086,7 +3997,7 @@ func (x *DeleteSandboxTemplateRequest) String() string { func (*DeleteSandboxTemplateRequest) ProtoMessage() {} func (x *DeleteSandboxTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[38] + mi := &file_openshell_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4099,7 +4010,7 @@ func (x *DeleteSandboxTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxTemplateRequest.ProtoReflect.Descriptor instead. func (*DeleteSandboxTemplateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{38} + return file_openshell_proto_rawDescGZIP(), []int{37} } func (x *DeleteSandboxTemplateRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4139,7 +4050,7 @@ type SandboxTemplateResponse struct { func (x *SandboxTemplateResponse) Reset() { *x = SandboxTemplateResponse{} - mi := &file_openshell_proto_msgTypes[39] + mi := &file_openshell_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4151,7 +4062,7 @@ func (x *SandboxTemplateResponse) String() string { func (*SandboxTemplateResponse) ProtoMessage() {} func (x *SandboxTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[39] + mi := &file_openshell_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4164,7 +4075,7 @@ func (x *SandboxTemplateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxTemplateResponse.ProtoReflect.Descriptor instead. func (*SandboxTemplateResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{39} + return file_openshell_proto_rawDescGZIP(), []int{38} } func (x *SandboxTemplateResponse) GetTemplate() *SandboxWorkloadTemplate { @@ -4185,7 +4096,7 @@ type ListSandboxTemplatesResponse struct { func (x *ListSandboxTemplatesResponse) Reset() { *x = ListSandboxTemplatesResponse{} - mi := &file_openshell_proto_msgTypes[40] + mi := &file_openshell_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4197,7 +4108,7 @@ func (x *ListSandboxTemplatesResponse) String() string { func (*ListSandboxTemplatesResponse) ProtoMessage() {} func (x *ListSandboxTemplatesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[40] + mi := &file_openshell_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4210,7 +4121,7 @@ func (x *ListSandboxTemplatesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxTemplatesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxTemplatesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{40} + return file_openshell_proto_rawDescGZIP(), []int{39} } func (x *ListSandboxTemplatesResponse) GetTemplates() []*SandboxWorkloadTemplate { @@ -4236,7 +4147,7 @@ type DeleteSandboxTemplateResponse struct { func (x *DeleteSandboxTemplateResponse) Reset() { *x = DeleteSandboxTemplateResponse{} - mi := &file_openshell_proto_msgTypes[41] + mi := &file_openshell_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4248,7 +4159,7 @@ func (x *DeleteSandboxTemplateResponse) String() string { func (*DeleteSandboxTemplateResponse) ProtoMessage() {} func (x *DeleteSandboxTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[41] + mi := &file_openshell_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4261,7 +4172,7 @@ func (x *DeleteSandboxTemplateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxTemplateResponse.ProtoReflect.Descriptor instead. func (*DeleteSandboxTemplateResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{41} + return file_openshell_proto_rawDescGZIP(), []int{40} } func (x *DeleteSandboxTemplateResponse) GetOutcome() DeletionOutcome { @@ -4288,7 +4199,7 @@ type BeginRootfsTarStagingRequest struct { func (x *BeginRootfsTarStagingRequest) Reset() { *x = BeginRootfsTarStagingRequest{} - mi := &file_openshell_proto_msgTypes[42] + mi := &file_openshell_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4300,7 +4211,7 @@ func (x *BeginRootfsTarStagingRequest) String() string { func (*BeginRootfsTarStagingRequest) ProtoMessage() {} func (x *BeginRootfsTarStagingRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[42] + mi := &file_openshell_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4313,7 +4224,7 @@ func (x *BeginRootfsTarStagingRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BeginRootfsTarStagingRequest.ProtoReflect.Descriptor instead. func (*BeginRootfsTarStagingRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{42} + return file_openshell_proto_rawDescGZIP(), []int{41} } func (x *BeginRootfsTarStagingRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4356,7 +4267,7 @@ type BeginRootfsTarStagingResponse struct { func (x *BeginRootfsTarStagingResponse) Reset() { *x = BeginRootfsTarStagingResponse{} - mi := &file_openshell_proto_msgTypes[43] + mi := &file_openshell_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4368,7 +4279,7 @@ func (x *BeginRootfsTarStagingResponse) String() string { func (*BeginRootfsTarStagingResponse) ProtoMessage() {} func (x *BeginRootfsTarStagingResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[43] + mi := &file_openshell_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4381,7 +4292,7 @@ func (x *BeginRootfsTarStagingResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BeginRootfsTarStagingResponse.ProtoReflect.Descriptor instead. func (*BeginRootfsTarStagingResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{43} + return file_openshell_proto_rawDescGZIP(), []int{42} } func (x *BeginRootfsTarStagingResponse) GetStagingToken() string { @@ -4424,7 +4335,7 @@ type GetSandboxRequest struct { func (x *GetSandboxRequest) Reset() { *x = GetSandboxRequest{} - mi := &file_openshell_proto_msgTypes[44] + mi := &file_openshell_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4436,7 +4347,7 @@ func (x *GetSandboxRequest) String() string { func (*GetSandboxRequest) ProtoMessage() {} func (x *GetSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[44] + mi := &file_openshell_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4449,7 +4360,7 @@ func (x *GetSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxRequest.ProtoReflect.Descriptor instead. func (*GetSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{44} + return file_openshell_proto_rawDescGZIP(), []int{43} } func (x *GetSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4485,7 +4396,7 @@ type ListSandboxesRequest struct { func (x *ListSandboxesRequest) Reset() { *x = ListSandboxesRequest{} - mi := &file_openshell_proto_msgTypes[45] + mi := &file_openshell_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4497,7 +4408,7 @@ func (x *ListSandboxesRequest) String() string { func (*ListSandboxesRequest) ProtoMessage() {} func (x *ListSandboxesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[45] + mi := &file_openshell_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4510,7 +4421,7 @@ func (x *ListSandboxesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{45} + return file_openshell_proto_rawDescGZIP(), []int{44} } func (x *ListSandboxesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4559,7 +4470,7 @@ type ListSandboxProvidersRequest struct { func (x *ListSandboxProvidersRequest) Reset() { *x = ListSandboxProvidersRequest{} - mi := &file_openshell_proto_msgTypes[46] + mi := &file_openshell_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4571,7 +4482,7 @@ func (x *ListSandboxProvidersRequest) String() string { func (*ListSandboxProvidersRequest) ProtoMessage() {} func (x *ListSandboxProvidersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[46] + mi := &file_openshell_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4584,7 +4495,7 @@ func (x *ListSandboxProvidersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxProvidersRequest.ProtoReflect.Descriptor instead. func (*ListSandboxProvidersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{46} + return file_openshell_proto_rawDescGZIP(), []int{45} } func (x *ListSandboxProvidersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4637,7 +4548,7 @@ type AttachSandboxProviderRequest struct { func (x *AttachSandboxProviderRequest) Reset() { *x = AttachSandboxProviderRequest{} - mi := &file_openshell_proto_msgTypes[47] + mi := &file_openshell_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4649,7 +4560,7 @@ func (x *AttachSandboxProviderRequest) String() string { func (*AttachSandboxProviderRequest) ProtoMessage() {} func (x *AttachSandboxProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[47] + mi := &file_openshell_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4662,7 +4573,7 @@ func (x *AttachSandboxProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachSandboxProviderRequest.ProtoReflect.Descriptor instead. func (*AttachSandboxProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{47} + return file_openshell_proto_rawDescGZIP(), []int{46} } func (x *AttachSandboxProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4722,7 +4633,7 @@ type DetachSandboxProviderRequest struct { func (x *DetachSandboxProviderRequest) Reset() { *x = DetachSandboxProviderRequest{} - mi := &file_openshell_proto_msgTypes[48] + mi := &file_openshell_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4734,7 +4645,7 @@ func (x *DetachSandboxProviderRequest) String() string { func (*DetachSandboxProviderRequest) ProtoMessage() {} func (x *DetachSandboxProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[48] + mi := &file_openshell_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4747,7 +4658,7 @@ func (x *DetachSandboxProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachSandboxProviderRequest.ProtoReflect.Descriptor instead. func (*DetachSandboxProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{48} + return file_openshell_proto_rawDescGZIP(), []int{47} } func (x *DetachSandboxProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4804,7 +4715,7 @@ type DeleteSandboxRequest struct { func (x *DeleteSandboxRequest) Reset() { *x = DeleteSandboxRequest{} - mi := &file_openshell_proto_msgTypes[49] + mi := &file_openshell_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4816,7 +4727,7 @@ func (x *DeleteSandboxRequest) String() string { func (*DeleteSandboxRequest) ProtoMessage() {} func (x *DeleteSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[49] + mi := &file_openshell_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4829,7 +4740,7 @@ func (x *DeleteSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxRequest.ProtoReflect.Descriptor instead. func (*DeleteSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{49} + return file_openshell_proto_rawDescGZIP(), []int{48} } func (x *DeleteSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4875,7 +4786,7 @@ type StopSandboxRequest struct { func (x *StopSandboxRequest) Reset() { *x = StopSandboxRequest{} - mi := &file_openshell_proto_msgTypes[50] + mi := &file_openshell_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4887,7 +4798,7 @@ func (x *StopSandboxRequest) String() string { func (*StopSandboxRequest) ProtoMessage() {} func (x *StopSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[50] + mi := &file_openshell_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4900,7 +4811,7 @@ func (x *StopSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StopSandboxRequest.ProtoReflect.Descriptor instead. func (*StopSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{50} + return file_openshell_proto_rawDescGZIP(), []int{49} } func (x *StopSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4939,7 +4850,7 @@ type StartSandboxRequest struct { func (x *StartSandboxRequest) Reset() { *x = StartSandboxRequest{} - mi := &file_openshell_proto_msgTypes[51] + mi := &file_openshell_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4951,7 +4862,7 @@ func (x *StartSandboxRequest) String() string { func (*StartSandboxRequest) ProtoMessage() {} func (x *StartSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[51] + mi := &file_openshell_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4964,7 +4875,7 @@ func (x *StartSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartSandboxRequest.ProtoReflect.Descriptor instead. func (*StartSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{51} + return file_openshell_proto_rawDescGZIP(), []int{50} } func (x *StartSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -5000,7 +4911,7 @@ type SuspendSandboxRequest struct { func (x *SuspendSandboxRequest) Reset() { *x = SuspendSandboxRequest{} - mi := &file_openshell_proto_msgTypes[52] + mi := &file_openshell_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5012,7 +4923,7 @@ func (x *SuspendSandboxRequest) String() string { func (*SuspendSandboxRequest) ProtoMessage() {} func (x *SuspendSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[52] + mi := &file_openshell_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5025,7 +4936,7 @@ func (x *SuspendSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendSandboxRequest.ProtoReflect.Descriptor instead. func (*SuspendSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{52} + return file_openshell_proto_rawDescGZIP(), []int{51} } func (x *SuspendSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -5057,7 +4968,7 @@ type ResumeSandboxRequest struct { func (x *ResumeSandboxRequest) Reset() { *x = ResumeSandboxRequest{} - mi := &file_openshell_proto_msgTypes[53] + mi := &file_openshell_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5069,7 +4980,7 @@ func (x *ResumeSandboxRequest) String() string { func (*ResumeSandboxRequest) ProtoMessage() {} func (x *ResumeSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[53] + mi := &file_openshell_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5082,7 +4993,7 @@ func (x *ResumeSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeSandboxRequest.ProtoReflect.Descriptor instead. func (*ResumeSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{53} + return file_openshell_proto_rawDescGZIP(), []int{52} } func (x *ResumeSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -5119,7 +5030,7 @@ type SandboxResponse struct { func (x *SandboxResponse) Reset() { *x = SandboxResponse{} - mi := &file_openshell_proto_msgTypes[54] + mi := &file_openshell_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5131,7 +5042,7 @@ func (x *SandboxResponse) String() string { func (*SandboxResponse) ProtoMessage() {} func (x *SandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[54] + mi := &file_openshell_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5144,7 +5055,7 @@ func (x *SandboxResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxResponse.ProtoReflect.Descriptor instead. func (*SandboxResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{54} + return file_openshell_proto_rawDescGZIP(), []int{53} } func (x *SandboxResponse) GetSandbox() *Sandbox { @@ -5173,7 +5084,7 @@ type ListSandboxesResponse struct { func (x *ListSandboxesResponse) Reset() { *x = ListSandboxesResponse{} - mi := &file_openshell_proto_msgTypes[55] + mi := &file_openshell_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5185,7 +5096,7 @@ func (x *ListSandboxesResponse) String() string { func (*ListSandboxesResponse) ProtoMessage() {} func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[55] + mi := &file_openshell_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5198,7 +5109,7 @@ func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{55} + return file_openshell_proto_rawDescGZIP(), []int{54} } func (x *ListSandboxesResponse) GetSandboxes() []*Sandbox { @@ -5227,7 +5138,7 @@ type ListSandboxProvidersResponse struct { func (x *ListSandboxProvidersResponse) Reset() { *x = ListSandboxProvidersResponse{} - mi := &file_openshell_proto_msgTypes[56] + mi := &file_openshell_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5239,7 +5150,7 @@ func (x *ListSandboxProvidersResponse) String() string { func (*ListSandboxProvidersResponse) ProtoMessage() {} func (x *ListSandboxProvidersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[56] + mi := &file_openshell_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5252,7 +5163,7 @@ func (x *ListSandboxProvidersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxProvidersResponse.ProtoReflect.Descriptor instead. func (*ListSandboxProvidersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{56} + return file_openshell_proto_rawDescGZIP(), []int{55} } func (x *ListSandboxProvidersResponse) GetProviders() []*datamodelv1.Provider { @@ -5283,7 +5194,7 @@ type AttachSandboxProviderResponse struct { func (x *AttachSandboxProviderResponse) Reset() { *x = AttachSandboxProviderResponse{} - mi := &file_openshell_proto_msgTypes[57] + mi := &file_openshell_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5295,7 +5206,7 @@ func (x *AttachSandboxProviderResponse) String() string { func (*AttachSandboxProviderResponse) ProtoMessage() {} func (x *AttachSandboxProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[57] + mi := &file_openshell_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5308,7 +5219,7 @@ func (x *AttachSandboxProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachSandboxProviderResponse.ProtoReflect.Descriptor instead. func (*AttachSandboxProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{57} + return file_openshell_proto_rawDescGZIP(), []int{56} } func (x *AttachSandboxProviderResponse) GetSandbox() *Sandbox { @@ -5346,7 +5257,7 @@ type DetachSandboxProviderResponse struct { func (x *DetachSandboxProviderResponse) Reset() { *x = DetachSandboxProviderResponse{} - mi := &file_openshell_proto_msgTypes[58] + mi := &file_openshell_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5358,7 +5269,7 @@ func (x *DetachSandboxProviderResponse) String() string { func (*DetachSandboxProviderResponse) ProtoMessage() {} func (x *DetachSandboxProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[58] + mi := &file_openshell_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5371,7 +5282,7 @@ func (x *DetachSandboxProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachSandboxProviderResponse.ProtoReflect.Descriptor instead. func (*DetachSandboxProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{58} + return file_openshell_proto_rawDescGZIP(), []int{57} } func (x *DetachSandboxProviderResponse) GetSandbox() *Sandbox { @@ -5413,7 +5324,7 @@ type ProviderDesiredIdentity struct { func (x *ProviderDesiredIdentity) Reset() { *x = ProviderDesiredIdentity{} - mi := &file_openshell_proto_msgTypes[59] + mi := &file_openshell_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5425,7 +5336,7 @@ func (x *ProviderDesiredIdentity) String() string { func (*ProviderDesiredIdentity) ProtoMessage() {} func (x *ProviderDesiredIdentity) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[59] + mi := &file_openshell_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5438,7 +5349,7 @@ func (x *ProviderDesiredIdentity) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderDesiredIdentity.ProtoReflect.Descriptor instead. func (*ProviderDesiredIdentity) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{59} + return file_openshell_proto_rawDescGZIP(), []int{58} } func (x *ProviderDesiredIdentity) GetSandboxId() string { @@ -5513,7 +5424,7 @@ type ConfigSnapshotRevision struct { func (x *ConfigSnapshotRevision) Reset() { *x = ConfigSnapshotRevision{} - mi := &file_openshell_proto_msgTypes[60] + mi := &file_openshell_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5525,7 +5436,7 @@ func (x *ConfigSnapshotRevision) String() string { func (*ConfigSnapshotRevision) ProtoMessage() {} func (x *ConfigSnapshotRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[60] + mi := &file_openshell_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5538,7 +5449,7 @@ func (x *ConfigSnapshotRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigSnapshotRevision.ProtoReflect.Descriptor instead. func (*ConfigSnapshotRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{60} + return file_openshell_proto_rawDescGZIP(), []int{59} } func (x *ConfigSnapshotRevision) GetComponent() isConfigSnapshotRevision_Component { @@ -5615,7 +5526,7 @@ type SandboxConfigRevision struct { func (x *SandboxConfigRevision) Reset() { *x = SandboxConfigRevision{} - mi := &file_openshell_proto_msgTypes[61] + mi := &file_openshell_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5627,7 +5538,7 @@ func (x *SandboxConfigRevision) String() string { func (*SandboxConfigRevision) ProtoMessage() {} func (x *SandboxConfigRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[61] + mi := &file_openshell_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5640,7 +5551,7 @@ func (x *SandboxConfigRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfigRevision.ProtoReflect.Descriptor instead. func (*SandboxConfigRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{61} + return file_openshell_proto_rawDescGZIP(), []int{60} } func (x *SandboxConfigRevision) GetConfigRevision() uint64 { @@ -5699,7 +5610,7 @@ type ConfigUpdateOperation struct { func (x *ConfigUpdateOperation) Reset() { *x = ConfigUpdateOperation{} - mi := &file_openshell_proto_msgTypes[62] + mi := &file_openshell_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5711,7 +5622,7 @@ func (x *ConfigUpdateOperation) String() string { func (*ConfigUpdateOperation) ProtoMessage() {} func (x *ConfigUpdateOperation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[62] + mi := &file_openshell_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5724,7 +5635,7 @@ func (x *ConfigUpdateOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdateOperation.ProtoReflect.Descriptor instead. func (*ConfigUpdateOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{62} + return file_openshell_proto_rawDescGZIP(), []int{61} } func (x *ConfigUpdateOperation) GetOperationId() string { @@ -5814,7 +5725,7 @@ type ProviderMutationReceipt struct { func (x *ProviderMutationReceipt) Reset() { *x = ProviderMutationReceipt{} - mi := &file_openshell_proto_msgTypes[63] + mi := &file_openshell_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5826,7 +5737,7 @@ func (x *ProviderMutationReceipt) String() string { func (*ProviderMutationReceipt) ProtoMessage() {} func (x *ProviderMutationReceipt) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[63] + mi := &file_openshell_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5839,7 +5750,7 @@ func (x *ProviderMutationReceipt) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderMutationReceipt.ProtoReflect.Descriptor instead. func (*ProviderMutationReceipt) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{63} + return file_openshell_proto_rawDescGZIP(), []int{62} } func (x *ProviderMutationReceipt) GetReceiptId() string { @@ -5915,7 +5826,7 @@ type ProviderReadinessObservation struct { func (x *ProviderReadinessObservation) Reset() { *x = ProviderReadinessObservation{} - mi := &file_openshell_proto_msgTypes[64] + mi := &file_openshell_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5927,7 +5838,7 @@ func (x *ProviderReadinessObservation) String() string { func (*ProviderReadinessObservation) ProtoMessage() {} func (x *ProviderReadinessObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[64] + mi := &file_openshell_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5940,7 +5851,7 @@ func (x *ProviderReadinessObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderReadinessObservation.ProtoReflect.Descriptor instead. func (*ProviderReadinessObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{64} + return file_openshell_proto_rawDescGZIP(), []int{63} } func (x *ProviderReadinessObservation) GetSessionId() string { @@ -6039,7 +5950,7 @@ type ProviderReadinessStatus struct { func (x *ProviderReadinessStatus) Reset() { *x = ProviderReadinessStatus{} - mi := &file_openshell_proto_msgTypes[65] + mi := &file_openshell_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6051,7 +5962,7 @@ func (x *ProviderReadinessStatus) String() string { func (*ProviderReadinessStatus) ProtoMessage() {} func (x *ProviderReadinessStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[65] + mi := &file_openshell_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6064,7 +5975,7 @@ func (x *ProviderReadinessStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderReadinessStatus.ProtoReflect.Descriptor instead. func (*ProviderReadinessStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{65} + return file_openshell_proto_rawDescGZIP(), []int{64} } func (x *ProviderReadinessStatus) GetReceipt() *ProviderMutationReceipt { @@ -6138,7 +6049,7 @@ type GetSandboxProviderStatusRequest struct { func (x *GetSandboxProviderStatusRequest) Reset() { *x = GetSandboxProviderStatusRequest{} - mi := &file_openshell_proto_msgTypes[66] + mi := &file_openshell_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6150,7 +6061,7 @@ func (x *GetSandboxProviderStatusRequest) String() string { func (*GetSandboxProviderStatusRequest) ProtoMessage() {} func (x *GetSandboxProviderStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[66] + mi := &file_openshell_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6163,7 +6074,7 @@ func (x *GetSandboxProviderStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxProviderStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxProviderStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{66} + return file_openshell_proto_rawDescGZIP(), []int{65} } func (x *GetSandboxProviderStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6203,7 +6114,7 @@ type GetSandboxProviderStatusResponse struct { func (x *GetSandboxProviderStatusResponse) Reset() { *x = GetSandboxProviderStatusResponse{} - mi := &file_openshell_proto_msgTypes[67] + mi := &file_openshell_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6215,7 +6126,7 @@ func (x *GetSandboxProviderStatusResponse) String() string { func (*GetSandboxProviderStatusResponse) ProtoMessage() {} func (x *GetSandboxProviderStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[67] + mi := &file_openshell_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6228,7 +6139,7 @@ func (x *GetSandboxProviderStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxProviderStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxProviderStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{67} + return file_openshell_proto_rawDescGZIP(), []int{66} } func (x *GetSandboxProviderStatusResponse) GetStatus() *ProviderReadinessStatus { @@ -6250,7 +6161,7 @@ type ReportProviderReadinessRequest struct { func (x *ReportProviderReadinessRequest) Reset() { *x = ReportProviderReadinessRequest{} - mi := &file_openshell_proto_msgTypes[68] + mi := &file_openshell_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6262,7 +6173,7 @@ func (x *ReportProviderReadinessRequest) String() string { func (*ReportProviderReadinessRequest) ProtoMessage() {} func (x *ReportProviderReadinessRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[68] + mi := &file_openshell_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6275,7 +6186,7 @@ func (x *ReportProviderReadinessRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportProviderReadinessRequest.ProtoReflect.Descriptor instead. func (*ReportProviderReadinessRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{68} + return file_openshell_proto_rawDescGZIP(), []int{67} } func (x *ReportProviderReadinessRequest) GetSandboxId() string { @@ -6305,7 +6216,7 @@ type ReportProviderReadinessResponse struct { func (x *ReportProviderReadinessResponse) Reset() { *x = ReportProviderReadinessResponse{} - mi := &file_openshell_proto_msgTypes[69] + mi := &file_openshell_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6317,7 +6228,7 @@ func (x *ReportProviderReadinessResponse) String() string { func (*ReportProviderReadinessResponse) ProtoMessage() {} func (x *ReportProviderReadinessResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[69] + mi := &file_openshell_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6330,7 +6241,7 @@ func (x *ReportProviderReadinessResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportProviderReadinessResponse.ProtoReflect.Descriptor instead. func (*ReportProviderReadinessResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{69} + return file_openshell_proto_rawDescGZIP(), []int{68} } func (x *ReportProviderReadinessResponse) GetAcceptedSequence() uint64 { @@ -6367,7 +6278,7 @@ type DeleteSandboxResponse struct { func (x *DeleteSandboxResponse) Reset() { *x = DeleteSandboxResponse{} - mi := &file_openshell_proto_msgTypes[70] + mi := &file_openshell_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6379,7 +6290,7 @@ func (x *DeleteSandboxResponse) String() string { func (*DeleteSandboxResponse) ProtoMessage() {} func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[70] + mi := &file_openshell_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6392,7 +6303,7 @@ func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxResponse.ProtoReflect.Descriptor instead. func (*DeleteSandboxResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{70} + return file_openshell_proto_rawDescGZIP(), []int{69} } func (x *DeleteSandboxResponse) GetOutcome() DeletionOutcome { @@ -6421,7 +6332,7 @@ type CreateSshSessionRequest struct { func (x *CreateSshSessionRequest) Reset() { *x = CreateSshSessionRequest{} - mi := &file_openshell_proto_msgTypes[71] + mi := &file_openshell_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6433,7 +6344,7 @@ func (x *CreateSshSessionRequest) String() string { func (*CreateSshSessionRequest) ProtoMessage() {} func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[71] + mi := &file_openshell_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6446,7 +6357,7 @@ func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSshSessionRequest.ProtoReflect.Descriptor instead. func (*CreateSshSessionRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{71} + return file_openshell_proto_rawDescGZIP(), []int{70} } func (x *CreateSshSessionRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6497,7 +6408,7 @@ type CreateSshSessionResponse struct { func (x *CreateSshSessionResponse) Reset() { *x = CreateSshSessionResponse{} - mi := &file_openshell_proto_msgTypes[72] + mi := &file_openshell_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6509,7 +6420,7 @@ func (x *CreateSshSessionResponse) String() string { func (*CreateSshSessionResponse) ProtoMessage() {} func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[72] + mi := &file_openshell_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6522,7 +6433,7 @@ func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSshSessionResponse.ProtoReflect.Descriptor instead. func (*CreateSshSessionResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{72} + return file_openshell_proto_rawDescGZIP(), []int{71} } func (x *CreateSshSessionResponse) GetSandboxId() string { @@ -6597,7 +6508,7 @@ type ExposeServiceRequest struct { func (x *ExposeServiceRequest) Reset() { *x = ExposeServiceRequest{} - mi := &file_openshell_proto_msgTypes[73] + mi := &file_openshell_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6609,7 +6520,7 @@ func (x *ExposeServiceRequest) String() string { func (*ExposeServiceRequest) ProtoMessage() {} func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[73] + mi := &file_openshell_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6622,7 +6533,7 @@ func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExposeServiceRequest.ProtoReflect.Descriptor instead. func (*ExposeServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{73} + return file_openshell_proto_rawDescGZIP(), []int{72} } func (x *ExposeServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6688,7 +6599,7 @@ type GetServiceRequest struct { func (x *GetServiceRequest) Reset() { *x = GetServiceRequest{} - mi := &file_openshell_proto_msgTypes[74] + mi := &file_openshell_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6700,7 +6611,7 @@ func (x *GetServiceRequest) String() string { func (*GetServiceRequest) ProtoMessage() {} func (x *GetServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[74] + mi := &file_openshell_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6713,7 +6624,7 @@ func (x *GetServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetServiceRequest.ProtoReflect.Descriptor instead. func (*GetServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{74} + return file_openshell_proto_rawDescGZIP(), []int{73} } func (x *GetServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6756,7 +6667,7 @@ type ListServicesRequest struct { func (x *ListServicesRequest) Reset() { *x = ListServicesRequest{} - mi := &file_openshell_proto_msgTypes[75] + mi := &file_openshell_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6768,7 +6679,7 @@ func (x *ListServicesRequest) String() string { func (*ListServicesRequest) ProtoMessage() {} func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[75] + mi := &file_openshell_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6781,7 +6692,7 @@ func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesRequest.ProtoReflect.Descriptor instead. func (*ListServicesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{75} + return file_openshell_proto_rawDescGZIP(), []int{74} } func (x *ListServicesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6824,7 +6735,7 @@ type ListServicesResponse struct { func (x *ListServicesResponse) Reset() { *x = ListServicesResponse{} - mi := &file_openshell_proto_msgTypes[76] + mi := &file_openshell_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6836,7 +6747,7 @@ func (x *ListServicesResponse) String() string { func (*ListServicesResponse) ProtoMessage() {} func (x *ListServicesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[76] + mi := &file_openshell_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6849,7 +6760,7 @@ func (x *ListServicesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesResponse.ProtoReflect.Descriptor instead. func (*ListServicesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{76} + return file_openshell_proto_rawDescGZIP(), []int{75} } func (x *ListServicesResponse) GetServices() []*ServiceEndpointResponse { @@ -6884,7 +6795,7 @@ type DeleteServiceRequest struct { func (x *DeleteServiceRequest) Reset() { *x = DeleteServiceRequest{} - mi := &file_openshell_proto_msgTypes[77] + mi := &file_openshell_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6896,7 +6807,7 @@ func (x *DeleteServiceRequest) String() string { func (*DeleteServiceRequest) ProtoMessage() {} func (x *DeleteServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[77] + mi := &file_openshell_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6909,7 +6820,7 @@ func (x *DeleteServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteServiceRequest.ProtoReflect.Descriptor instead. func (*DeleteServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{77} + return file_openshell_proto_rawDescGZIP(), []int{76} } func (x *DeleteServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6957,7 +6868,7 @@ type DeleteServiceResponse struct { func (x *DeleteServiceResponse) Reset() { *x = DeleteServiceResponse{} - mi := &file_openshell_proto_msgTypes[78] + mi := &file_openshell_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6969,7 +6880,7 @@ func (x *DeleteServiceResponse) String() string { func (*DeleteServiceResponse) ProtoMessage() {} func (x *DeleteServiceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[78] + mi := &file_openshell_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6982,7 +6893,7 @@ func (x *DeleteServiceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteServiceResponse.ProtoReflect.Descriptor instead. func (*DeleteServiceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{78} + return file_openshell_proto_rawDescGZIP(), []int{77} } func (x *DeleteServiceResponse) GetOutcome() DeletionOutcome { @@ -7015,7 +6926,7 @@ type ServiceEndpoint struct { func (x *ServiceEndpoint) Reset() { *x = ServiceEndpoint{} - mi := &file_openshell_proto_msgTypes[79] + mi := &file_openshell_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7027,7 +6938,7 @@ func (x *ServiceEndpoint) String() string { func (*ServiceEndpoint) ProtoMessage() {} func (x *ServiceEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[79] + mi := &file_openshell_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7040,7 +6951,7 @@ func (x *ServiceEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceEndpoint.ProtoReflect.Descriptor instead. func (*ServiceEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{79} + return file_openshell_proto_rawDescGZIP(), []int{78} } func (x *ServiceEndpoint) GetMetadata() *datamodelv1.ObjectMeta { @@ -7103,7 +7014,7 @@ type ServiceEndpointResponse struct { func (x *ServiceEndpointResponse) Reset() { *x = ServiceEndpointResponse{} - mi := &file_openshell_proto_msgTypes[80] + mi := &file_openshell_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7115,7 +7026,7 @@ func (x *ServiceEndpointResponse) String() string { func (*ServiceEndpointResponse) ProtoMessage() {} func (x *ServiceEndpointResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[80] + mi := &file_openshell_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7128,7 +7039,7 @@ func (x *ServiceEndpointResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceEndpointResponse.ProtoReflect.Descriptor instead. func (*ServiceEndpointResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{80} + return file_openshell_proto_rawDescGZIP(), []int{79} } func (x *ServiceEndpointResponse) GetEndpoint() *ServiceEndpoint { @@ -7159,7 +7070,7 @@ type RevokeSshSessionRequest struct { func (x *RevokeSshSessionRequest) Reset() { *x = RevokeSshSessionRequest{} - mi := &file_openshell_proto_msgTypes[81] + mi := &file_openshell_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7171,7 +7082,7 @@ func (x *RevokeSshSessionRequest) String() string { func (*RevokeSshSessionRequest) ProtoMessage() {} func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[81] + mi := &file_openshell_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7184,7 +7095,7 @@ func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RevokeSshSessionRequest.ProtoReflect.Descriptor instead. func (*RevokeSshSessionRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{81} + return file_openshell_proto_rawDescGZIP(), []int{80} } func (x *RevokeSshSessionRequest) GetToken() string { @@ -7211,7 +7122,7 @@ type RevokeSshSessionResponse struct { func (x *RevokeSshSessionResponse) Reset() { *x = RevokeSshSessionResponse{} - mi := &file_openshell_proto_msgTypes[82] + mi := &file_openshell_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7223,7 +7134,7 @@ func (x *RevokeSshSessionResponse) String() string { func (*RevokeSshSessionResponse) ProtoMessage() {} func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[82] + mi := &file_openshell_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7236,7 +7147,7 @@ func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RevokeSshSessionResponse.ProtoReflect.Descriptor instead. func (*RevokeSshSessionResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{82} + return file_openshell_proto_rawDescGZIP(), []int{81} } func (x *RevokeSshSessionResponse) GetOutcome() DeletionOutcome { @@ -7286,7 +7197,7 @@ type ExecSandboxRequest struct { func (x *ExecSandboxRequest) Reset() { *x = ExecSandboxRequest{} - mi := &file_openshell_proto_msgTypes[83] + mi := &file_openshell_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7298,7 +7209,7 @@ func (x *ExecSandboxRequest) String() string { func (*ExecSandboxRequest) ProtoMessage() {} func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[83] + mi := &file_openshell_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7311,7 +7222,7 @@ func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxRequest.ProtoReflect.Descriptor instead. func (*ExecSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{83} + return file_openshell_proto_rawDescGZIP(), []int{82} } func (x *ExecSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -7408,7 +7319,7 @@ type ExecSandboxStdout struct { func (x *ExecSandboxStdout) Reset() { *x = ExecSandboxStdout{} - mi := &file_openshell_proto_msgTypes[84] + mi := &file_openshell_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7420,7 +7331,7 @@ func (x *ExecSandboxStdout) String() string { func (*ExecSandboxStdout) ProtoMessage() {} func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[84] + mi := &file_openshell_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7433,7 +7344,7 @@ func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxStdout.ProtoReflect.Descriptor instead. func (*ExecSandboxStdout) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{84} + return file_openshell_proto_rawDescGZIP(), []int{83} } func (x *ExecSandboxStdout) GetData() []byte { @@ -7453,7 +7364,7 @@ type ExecSandboxStderr struct { func (x *ExecSandboxStderr) Reset() { *x = ExecSandboxStderr{} - mi := &file_openshell_proto_msgTypes[85] + mi := &file_openshell_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7465,7 +7376,7 @@ func (x *ExecSandboxStderr) String() string { func (*ExecSandboxStderr) ProtoMessage() {} func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[85] + mi := &file_openshell_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7478,7 +7389,7 @@ func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxStderr.ProtoReflect.Descriptor instead. func (*ExecSandboxStderr) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{85} + return file_openshell_proto_rawDescGZIP(), []int{84} } func (x *ExecSandboxStderr) GetData() []byte { @@ -7498,7 +7409,7 @@ type ExecSandboxExit struct { func (x *ExecSandboxExit) Reset() { *x = ExecSandboxExit{} - mi := &file_openshell_proto_msgTypes[86] + mi := &file_openshell_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7510,7 +7421,7 @@ func (x *ExecSandboxExit) String() string { func (*ExecSandboxExit) ProtoMessage() {} func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[86] + mi := &file_openshell_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7523,7 +7434,7 @@ func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxExit.ProtoReflect.Descriptor instead. func (*ExecSandboxExit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{86} + return file_openshell_proto_rawDescGZIP(), []int{85} } func (x *ExecSandboxExit) GetExitCode() int32 { @@ -7548,7 +7459,7 @@ type ExecSandboxEvent struct { func (x *ExecSandboxEvent) Reset() { *x = ExecSandboxEvent{} - mi := &file_openshell_proto_msgTypes[87] + mi := &file_openshell_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7560,7 +7471,7 @@ func (x *ExecSandboxEvent) String() string { func (*ExecSandboxEvent) ProtoMessage() {} func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[87] + mi := &file_openshell_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7573,7 +7484,7 @@ func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxEvent.ProtoReflect.Descriptor instead. func (*ExecSandboxEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{87} + return file_openshell_proto_rawDescGZIP(), []int{86} } func (x *ExecSandboxEvent) GetPayload() isExecSandboxEvent_Payload { @@ -7655,7 +7566,7 @@ type TcpForwardInit struct { func (x *TcpForwardInit) Reset() { *x = TcpForwardInit{} - mi := &file_openshell_proto_msgTypes[88] + mi := &file_openshell_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7667,7 +7578,7 @@ func (x *TcpForwardInit) String() string { func (*TcpForwardInit) ProtoMessage() {} func (x *TcpForwardInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[88] + mi := &file_openshell_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7680,7 +7591,7 @@ func (x *TcpForwardInit) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpForwardInit.ProtoReflect.Descriptor instead. func (*TcpForwardInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{88} + return file_openshell_proto_rawDescGZIP(), []int{87} } func (x *TcpForwardInit) GetSandbox() string { @@ -7766,7 +7677,7 @@ type TcpForwardFrame struct { func (x *TcpForwardFrame) Reset() { *x = TcpForwardFrame{} - mi := &file_openshell_proto_msgTypes[89] + mi := &file_openshell_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7778,7 +7689,7 @@ func (x *TcpForwardFrame) String() string { func (*TcpForwardFrame) ProtoMessage() {} func (x *TcpForwardFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[89] + mi := &file_openshell_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7791,7 +7702,7 @@ func (x *TcpForwardFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpForwardFrame.ProtoReflect.Descriptor instead. func (*TcpForwardFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{89} + return file_openshell_proto_rawDescGZIP(), []int{88} } func (x *TcpForwardFrame) GetPayload() isTcpForwardFrame_Payload { @@ -7850,7 +7761,7 @@ type ExecSandboxInput struct { func (x *ExecSandboxInput) Reset() { *x = ExecSandboxInput{} - mi := &file_openshell_proto_msgTypes[90] + mi := &file_openshell_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7862,7 +7773,7 @@ func (x *ExecSandboxInput) String() string { func (*ExecSandboxInput) ProtoMessage() {} func (x *ExecSandboxInput) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[90] + mi := &file_openshell_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7875,7 +7786,7 @@ func (x *ExecSandboxInput) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxInput.ProtoReflect.Descriptor instead. func (*ExecSandboxInput) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{90} + return file_openshell_proto_rawDescGZIP(), []int{89} } func (x *ExecSandboxInput) GetPayload() isExecSandboxInput_Payload { @@ -7948,7 +7859,7 @@ type ExecSandboxWindowResize struct { func (x *ExecSandboxWindowResize) Reset() { *x = ExecSandboxWindowResize{} - mi := &file_openshell_proto_msgTypes[91] + mi := &file_openshell_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7960,7 +7871,7 @@ func (x *ExecSandboxWindowResize) String() string { func (*ExecSandboxWindowResize) ProtoMessage() {} func (x *ExecSandboxWindowResize) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[91] + mi := &file_openshell_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7973,7 +7884,7 @@ func (x *ExecSandboxWindowResize) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxWindowResize.ProtoReflect.Descriptor instead. func (*ExecSandboxWindowResize) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{91} + return file_openshell_proto_rawDescGZIP(), []int{90} } func (x *ExecSandboxWindowResize) GetCols() uint32 { @@ -8009,7 +7920,7 @@ type SshSession struct { func (x *SshSession) Reset() { *x = SshSession{} - mi := &file_openshell_proto_msgTypes[92] + mi := &file_openshell_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8021,7 +7932,7 @@ func (x *SshSession) String() string { func (*SshSession) ProtoMessage() {} func (x *SshSession) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[92] + mi := &file_openshell_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8034,7 +7945,7 @@ func (x *SshSession) ProtoReflect() protoreflect.Message { // Deprecated: Use SshSession.ProtoReflect.Descriptor instead. func (*SshSession) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{92} + return file_openshell_proto_rawDescGZIP(), []int{91} } func (x *SshSession) GetMetadata() *datamodelv1.ObjectMeta { @@ -8123,7 +8034,7 @@ type WatchSandboxRequest struct { func (x *WatchSandboxRequest) Reset() { *x = WatchSandboxRequest{} - mi := &file_openshell_proto_msgTypes[93] + mi := &file_openshell_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8135,7 +8046,7 @@ func (x *WatchSandboxRequest) String() string { func (*WatchSandboxRequest) ProtoMessage() {} func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[93] + mi := &file_openshell_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8148,7 +8059,7 @@ func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchSandboxRequest.ProtoReflect.Descriptor instead. func (*WatchSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{93} + return file_openshell_proto_rawDescGZIP(), []int{92} } func (x *WatchSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8264,7 +8175,7 @@ type SandboxStreamEvent struct { func (x *SandboxStreamEvent) Reset() { *x = SandboxStreamEvent{} - mi := &file_openshell_proto_msgTypes[94] + mi := &file_openshell_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8276,7 +8187,7 @@ func (x *SandboxStreamEvent) String() string { func (*SandboxStreamEvent) ProtoMessage() {} func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[94] + mi := &file_openshell_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8289,7 +8200,7 @@ func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStreamEvent.ProtoReflect.Descriptor instead. func (*SandboxStreamEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{94} + return file_openshell_proto_rawDescGZIP(), []int{93} } func (x *SandboxStreamEvent) GetPayload() isSandboxStreamEvent_Payload { @@ -8411,7 +8322,7 @@ type SandboxLogLine struct { func (x *SandboxLogLine) Reset() { *x = SandboxLogLine{} - mi := &file_openshell_proto_msgTypes[95] + mi := &file_openshell_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8423,7 +8334,7 @@ func (x *SandboxLogLine) String() string { func (*SandboxLogLine) ProtoMessage() {} func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[95] + mi := &file_openshell_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8436,7 +8347,7 @@ func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxLogLine.ProtoReflect.Descriptor instead. func (*SandboxLogLine) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{95} + return file_openshell_proto_rawDescGZIP(), []int{94} } func (x *SandboxLogLine) GetSandboxId() string { @@ -8502,7 +8413,7 @@ type SandboxStreamWarning struct { func (x *SandboxStreamWarning) Reset() { *x = SandboxStreamWarning{} - mi := &file_openshell_proto_msgTypes[96] + mi := &file_openshell_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8514,7 +8425,7 @@ func (x *SandboxStreamWarning) String() string { func (*SandboxStreamWarning) ProtoMessage() {} func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[96] + mi := &file_openshell_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8527,7 +8438,7 @@ func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStreamWarning.ProtoReflect.Descriptor instead. func (*SandboxStreamWarning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{96} + return file_openshell_proto_rawDescGZIP(), []int{95} } func (x *SandboxStreamWarning) GetMessage() string { @@ -8552,7 +8463,7 @@ type CreateProviderRequest struct { func (x *CreateProviderRequest) Reset() { *x = CreateProviderRequest{} - mi := &file_openshell_proto_msgTypes[97] + mi := &file_openshell_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8564,7 +8475,7 @@ func (x *CreateProviderRequest) String() string { func (*CreateProviderRequest) ProtoMessage() {} func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[97] + mi := &file_openshell_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8577,7 +8488,7 @@ func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateProviderRequest.ProtoReflect.Descriptor instead. func (*CreateProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{97} + return file_openshell_proto_rawDescGZIP(), []int{96} } func (x *CreateProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8613,7 +8524,7 @@ type GetProviderRequest struct { func (x *GetProviderRequest) Reset() { *x = GetProviderRequest{} - mi := &file_openshell_proto_msgTypes[98] + mi := &file_openshell_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8625,7 +8536,7 @@ func (x *GetProviderRequest) String() string { func (*GetProviderRequest) ProtoMessage() {} func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[98] + mi := &file_openshell_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8638,7 +8549,7 @@ func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRequest.ProtoReflect.Descriptor instead. func (*GetProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{98} + return file_openshell_proto_rawDescGZIP(), []int{97} } func (x *GetProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8673,7 +8584,7 @@ type GetProviderCredentialsRequest struct { func (x *GetProviderCredentialsRequest) Reset() { *x = GetProviderCredentialsRequest{} - mi := &file_openshell_proto_msgTypes[99] + mi := &file_openshell_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8685,7 +8596,7 @@ func (x *GetProviderCredentialsRequest) String() string { func (*GetProviderCredentialsRequest) ProtoMessage() {} func (x *GetProviderCredentialsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[99] + mi := &file_openshell_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8698,7 +8609,7 @@ func (x *GetProviderCredentialsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderCredentialsRequest.ProtoReflect.Descriptor instead. func (*GetProviderCredentialsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{99} + return file_openshell_proto_rawDescGZIP(), []int{98} } func (x *GetProviderCredentialsRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8741,7 +8652,7 @@ type ProviderCredentialValue struct { func (x *ProviderCredentialValue) Reset() { *x = ProviderCredentialValue{} - mi := &file_openshell_proto_msgTypes[100] + mi := &file_openshell_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8753,7 +8664,7 @@ func (x *ProviderCredentialValue) String() string { func (*ProviderCredentialValue) ProtoMessage() {} func (x *ProviderCredentialValue) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[100] + mi := &file_openshell_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8766,7 +8677,7 @@ func (x *ProviderCredentialValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialValue.ProtoReflect.Descriptor instead. func (*ProviderCredentialValue) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{100} + return file_openshell_proto_rawDescGZIP(), []int{99} } func (x *ProviderCredentialValue) GetValue() string { @@ -8793,7 +8704,7 @@ type GetProviderCredentialsResponse struct { func (x *GetProviderCredentialsResponse) Reset() { *x = GetProviderCredentialsResponse{} - mi := &file_openshell_proto_msgTypes[101] + mi := &file_openshell_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8805,7 +8716,7 @@ func (x *GetProviderCredentialsResponse) String() string { func (*GetProviderCredentialsResponse) ProtoMessage() {} func (x *GetProviderCredentialsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[101] + mi := &file_openshell_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8818,7 +8729,7 @@ func (x *GetProviderCredentialsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderCredentialsResponse.ProtoReflect.Descriptor instead. func (*GetProviderCredentialsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{101} + return file_openshell_proto_rawDescGZIP(), []int{100} } func (x *GetProviderCredentialsResponse) GetCredentials() map[string]*ProviderCredentialValue { @@ -8847,7 +8758,7 @@ type ListProvidersRequest struct { func (x *ListProvidersRequest) Reset() { *x = ListProvidersRequest{} - mi := &file_openshell_proto_msgTypes[102] + mi := &file_openshell_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8859,7 +8770,7 @@ func (x *ListProvidersRequest) String() string { func (*ListProvidersRequest) ProtoMessage() {} func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[102] + mi := &file_openshell_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8872,7 +8783,7 @@ func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProvidersRequest.ProtoReflect.Descriptor instead. func (*ListProvidersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{102} + return file_openshell_proto_rawDescGZIP(), []int{101} } func (x *ListProvidersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8924,7 +8835,7 @@ type UpdateProviderRequest struct { func (x *UpdateProviderRequest) Reset() { *x = UpdateProviderRequest{} - mi := &file_openshell_proto_msgTypes[103] + mi := &file_openshell_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8936,7 +8847,7 @@ func (x *UpdateProviderRequest) String() string { func (*UpdateProviderRequest) ProtoMessage() {} func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[103] + mi := &file_openshell_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8949,7 +8860,7 @@ func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{103} + return file_openshell_proto_rawDescGZIP(), []int{102} } func (x *UpdateProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -9003,7 +8914,7 @@ type DeleteProviderRequest struct { func (x *DeleteProviderRequest) Reset() { *x = DeleteProviderRequest{} - mi := &file_openshell_proto_msgTypes[104] + mi := &file_openshell_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9015,7 +8926,7 @@ func (x *DeleteProviderRequest) String() string { func (*DeleteProviderRequest) ProtoMessage() {} func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[104] + mi := &file_openshell_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9028,7 +8939,7 @@ func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{104} + return file_openshell_proto_rawDescGZIP(), []int{103} } func (x *DeleteProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -9074,7 +8985,7 @@ type ProviderResponse struct { func (x *ProviderResponse) Reset() { *x = ProviderResponse{} - mi := &file_openshell_proto_msgTypes[105] + mi := &file_openshell_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9086,7 +8997,7 @@ func (x *ProviderResponse) String() string { func (*ProviderResponse) ProtoMessage() {} func (x *ProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[105] + mi := &file_openshell_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9099,7 +9010,7 @@ func (x *ProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderResponse.ProtoReflect.Descriptor instead. func (*ProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{105} + return file_openshell_proto_rawDescGZIP(), []int{104} } func (x *ProviderResponse) GetProvider() *datamodelv1.Provider { @@ -9135,7 +9046,7 @@ type ListProvidersResponse struct { func (x *ListProvidersResponse) Reset() { *x = ListProvidersResponse{} - mi := &file_openshell_proto_msgTypes[106] + mi := &file_openshell_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9147,7 +9058,7 @@ func (x *ListProvidersResponse) String() string { func (*ListProvidersResponse) ProtoMessage() {} func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[106] + mi := &file_openshell_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9160,7 +9071,7 @@ func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProvidersResponse.ProtoReflect.Descriptor instead. func (*ListProvidersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{106} + return file_openshell_proto_rawDescGZIP(), []int{105} } func (x *ListProvidersResponse) GetProviders() []*datamodelv1.Provider { @@ -9194,7 +9105,7 @@ type ListProviderProfilesRequest struct { func (x *ListProviderProfilesRequest) Reset() { *x = ListProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[107] + mi := &file_openshell_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9206,7 +9117,7 @@ func (x *ListProviderProfilesRequest) String() string { func (*ListProviderProfilesRequest) ProtoMessage() {} func (x *ListProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[107] + mi := &file_openshell_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9219,7 +9130,7 @@ func (x *ListProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ListProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{107} + return file_openshell_proto_rawDescGZIP(), []int{106} } func (x *ListProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -9255,7 +9166,7 @@ type GetProviderProfileRequest struct { func (x *GetProviderProfileRequest) Reset() { *x = GetProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[108] + mi := &file_openshell_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9267,7 +9178,7 @@ func (x *GetProviderProfileRequest) String() string { func (*GetProviderProfileRequest) ProtoMessage() {} func (x *GetProviderProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[108] + mi := &file_openshell_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9280,7 +9191,7 @@ func (x *GetProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderProfileRequest.ProtoReflect.Descriptor instead. func (*GetProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{108} + return file_openshell_proto_rawDescGZIP(), []int{107} } func (x *GetProviderProfileRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -9308,7 +9219,7 @@ type ProviderProfileImportItem struct { func (x *ProviderProfileImportItem) Reset() { *x = ProviderProfileImportItem{} - mi := &file_openshell_proto_msgTypes[109] + mi := &file_openshell_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9320,7 +9231,7 @@ func (x *ProviderProfileImportItem) String() string { func (*ProviderProfileImportItem) ProtoMessage() {} func (x *ProviderProfileImportItem) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[109] + mi := &file_openshell_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9333,7 +9244,7 @@ func (x *ProviderProfileImportItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileImportItem.ProtoReflect.Descriptor instead. func (*ProviderProfileImportItem) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{109} + return file_openshell_proto_rawDescGZIP(), []int{108} } func (x *ProviderProfileImportItem) GetProfile() *ProviderProfile { @@ -9364,7 +9275,7 @@ type ProviderProfileDiagnostic struct { func (x *ProviderProfileDiagnostic) Reset() { *x = ProviderProfileDiagnostic{} - mi := &file_openshell_proto_msgTypes[110] + mi := &file_openshell_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9376,7 +9287,7 @@ func (x *ProviderProfileDiagnostic) String() string { func (*ProviderProfileDiagnostic) ProtoMessage() {} func (x *ProviderProfileDiagnostic) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[110] + mi := &file_openshell_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9389,7 +9300,7 @@ func (x *ProviderProfileDiagnostic) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileDiagnostic.ProtoReflect.Descriptor instead. func (*ProviderProfileDiagnostic) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{110} + return file_openshell_proto_rawDescGZIP(), []int{109} } func (x *ProviderProfileDiagnostic) GetSource() string { @@ -9446,7 +9357,7 @@ type ProviderCredentialTokenGrantAudienceOverride struct { func (x *ProviderCredentialTokenGrantAudienceOverride) Reset() { *x = ProviderCredentialTokenGrantAudienceOverride{} - mi := &file_openshell_proto_msgTypes[111] + mi := &file_openshell_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9458,7 +9369,7 @@ func (x *ProviderCredentialTokenGrantAudienceOverride) String() string { func (*ProviderCredentialTokenGrantAudienceOverride) ProtoMessage() {} func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[111] + mi := &file_openshell_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9471,7 +9382,7 @@ func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protorefle // Deprecated: Use ProviderCredentialTokenGrantAudienceOverride.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrantAudienceOverride) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{111} + return file_openshell_proto_rawDescGZIP(), []int{110} } func (x *ProviderCredentialTokenGrantAudienceOverride) GetHost() string { @@ -9525,7 +9436,7 @@ type ProviderCredentialTokenGrantSubjectToken struct { func (x *ProviderCredentialTokenGrantSubjectToken) Reset() { *x = ProviderCredentialTokenGrantSubjectToken{} - mi := &file_openshell_proto_msgTypes[112] + mi := &file_openshell_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9537,7 +9448,7 @@ func (x *ProviderCredentialTokenGrantSubjectToken) String() string { func (*ProviderCredentialTokenGrantSubjectToken) ProtoMessage() {} func (x *ProviderCredentialTokenGrantSubjectToken) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[112] + mi := &file_openshell_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9550,7 +9461,7 @@ func (x *ProviderCredentialTokenGrantSubjectToken) ProtoReflect() protoreflect.M // Deprecated: Use ProviderCredentialTokenGrantSubjectToken.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrantSubjectToken) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{112} + return file_openshell_proto_rawDescGZIP(), []int{111} } func (x *ProviderCredentialTokenGrantSubjectToken) GetSource() string { @@ -9606,7 +9517,7 @@ type ProviderCredentialTokenGrant struct { func (x *ProviderCredentialTokenGrant) Reset() { *x = ProviderCredentialTokenGrant{} - mi := &file_openshell_proto_msgTypes[113] + mi := &file_openshell_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9618,7 +9529,7 @@ func (x *ProviderCredentialTokenGrant) String() string { func (*ProviderCredentialTokenGrant) ProtoMessage() {} func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[113] + mi := &file_openshell_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9631,7 +9542,7 @@ func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialTokenGrant.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrant) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{113} + return file_openshell_proto_rawDescGZIP(), []int{112} } func (x *ProviderCredentialTokenGrant) GetTokenEndpoint() string { @@ -9735,7 +9646,7 @@ type ProviderProfileCredential struct { func (x *ProviderProfileCredential) Reset() { *x = ProviderProfileCredential{} - mi := &file_openshell_proto_msgTypes[114] + mi := &file_openshell_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9747,7 +9658,7 @@ func (x *ProviderProfileCredential) String() string { func (*ProviderProfileCredential) ProtoMessage() {} func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[114] + mi := &file_openshell_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9760,7 +9671,7 @@ func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileCredential.ProtoReflect.Descriptor instead. func (*ProviderProfileCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{114} + return file_openshell_proto_rawDescGZIP(), []int{113} } func (x *ProviderProfileCredential) GetName() string { @@ -9859,7 +9770,7 @@ type ProviderCredentialRefreshMaterial struct { func (x *ProviderCredentialRefreshMaterial) Reset() { *x = ProviderCredentialRefreshMaterial{} - mi := &file_openshell_proto_msgTypes[115] + mi := &file_openshell_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9871,7 +9782,7 @@ func (x *ProviderCredentialRefreshMaterial) String() string { func (*ProviderCredentialRefreshMaterial) ProtoMessage() {} func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[115] + mi := &file_openshell_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9884,7 +9795,7 @@ func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message // Deprecated: Use ProviderCredentialRefreshMaterial.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshMaterial) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{115} + return file_openshell_proto_rawDescGZIP(), []int{114} } func (x *ProviderCredentialRefreshMaterial) GetName() string { @@ -9929,7 +9840,7 @@ type ProviderCredentialRefreshOutput struct { func (x *ProviderCredentialRefreshOutput) Reset() { *x = ProviderCredentialRefreshOutput{} - mi := &file_openshell_proto_msgTypes[116] + mi := &file_openshell_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9941,7 +9852,7 @@ func (x *ProviderCredentialRefreshOutput) String() string { func (*ProviderCredentialRefreshOutput) ProtoMessage() {} func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[116] + mi := &file_openshell_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9954,7 +9865,7 @@ func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefreshOutput.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshOutput) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{116} + return file_openshell_proto_rawDescGZIP(), []int{115} } func (x *ProviderCredentialRefreshOutput) GetOutput() string { @@ -9986,7 +9897,7 @@ type ProviderCredentialRefresh struct { func (x *ProviderCredentialRefresh) Reset() { *x = ProviderCredentialRefresh{} - mi := &file_openshell_proto_msgTypes[117] + mi := &file_openshell_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9998,7 +9909,7 @@ func (x *ProviderCredentialRefresh) String() string { func (*ProviderCredentialRefresh) ProtoMessage() {} func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[117] + mi := &file_openshell_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10011,7 +9922,7 @@ func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefresh.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefresh) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{117} + return file_openshell_proto_rawDescGZIP(), []int{116} } func (x *ProviderCredentialRefresh) GetStrategy() ProviderCredentialRefreshStrategy { @@ -10092,7 +10003,7 @@ type ProviderCredentialRefreshStatus struct { func (x *ProviderCredentialRefreshStatus) Reset() { *x = ProviderCredentialRefreshStatus{} - mi := &file_openshell_proto_msgTypes[118] + mi := &file_openshell_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10104,7 +10015,7 @@ func (x *ProviderCredentialRefreshStatus) String() string { func (*ProviderCredentialRefreshStatus) ProtoMessage() {} func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[118] + mi := &file_openshell_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10117,7 +10028,7 @@ func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefreshStatus.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{118} + return file_openshell_proto_rawDescGZIP(), []int{117} } func (x *ProviderCredentialRefreshStatus) GetProvider() string { @@ -10222,7 +10133,7 @@ type ProviderProfileDiscovery struct { func (x *ProviderProfileDiscovery) Reset() { *x = ProviderProfileDiscovery{} - mi := &file_openshell_proto_msgTypes[119] + mi := &file_openshell_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10234,7 +10145,7 @@ func (x *ProviderProfileDiscovery) String() string { func (*ProviderProfileDiscovery) ProtoMessage() {} func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[119] + mi := &file_openshell_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10247,7 +10158,7 @@ func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileDiscovery.ProtoReflect.Descriptor instead. func (*ProviderProfileDiscovery) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{119} + return file_openshell_proto_rawDescGZIP(), []int{118} } func (x *ProviderProfileDiscovery) GetCredentials() []string { @@ -10269,7 +10180,7 @@ type GetProviderRefreshStatusRequest struct { func (x *GetProviderRefreshStatusRequest) Reset() { *x = GetProviderRefreshStatusRequest{} - mi := &file_openshell_proto_msgTypes[120] + mi := &file_openshell_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10281,7 +10192,7 @@ func (x *GetProviderRefreshStatusRequest) String() string { func (*GetProviderRefreshStatusRequest) ProtoMessage() {} func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[120] + mi := &file_openshell_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10294,7 +10205,7 @@ func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRefreshStatusRequest.ProtoReflect.Descriptor instead. func (*GetProviderRefreshStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{120} + return file_openshell_proto_rawDescGZIP(), []int{119} } func (x *GetProviderRefreshStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10327,7 +10238,7 @@ type GetProviderRefreshStatusResponse struct { func (x *GetProviderRefreshStatusResponse) Reset() { *x = GetProviderRefreshStatusResponse{} - mi := &file_openshell_proto_msgTypes[121] + mi := &file_openshell_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10339,7 +10250,7 @@ func (x *GetProviderRefreshStatusResponse) String() string { func (*GetProviderRefreshStatusResponse) ProtoMessage() {} func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[121] + mi := &file_openshell_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10352,7 +10263,7 @@ func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRefreshStatusResponse.ProtoReflect.Descriptor instead. func (*GetProviderRefreshStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{121} + return file_openshell_proto_rawDescGZIP(), []int{120} } func (x *GetProviderRefreshStatusResponse) GetCredentials() []*ProviderCredentialRefreshStatus { @@ -10384,7 +10295,7 @@ type ConfigureProviderRefreshRequest struct { func (x *ConfigureProviderRefreshRequest) Reset() { *x = ConfigureProviderRefreshRequest{} - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10396,7 +10307,7 @@ func (x *ConfigureProviderRefreshRequest) String() string { func (*ConfigureProviderRefreshRequest) ProtoMessage() {} func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10409,7 +10320,7 @@ func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureProviderRefreshRequest.ProtoReflect.Descriptor instead. func (*ConfigureProviderRefreshRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{122} + return file_openshell_proto_rawDescGZIP(), []int{121} } func (x *ConfigureProviderRefreshRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10477,7 +10388,7 @@ type ConfigureProviderRefreshResponse struct { func (x *ConfigureProviderRefreshResponse) Reset() { *x = ConfigureProviderRefreshResponse{} - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10489,7 +10400,7 @@ func (x *ConfigureProviderRefreshResponse) String() string { func (*ConfigureProviderRefreshResponse) ProtoMessage() {} func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10502,7 +10413,7 @@ func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureProviderRefreshResponse.ProtoReflect.Descriptor instead. func (*ConfigureProviderRefreshResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{123} + return file_openshell_proto_rawDescGZIP(), []int{122} } func (x *ConfigureProviderRefreshResponse) GetStatus() *ProviderCredentialRefreshStatus { @@ -10527,7 +10438,7 @@ type RotateProviderCredentialRequest struct { func (x *RotateProviderCredentialRequest) Reset() { *x = RotateProviderCredentialRequest{} - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10539,7 +10450,7 @@ func (x *RotateProviderCredentialRequest) String() string { func (*RotateProviderCredentialRequest) ProtoMessage() {} func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10552,7 +10463,7 @@ func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateProviderCredentialRequest.ProtoReflect.Descriptor instead. func (*RotateProviderCredentialRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{124} + return file_openshell_proto_rawDescGZIP(), []int{123} } func (x *RotateProviderCredentialRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10592,7 +10503,7 @@ type RotateProviderCredentialResponse struct { func (x *RotateProviderCredentialResponse) Reset() { *x = RotateProviderCredentialResponse{} - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10604,7 +10515,7 @@ func (x *RotateProviderCredentialResponse) String() string { func (*RotateProviderCredentialResponse) ProtoMessage() {} func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10617,7 +10528,7 @@ func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateProviderCredentialResponse.ProtoReflect.Descriptor instead. func (*RotateProviderCredentialResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{125} + return file_openshell_proto_rawDescGZIP(), []int{124} } func (x *RotateProviderCredentialResponse) GetStatus() *ProviderCredentialRefreshStatus { @@ -10643,7 +10554,7 @@ type DeleteProviderRefreshRequest struct { func (x *DeleteProviderRefreshRequest) Reset() { *x = DeleteProviderRefreshRequest{} - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10655,7 +10566,7 @@ func (x *DeleteProviderRefreshRequest) String() string { func (*DeleteProviderRefreshRequest) ProtoMessage() {} func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10668,7 +10579,7 @@ func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRefreshRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderRefreshRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{126} + return file_openshell_proto_rawDescGZIP(), []int{125} } func (x *DeleteProviderRefreshRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10715,7 +10626,7 @@ type DeleteProviderRefreshResponse struct { func (x *DeleteProviderRefreshResponse) Reset() { *x = DeleteProviderRefreshResponse{} - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10727,7 +10638,7 @@ func (x *DeleteProviderRefreshResponse) String() string { func (*DeleteProviderRefreshResponse) ProtoMessage() {} func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10740,7 +10651,7 @@ func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRefreshResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderRefreshResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{127} + return file_openshell_proto_rawDescGZIP(), []int{126} } func (x *DeleteProviderRefreshResponse) GetOutcome() DeletionOutcome { @@ -10783,7 +10694,7 @@ type ProviderProfile struct { func (x *ProviderProfile) Reset() { *x = ProviderProfile{} - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10795,7 +10706,7 @@ func (x *ProviderProfile) String() string { func (*ProviderProfile) ProtoMessage() {} func (x *ProviderProfile) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10808,7 +10719,7 @@ func (x *ProviderProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfile.ProtoReflect.Descriptor instead. func (*ProviderProfile) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{128} + return file_openshell_proto_rawDescGZIP(), []int{127} } func (x *ProviderProfile) GetId() string { @@ -10924,7 +10835,7 @@ type ProviderProfileFile struct { func (x *ProviderProfileFile) Reset() { *x = ProviderProfileFile{} - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10936,7 +10847,7 @@ func (x *ProviderProfileFile) String() string { func (*ProviderProfileFile) ProtoMessage() {} func (x *ProviderProfileFile) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10949,7 +10860,7 @@ func (x *ProviderProfileFile) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileFile.ProtoReflect.Descriptor instead. func (*ProviderProfileFile) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{129} + return file_openshell_proto_rawDescGZIP(), []int{128} } func (x *ProviderProfileFile) GetPath() string { @@ -10983,7 +10894,7 @@ type ProviderProfileResponse struct { func (x *ProviderProfileResponse) Reset() { *x = ProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10995,7 +10906,7 @@ func (x *ProviderProfileResponse) String() string { func (*ProviderProfileResponse) ProtoMessage() {} func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11008,7 +10919,7 @@ func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileResponse.ProtoReflect.Descriptor instead. func (*ProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{130} + return file_openshell_proto_rawDescGZIP(), []int{129} } func (x *ProviderProfileResponse) GetProfile() *ProviderProfile { @@ -11030,7 +10941,7 @@ type ListProviderProfilesResponse struct { func (x *ListProviderProfilesResponse) Reset() { *x = ListProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11042,7 +10953,7 @@ func (x *ListProviderProfilesResponse) String() string { func (*ListProviderProfilesResponse) ProtoMessage() {} func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11055,7 +10966,7 @@ func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ListProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{131} + return file_openshell_proto_rawDescGZIP(), []int{130} } func (x *ListProviderProfilesResponse) GetProfiles() []*ProviderProfile { @@ -11087,7 +10998,7 @@ type ImportProviderProfilesRequest struct { func (x *ImportProviderProfilesRequest) Reset() { *x = ImportProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11099,7 +11010,7 @@ func (x *ImportProviderProfilesRequest) String() string { func (*ImportProviderProfilesRequest) ProtoMessage() {} func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[131] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11112,7 +11023,7 @@ func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{132} + return file_openshell_proto_rawDescGZIP(), []int{131} } func (x *ImportProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11148,7 +11059,7 @@ type ImportProviderProfilesResponse struct { func (x *ImportProviderProfilesResponse) Reset() { *x = ImportProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11160,7 +11071,7 @@ func (x *ImportProviderProfilesResponse) String() string { func (*ImportProviderProfilesResponse) ProtoMessage() {} func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11173,7 +11084,7 @@ func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{133} + return file_openshell_proto_rawDescGZIP(), []int{132} } func (x *ImportProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11219,7 +11130,7 @@ type UpdateProviderProfilesRequest struct { func (x *UpdateProviderProfilesRequest) Reset() { *x = UpdateProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11231,7 +11142,7 @@ func (x *UpdateProviderProfilesRequest) String() string { func (*UpdateProviderProfilesRequest) ProtoMessage() {} func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11244,7 +11155,7 @@ func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{134} + return file_openshell_proto_rawDescGZIP(), []int{133} } func (x *UpdateProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11294,7 +11205,7 @@ type UpdateProviderProfilesResponse struct { func (x *UpdateProviderProfilesResponse) Reset() { *x = UpdateProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11306,7 +11217,7 @@ func (x *UpdateProviderProfilesResponse) String() string { func (*UpdateProviderProfilesResponse) ProtoMessage() {} func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[134] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11319,7 +11230,7 @@ func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{135} + return file_openshell_proto_rawDescGZIP(), []int{134} } func (x *UpdateProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11355,7 +11266,7 @@ type LintProviderProfilesRequest struct { func (x *LintProviderProfilesRequest) Reset() { *x = LintProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11367,7 +11278,7 @@ func (x *LintProviderProfilesRequest) String() string { func (*LintProviderProfilesRequest) ProtoMessage() {} func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[135] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11380,7 +11291,7 @@ func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*LintProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{136} + return file_openshell_proto_rawDescGZIP(), []int{135} } func (x *LintProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11411,7 +11322,7 @@ type LintProviderProfilesResponse struct { func (x *LintProviderProfilesResponse) Reset() { *x = LintProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11423,7 +11334,7 @@ func (x *LintProviderProfilesResponse) String() string { func (*LintProviderProfilesResponse) ProtoMessage() {} func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[136] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11436,7 +11347,7 @@ func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*LintProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{137} + return file_openshell_proto_rawDescGZIP(), []int{136} } func (x *LintProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11470,7 +11381,7 @@ type DeleteProviderResponse struct { func (x *DeleteProviderResponse) Reset() { *x = DeleteProviderResponse{} - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11482,7 +11393,7 @@ func (x *DeleteProviderResponse) String() string { func (*DeleteProviderResponse) ProtoMessage() {} func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[137] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11495,7 +11406,7 @@ func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{138} + return file_openshell_proto_rawDescGZIP(), []int{137} } func (x *DeleteProviderResponse) GetOutcome() DeletionOutcome { @@ -11521,7 +11432,7 @@ type DeleteProviderProfileRequest struct { func (x *DeleteProviderProfileRequest) Reset() { *x = DeleteProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11533,7 +11444,7 @@ func (x *DeleteProviderProfileRequest) String() string { func (*DeleteProviderProfileRequest) ProtoMessage() {} func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[138] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11546,7 +11457,7 @@ func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{139} + return file_openshell_proto_rawDescGZIP(), []int{138} } func (x *DeleteProviderProfileRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11587,7 +11498,7 @@ type DeleteProviderProfileResponse struct { func (x *DeleteProviderProfileResponse) Reset() { *x = DeleteProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11599,7 +11510,7 @@ func (x *DeleteProviderProfileResponse) String() string { func (*DeleteProviderProfileResponse) ProtoMessage() {} func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[139] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11612,7 +11523,7 @@ func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{140} + return file_openshell_proto_rawDescGZIP(), []int{139} } func (x *DeleteProviderProfileResponse) GetOutcome() DeletionOutcome { @@ -11641,7 +11552,7 @@ type GetSandboxProviderEnvironmentRequest struct { func (x *GetSandboxProviderEnvironmentRequest) Reset() { *x = GetSandboxProviderEnvironmentRequest{} - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[140] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11653,7 +11564,7 @@ func (x *GetSandboxProviderEnvironmentRequest) String() string { func (*GetSandboxProviderEnvironmentRequest) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[140] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11666,7 +11577,7 @@ func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Messa // Deprecated: Use GetSandboxProviderEnvironmentRequest.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{141} + return file_openshell_proto_rawDescGZIP(), []int{140} } func (x *GetSandboxProviderEnvironmentRequest) GetSandboxId() string { @@ -11702,7 +11613,7 @@ type StaticCredentialEndpointBinding struct { func (x *StaticCredentialEndpointBinding) Reset() { *x = StaticCredentialEndpointBinding{} - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11714,7 +11625,7 @@ func (x *StaticCredentialEndpointBinding) String() string { func (*StaticCredentialEndpointBinding) ProtoMessage() {} func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[141] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11727,7 +11638,7 @@ func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialEndpointBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialEndpointBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{142} + return file_openshell_proto_rawDescGZIP(), []int{141} } func (x *StaticCredentialEndpointBinding) GetHost() string { @@ -11771,7 +11682,7 @@ type StaticCredentialBinding struct { func (x *StaticCredentialBinding) Reset() { *x = StaticCredentialBinding{} - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[142] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11783,7 +11694,7 @@ func (x *StaticCredentialBinding) String() string { func (*StaticCredentialBinding) ProtoMessage() {} func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[142] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11796,7 +11707,7 @@ func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{143} + return file_openshell_proto_rawDescGZIP(), []int{142} } func (x *StaticCredentialBinding) GetEndpoints() []*StaticCredentialEndpointBinding { @@ -11866,7 +11777,7 @@ type GetSandboxProviderEnvironmentResponse struct { func (x *GetSandboxProviderEnvironmentResponse) Reset() { *x = GetSandboxProviderEnvironmentResponse{} - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[143] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11878,7 +11789,7 @@ func (x *GetSandboxProviderEnvironmentResponse) String() string { func (*GetSandboxProviderEnvironmentResponse) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[143] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11891,7 +11802,7 @@ func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Mess // Deprecated: Use GetSandboxProviderEnvironmentResponse.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{144} + return file_openshell_proto_rawDescGZIP(), []int{143} } func (x *GetSandboxProviderEnvironmentResponse) GetEnvironment() map[string]string { @@ -12000,7 +11911,7 @@ type ProviderEnvironmentValue struct { func (x *ProviderEnvironmentValue) Reset() { *x = ProviderEnvironmentValue{} - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[144] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12012,7 +11923,7 @@ func (x *ProviderEnvironmentValue) String() string { func (*ProviderEnvironmentValue) ProtoMessage() {} func (x *ProviderEnvironmentValue) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[144] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12025,7 +11936,7 @@ func (x *ProviderEnvironmentValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderEnvironmentValue.ProtoReflect.Descriptor instead. func (*ProviderEnvironmentValue) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{145} + return file_openshell_proto_rawDescGZIP(), []int{144} } func (x *ProviderEnvironmentValue) GetName() string { @@ -12091,7 +12002,7 @@ type ProviderEnvironmentSnapshot struct { func (x *ProviderEnvironmentSnapshot) Reset() { *x = ProviderEnvironmentSnapshot{} - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12103,7 +12014,7 @@ func (x *ProviderEnvironmentSnapshot) String() string { func (*ProviderEnvironmentSnapshot) ProtoMessage() {} func (x *ProviderEnvironmentSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[145] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12116,7 +12027,7 @@ func (x *ProviderEnvironmentSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderEnvironmentSnapshot.ProtoReflect.Descriptor instead. func (*ProviderEnvironmentSnapshot) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{146} + return file_openshell_proto_rawDescGZIP(), []int{145} } func (x *ProviderEnvironmentSnapshot) GetProviderEnvRevision() uint64 { @@ -12185,7 +12096,7 @@ type ExchangeProviderSubjectTokenRequest struct { func (x *ExchangeProviderSubjectTokenRequest) Reset() { *x = ExchangeProviderSubjectTokenRequest{} - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12197,7 +12108,7 @@ func (x *ExchangeProviderSubjectTokenRequest) String() string { func (*ExchangeProviderSubjectTokenRequest) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[146] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12210,7 +12121,7 @@ func (x *ExchangeProviderSubjectTokenRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use ExchangeProviderSubjectTokenRequest.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{147} + return file_openshell_proto_rawDescGZIP(), []int{146} } func (x *ExchangeProviderSubjectTokenRequest) GetSandboxId() string { @@ -12252,7 +12163,7 @@ type ExchangeProviderSubjectTokenResponse struct { func (x *ExchangeProviderSubjectTokenResponse) Reset() { *x = ExchangeProviderSubjectTokenResponse{} - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[147] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12264,7 +12175,7 @@ func (x *ExchangeProviderSubjectTokenResponse) String() string { func (*ExchangeProviderSubjectTokenResponse) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[147] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12277,7 +12188,7 @@ func (x *ExchangeProviderSubjectTokenResponse) ProtoReflect() protoreflect.Messa // Deprecated: Use ExchangeProviderSubjectTokenResponse.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{148} + return file_openshell_proto_rawDescGZIP(), []int{147} } func (x *ExchangeProviderSubjectTokenResponse) GetAccessToken() string { @@ -12351,7 +12262,7 @@ type UpdateConfigRequest struct { func (x *UpdateConfigRequest) Reset() { *x = UpdateConfigRequest{} - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12363,7 +12274,7 @@ func (x *UpdateConfigRequest) String() string { func (*UpdateConfigRequest) ProtoMessage() {} func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[148] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12376,7 +12287,7 @@ func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigRequest.ProtoReflect.Descriptor instead. func (*UpdateConfigRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{149} + return file_openshell_proto_rawDescGZIP(), []int{148} } func (x *UpdateConfigRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -12473,7 +12384,7 @@ type PolicyMergeOperation struct { func (x *PolicyMergeOperation) Reset() { *x = PolicyMergeOperation{} - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12485,7 +12396,7 @@ func (x *PolicyMergeOperation) String() string { func (*PolicyMergeOperation) ProtoMessage() {} func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[149] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12498,7 +12409,7 @@ func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyMergeOperation.ProtoReflect.Descriptor instead. func (*PolicyMergeOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{150} + return file_openshell_proto_rawDescGZIP(), []int{149} } func (x *PolicyMergeOperation) GetOperation() isPolicyMergeOperation_Operation { @@ -12612,7 +12523,7 @@ type AddNetworkRule struct { func (x *AddNetworkRule) Reset() { *x = AddNetworkRule{} - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12624,7 +12535,7 @@ func (x *AddNetworkRule) String() string { func (*AddNetworkRule) ProtoMessage() {} func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[150] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12637,7 +12548,7 @@ func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use AddNetworkRule.ProtoReflect.Descriptor instead. func (*AddNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{151} + return file_openshell_proto_rawDescGZIP(), []int{150} } func (x *AddNetworkRule) GetRuleName() string { @@ -12665,7 +12576,7 @@ type RemoveNetworkEndpoint struct { func (x *RemoveNetworkEndpoint) Reset() { *x = RemoveNetworkEndpoint{} - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12677,7 +12588,7 @@ func (x *RemoveNetworkEndpoint) String() string { func (*RemoveNetworkEndpoint) ProtoMessage() {} func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[151] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12690,7 +12601,7 @@ func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkEndpoint.ProtoReflect.Descriptor instead. func (*RemoveNetworkEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{152} + return file_openshell_proto_rawDescGZIP(), []int{151} } func (x *RemoveNetworkEndpoint) GetRuleName() string { @@ -12723,7 +12634,7 @@ type RemoveNetworkRule struct { func (x *RemoveNetworkRule) Reset() { *x = RemoveNetworkRule{} - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12735,7 +12646,7 @@ func (x *RemoveNetworkRule) String() string { func (*RemoveNetworkRule) ProtoMessage() {} func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[152] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12748,7 +12659,7 @@ func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkRule.ProtoReflect.Descriptor instead. func (*RemoveNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{153} + return file_openshell_proto_rawDescGZIP(), []int{152} } func (x *RemoveNetworkRule) GetRuleName() string { @@ -12777,7 +12688,7 @@ type L7RuleTarget struct { func (x *L7RuleTarget) Reset() { *x = L7RuleTarget{} - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12789,7 +12700,7 @@ func (x *L7RuleTarget) String() string { func (*L7RuleTarget) ProtoMessage() {} func (x *L7RuleTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[153] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12802,7 +12713,7 @@ func (x *L7RuleTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RuleTarget.ProtoReflect.Descriptor instead. func (*L7RuleTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{154} + return file_openshell_proto_rawDescGZIP(), []int{153} } func (x *L7RuleTarget) GetRuleName() string { @@ -12857,7 +12768,7 @@ type AddDenyRules struct { func (x *AddDenyRules) Reset() { *x = AddDenyRules{} - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[154] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12869,7 +12780,7 @@ func (x *AddDenyRules) String() string { func (*AddDenyRules) ProtoMessage() {} func (x *AddDenyRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[154] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12882,7 +12793,7 @@ func (x *AddDenyRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddDenyRules.ProtoReflect.Descriptor instead. func (*AddDenyRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{155} + return file_openshell_proto_rawDescGZIP(), []int{154} } func (x *AddDenyRules) GetDenyRules() []*sandboxv1.L7DenyRule { @@ -12909,7 +12820,7 @@ type AddAllowRules struct { func (x *AddAllowRules) Reset() { *x = AddAllowRules{} - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[155] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12921,7 +12832,7 @@ func (x *AddAllowRules) String() string { func (*AddAllowRules) ProtoMessage() {} func (x *AddAllowRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[155] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12934,7 +12845,7 @@ func (x *AddAllowRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAllowRules.ProtoReflect.Descriptor instead. func (*AddAllowRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{156} + return file_openshell_proto_rawDescGZIP(), []int{155} } func (x *AddAllowRules) GetRules() []*sandboxv1.L7Rule { @@ -12961,7 +12872,7 @@ type RemoveNetworkBinary struct { func (x *RemoveNetworkBinary) Reset() { *x = RemoveNetworkBinary{} - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[156] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12973,7 +12884,7 @@ func (x *RemoveNetworkBinary) String() string { func (*RemoveNetworkBinary) ProtoMessage() {} func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[156] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12986,7 +12897,7 @@ func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkBinary.ProtoReflect.Descriptor instead. func (*RemoveNetworkBinary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{157} + return file_openshell_proto_rawDescGZIP(), []int{156} } func (x *RemoveNetworkBinary) GetRuleName() string { @@ -13022,7 +12933,7 @@ type UpdateConfigResponse struct { func (x *UpdateConfigResponse) Reset() { *x = UpdateConfigResponse{} - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[157] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13034,7 +12945,7 @@ func (x *UpdateConfigResponse) String() string { func (*UpdateConfigResponse) ProtoMessage() {} func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[157] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13047,7 +12958,7 @@ func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigResponse.ProtoReflect.Descriptor instead. func (*UpdateConfigResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{158} + return file_openshell_proto_rawDescGZIP(), []int{157} } func (x *UpdateConfigResponse) GetVersion() uint32 { @@ -13101,7 +13012,7 @@ type GetSandboxPolicyStatusRequest struct { func (x *GetSandboxPolicyStatusRequest) Reset() { *x = GetSandboxPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[158] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13113,7 +13024,7 @@ func (x *GetSandboxPolicyStatusRequest) String() string { func (*GetSandboxPolicyStatusRequest) ProtoMessage() {} func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[158] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13126,7 +13037,7 @@ func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{159} + return file_openshell_proto_rawDescGZIP(), []int{158} } func (x *GetSandboxPolicyStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -13170,7 +13081,7 @@ type GetSandboxPolicyStatusResponse struct { func (x *GetSandboxPolicyStatusResponse) Reset() { *x = GetSandboxPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[159] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13182,7 +13093,7 @@ func (x *GetSandboxPolicyStatusResponse) String() string { func (*GetSandboxPolicyStatusResponse) ProtoMessage() {} func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[159] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13195,7 +13106,7 @@ func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{160} + return file_openshell_proto_rawDescGZIP(), []int{159} } func (x *GetSandboxPolicyStatusResponse) GetRevision() *SandboxPolicyRevision { @@ -13232,7 +13143,7 @@ type ListSandboxPoliciesRequest struct { func (x *ListSandboxPoliciesRequest) Reset() { *x = ListSandboxPoliciesRequest{} - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[160] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13244,7 +13155,7 @@ func (x *ListSandboxPoliciesRequest) String() string { func (*ListSandboxPoliciesRequest) ProtoMessage() {} func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[160] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13257,7 +13168,7 @@ func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{161} + return file_openshell_proto_rawDescGZIP(), []int{160} } func (x *ListSandboxPoliciesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -13309,7 +13220,7 @@ type ListSandboxPoliciesResponse struct { func (x *ListSandboxPoliciesResponse) Reset() { *x = ListSandboxPoliciesResponse{} - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[161] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13321,7 +13232,7 @@ func (x *ListSandboxPoliciesResponse) String() string { func (*ListSandboxPoliciesResponse) ProtoMessage() {} func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[161] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13334,7 +13245,7 @@ func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{162} + return file_openshell_proto_rawDescGZIP(), []int{161} } func (x *ListSandboxPoliciesResponse) GetRevisions() []*SandboxPolicyRevision { @@ -13368,7 +13279,7 @@ type ReportPolicyStatusRequest struct { func (x *ReportPolicyStatusRequest) Reset() { *x = ReportPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[162] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13380,7 +13291,7 @@ func (x *ReportPolicyStatusRequest) String() string { func (*ReportPolicyStatusRequest) ProtoMessage() {} func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[162] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13393,7 +13304,7 @@ func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{163} + return file_openshell_proto_rawDescGZIP(), []int{162} } func (x *ReportPolicyStatusRequest) GetSandboxId() string { @@ -13433,7 +13344,7 @@ type ReportPolicyStatusResponse struct { func (x *ReportPolicyStatusResponse) Reset() { *x = ReportPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[163] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13445,7 +13356,7 @@ func (x *ReportPolicyStatusResponse) String() string { func (*ReportPolicyStatusResponse) ProtoMessage() {} func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[163] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13458,7 +13369,7 @@ func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{164} + return file_openshell_proto_rawDescGZIP(), []int{163} } type SandboxConfigurationAdmission struct { @@ -13476,7 +13387,7 @@ type SandboxConfigurationAdmission struct { func (x *SandboxConfigurationAdmission) Reset() { *x = SandboxConfigurationAdmission{} - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[164] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13488,7 +13399,7 @@ func (x *SandboxConfigurationAdmission) String() string { func (*SandboxConfigurationAdmission) ProtoMessage() {} func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[164] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13501,7 +13412,7 @@ func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfigurationAdmission.ProtoReflect.Descriptor instead. func (*SandboxConfigurationAdmission) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{165} + return file_openshell_proto_rawDescGZIP(), []int{164} } func (x *SandboxConfigurationAdmission) GetInstanceId() string { @@ -13565,7 +13476,7 @@ type ReportSandboxConfigurationRequest struct { func (x *ReportSandboxConfigurationRequest) Reset() { *x = ReportSandboxConfigurationRequest{} - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[165] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13577,7 +13488,7 @@ func (x *ReportSandboxConfigurationRequest) String() string { func (*ReportSandboxConfigurationRequest) ProtoMessage() {} func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[165] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13590,7 +13501,7 @@ func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ReportSandboxConfigurationRequest.ProtoReflect.Descriptor instead. func (*ReportSandboxConfigurationRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{166} + return file_openshell_proto_rawDescGZIP(), []int{165} } func (x *ReportSandboxConfigurationRequest) GetSandboxId() string { @@ -13622,7 +13533,7 @@ type ReportSandboxConfigurationResponse struct { func (x *ReportSandboxConfigurationResponse) Reset() { *x = ReportSandboxConfigurationResponse{} - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[166] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13634,7 +13545,7 @@ func (x *ReportSandboxConfigurationResponse) String() string { func (*ReportSandboxConfigurationResponse) ProtoMessage() {} func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[166] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13647,7 +13558,7 @@ func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ReportSandboxConfigurationResponse.ProtoReflect.Descriptor instead. func (*ReportSandboxConfigurationResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{167} + return file_openshell_proto_rawDescGZIP(), []int{166} } // A versioned policy revision with metadata. @@ -13680,7 +13591,7 @@ type SandboxPolicyRevision struct { func (x *SandboxPolicyRevision) Reset() { *x = SandboxPolicyRevision{} - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[167] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13692,7 +13603,7 @@ func (x *SandboxPolicyRevision) String() string { func (*SandboxPolicyRevision) ProtoMessage() {} func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[167] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13705,7 +13616,7 @@ func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxPolicyRevision.ProtoReflect.Descriptor instead. func (*SandboxPolicyRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{168} + return file_openshell_proto_rawDescGZIP(), []int{167} } func (x *SandboxPolicyRevision) GetVersion() uint32 { @@ -13785,7 +13696,7 @@ type GetSandboxLogsRequest struct { func (x *GetSandboxLogsRequest) Reset() { *x = GetSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[168] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13797,7 +13708,7 @@ func (x *GetSandboxLogsRequest) String() string { func (*GetSandboxLogsRequest) ProtoMessage() {} func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[168] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13810,7 +13721,7 @@ func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*GetSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{169} + return file_openshell_proto_rawDescGZIP(), []int{168} } func (x *GetSandboxLogsRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -13868,7 +13779,7 @@ type PushSandboxLogsRequest struct { func (x *PushSandboxLogsRequest) Reset() { *x = PushSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[169] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13880,7 +13791,7 @@ func (x *PushSandboxLogsRequest) String() string { func (*PushSandboxLogsRequest) ProtoMessage() {} func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[169] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13893,7 +13804,7 @@ func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*PushSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{170} + return file_openshell_proto_rawDescGZIP(), []int{169} } func (x *PushSandboxLogsRequest) GetSandboxId() string { @@ -13919,7 +13830,7 @@ type PushSandboxLogsResponse struct { func (x *PushSandboxLogsResponse) Reset() { *x = PushSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[170] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13931,7 +13842,7 @@ func (x *PushSandboxLogsResponse) String() string { func (*PushSandboxLogsResponse) ProtoMessage() {} func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[170] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13944,7 +13855,7 @@ func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*PushSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{171} + return file_openshell_proto_rawDescGZIP(), []int{170} } // Get sandbox logs response. @@ -13960,7 +13871,7 @@ type GetSandboxLogsResponse struct { func (x *GetSandboxLogsResponse) Reset() { *x = GetSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[171] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13972,7 +13883,7 @@ func (x *GetSandboxLogsResponse) String() string { func (*GetSandboxLogsResponse) ProtoMessage() {} func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[171] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13985,7 +13896,7 @@ func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*GetSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{172} + return file_openshell_proto_rawDescGZIP(), []int{171} } func (x *GetSandboxLogsResponse) GetLogs() []*SandboxLogLine { @@ -14019,7 +13930,7 @@ type SupervisorMessage struct { func (x *SupervisorMessage) Reset() { *x = SupervisorMessage{} - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[172] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14031,7 +13942,7 @@ func (x *SupervisorMessage) String() string { func (*SupervisorMessage) ProtoMessage() {} func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[172] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14044,7 +13955,7 @@ func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMessage.ProtoReflect.Descriptor instead. func (*SupervisorMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{173} + return file_openshell_proto_rawDescGZIP(), []int{172} } func (x *SupervisorMessage) GetPayload() isSupervisorMessage_Payload { @@ -14152,7 +14063,7 @@ type GatewayMessage struct { func (x *GatewayMessage) Reset() { *x = GatewayMessage{} - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[173] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14164,7 +14075,7 @@ func (x *GatewayMessage) String() string { func (*GatewayMessage) ProtoMessage() {} func (x *GatewayMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[173] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14177,7 +14088,7 @@ func (x *GatewayMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayMessage.ProtoReflect.Descriptor instead. func (*GatewayMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{174} + return file_openshell_proto_rawDescGZIP(), []int{173} } func (x *GatewayMessage) GetPayload() isGatewayMessage_Payload { @@ -14327,7 +14238,7 @@ type SupervisorHello struct { func (x *SupervisorHello) Reset() { *x = SupervisorHello{} - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[174] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14339,7 +14250,7 @@ func (x *SupervisorHello) String() string { func (*SupervisorHello) ProtoMessage() {} func (x *SupervisorHello) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[174] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14352,7 +14263,7 @@ func (x *SupervisorHello) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHello.ProtoReflect.Descriptor instead. func (*SupervisorHello) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{175} + return file_openshell_proto_rawDescGZIP(), []int{174} } func (x *SupervisorHello) GetSandboxId() string { @@ -14425,7 +14336,7 @@ type SessionAccepted struct { func (x *SessionAccepted) Reset() { *x = SessionAccepted{} - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[175] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14437,7 +14348,7 @@ func (x *SessionAccepted) String() string { func (*SessionAccepted) ProtoMessage() {} func (x *SessionAccepted) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[175] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14450,7 +14361,7 @@ func (x *SessionAccepted) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionAccepted.ProtoReflect.Descriptor instead. func (*SessionAccepted) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{176} + return file_openshell_proto_rawDescGZIP(), []int{175} } func (x *SessionAccepted) GetSessionId() string { @@ -14499,7 +14410,7 @@ type ConfigUpdate struct { func (x *ConfigUpdate) Reset() { *x = ConfigUpdate{} - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[176] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14511,7 +14422,7 @@ func (x *ConfigUpdate) String() string { func (*ConfigUpdate) ProtoMessage() {} func (x *ConfigUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[176] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14524,7 +14435,7 @@ func (x *ConfigUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdate.ProtoReflect.Descriptor instead. func (*ConfigUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{177} + return file_openshell_proto_rawDescGZIP(), []int{176} } func (x *ConfigUpdate) GetUpdateId() string { @@ -14561,7 +14472,7 @@ type ConfigApplyFailure struct { func (x *ConfigApplyFailure) Reset() { *x = ConfigApplyFailure{} - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[177] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14573,7 +14484,7 @@ func (x *ConfigApplyFailure) String() string { func (*ConfigApplyFailure) ProtoMessage() {} func (x *ConfigApplyFailure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[177] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14586,7 +14497,7 @@ func (x *ConfigApplyFailure) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigApplyFailure.ProtoReflect.Descriptor instead. func (*ConfigApplyFailure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{178} + return file_openshell_proto_rawDescGZIP(), []int{177} } func (x *ConfigApplyFailure) GetCode() string { @@ -14630,7 +14541,7 @@ type ConfigUpdateResult struct { func (x *ConfigUpdateResult) Reset() { *x = ConfigUpdateResult{} - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[178] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14642,7 +14553,7 @@ func (x *ConfigUpdateResult) String() string { func (*ConfigUpdateResult) ProtoMessage() {} func (x *ConfigUpdateResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[178] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14655,7 +14566,7 @@ func (x *ConfigUpdateResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdateResult.ProtoReflect.Descriptor instead. func (*ConfigUpdateResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{179} + return file_openshell_proto_rawDescGZIP(), []int{178} } func (x *ConfigUpdateResult) GetUpdateId() string { @@ -14706,7 +14617,7 @@ type PolicyLoadResult struct { func (x *PolicyLoadResult) Reset() { *x = PolicyLoadResult{} - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[179] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14718,7 +14629,7 @@ func (x *PolicyLoadResult) String() string { func (*PolicyLoadResult) ProtoMessage() {} func (x *PolicyLoadResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[179] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14731,7 +14642,7 @@ func (x *PolicyLoadResult) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyLoadResult.ProtoReflect.Descriptor instead. func (*PolicyLoadResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{180} + return file_openshell_proto_rawDescGZIP(), []int{179} } func (x *PolicyLoadResult) GetVersion() uint32 { @@ -14766,7 +14677,7 @@ type SessionRejected struct { func (x *SessionRejected) Reset() { *x = SessionRejected{} - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[180] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14778,7 +14689,7 @@ func (x *SessionRejected) String() string { func (*SessionRejected) ProtoMessage() {} func (x *SessionRejected) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[180] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14791,7 +14702,7 @@ func (x *SessionRejected) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRejected.ProtoReflect.Descriptor instead. func (*SessionRejected) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{181} + return file_openshell_proto_rawDescGZIP(), []int{180} } func (x *SessionRejected) GetReason() string { @@ -14820,7 +14731,7 @@ type SessionRedirect struct { func (x *SessionRedirect) Reset() { *x = SessionRedirect{} - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[181] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14832,7 +14743,7 @@ func (x *SessionRedirect) String() string { func (*SessionRedirect) ProtoMessage() {} func (x *SessionRedirect) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[181] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14845,7 +14756,7 @@ func (x *SessionRedirect) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRedirect.ProtoReflect.Descriptor instead. func (*SessionRedirect) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{182} + return file_openshell_proto_rawDescGZIP(), []int{181} } func (x *SessionRedirect) GetPeerEndpoint() string { @@ -14871,7 +14782,7 @@ type SupervisorHeartbeat struct { func (x *SupervisorHeartbeat) Reset() { *x = SupervisorHeartbeat{} - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[182] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14883,7 +14794,7 @@ func (x *SupervisorHeartbeat) String() string { func (*SupervisorHeartbeat) ProtoMessage() {} func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[182] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14896,7 +14807,7 @@ func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHeartbeat.ProtoReflect.Descriptor instead. func (*SupervisorHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{183} + return file_openshell_proto_rawDescGZIP(), []int{182} } // Gateway heartbeat. @@ -14908,7 +14819,7 @@ type GatewayHeartbeat struct { func (x *GatewayHeartbeat) Reset() { *x = GatewayHeartbeat{} - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[183] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14920,7 +14831,7 @@ func (x *GatewayHeartbeat) String() string { func (*GatewayHeartbeat) ProtoMessage() {} func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[183] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14933,7 +14844,7 @@ func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayHeartbeat.ProtoReflect.Descriptor instead. func (*GatewayHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{184} + return file_openshell_proto_rawDescGZIP(), []int{183} } // Terminal result reported before the supervisor shuts down. A successful RPC @@ -14950,7 +14861,7 @@ type ReportMainProcessExitRequest struct { func (x *ReportMainProcessExitRequest) Reset() { *x = ReportMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[184] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14962,7 +14873,7 @@ func (x *ReportMainProcessExitRequest) String() string { func (*ReportMainProcessExitRequest) ProtoMessage() {} func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[184] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14975,7 +14886,7 @@ func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{185} + return file_openshell_proto_rawDescGZIP(), []int{184} } func (x *ReportMainProcessExitRequest) GetSandboxId() string { @@ -15007,7 +14918,7 @@ type ReportMainProcessExitResponse struct { func (x *ReportMainProcessExitResponse) Reset() { *x = ReportMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[185] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15019,7 +14930,7 @@ func (x *ReportMainProcessExitResponse) String() string { func (*ReportMainProcessExitResponse) ProtoMessage() {} func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[185] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15032,7 +14943,7 @@ func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{186} + return file_openshell_proto_rawDescGZIP(), []int{185} } // Terminal-delivery completion reported after all expected foreground SSH @@ -15047,7 +14958,7 @@ type FinalizeMainProcessExitRequest struct { func (x *FinalizeMainProcessExitRequest) Reset() { *x = FinalizeMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[186] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15059,7 +14970,7 @@ func (x *FinalizeMainProcessExitRequest) String() string { func (*FinalizeMainProcessExitRequest) ProtoMessage() {} func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[186] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15072,7 +14983,7 @@ func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{187} + return file_openshell_proto_rawDescGZIP(), []int{186} } func (x *FinalizeMainProcessExitRequest) GetSandboxId() string { @@ -15097,7 +15008,7 @@ type FinalizeMainProcessExitResponse struct { func (x *FinalizeMainProcessExitResponse) Reset() { *x = FinalizeMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[187] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15109,7 +15020,7 @@ func (x *FinalizeMainProcessExitResponse) String() string { func (*FinalizeMainProcessExitResponse) ProtoMessage() {} func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[187] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15122,7 +15033,7 @@ func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{188} + return file_openshell_proto_rawDescGZIP(), []int{187} } // Gateway requests the supervisor to open a relay channel. @@ -15151,7 +15062,7 @@ type RelayOpen struct { func (x *RelayOpen) Reset() { *x = RelayOpen{} - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[188] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15163,7 +15074,7 @@ func (x *RelayOpen) String() string { func (*RelayOpen) ProtoMessage() {} func (x *RelayOpen) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[188] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15176,7 +15087,7 @@ func (x *RelayOpen) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpen.ProtoReflect.Descriptor instead. func (*RelayOpen) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{189} + return file_openshell_proto_rawDescGZIP(), []int{188} } func (x *RelayOpen) GetChannelId() string { @@ -15243,7 +15154,7 @@ type SshRelayTarget struct { func (x *SshRelayTarget) Reset() { *x = SshRelayTarget{} - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[189] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15255,7 +15166,7 @@ func (x *SshRelayTarget) String() string { func (*SshRelayTarget) ProtoMessage() {} func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[189] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15268,7 +15179,7 @@ func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use SshRelayTarget.ProtoReflect.Descriptor instead. func (*SshRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{190} + return file_openshell_proto_rawDescGZIP(), []int{189} } // TCP target dialed by the supervisor from inside the sandbox. @@ -15284,7 +15195,7 @@ type TcpRelayTarget struct { func (x *TcpRelayTarget) Reset() { *x = TcpRelayTarget{} - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[190] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15296,7 +15207,7 @@ func (x *TcpRelayTarget) String() string { func (*TcpRelayTarget) ProtoMessage() {} func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[190] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15309,7 +15220,7 @@ func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpRelayTarget.ProtoReflect.Descriptor instead. func (*TcpRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{191} + return file_openshell_proto_rawDescGZIP(), []int{190} } func (x *TcpRelayTarget) GetHost() string { @@ -15337,7 +15248,7 @@ type RelayInit struct { func (x *RelayInit) Reset() { *x = RelayInit{} - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[191] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15349,7 +15260,7 @@ func (x *RelayInit) String() string { func (*RelayInit) ProtoMessage() {} func (x *RelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[191] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15362,7 +15273,7 @@ func (x *RelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayInit.ProtoReflect.Descriptor instead. func (*RelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{192} + return file_openshell_proto_rawDescGZIP(), []int{191} } func (x *RelayInit) GetChannelId() string { @@ -15389,7 +15300,7 @@ type RelayFrame struct { func (x *RelayFrame) Reset() { *x = RelayFrame{} - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[192] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15401,7 +15312,7 @@ func (x *RelayFrame) String() string { func (*RelayFrame) ProtoMessage() {} func (x *RelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[192] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15414,7 +15325,7 @@ func (x *RelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayFrame.ProtoReflect.Descriptor instead. func (*RelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{193} + return file_openshell_proto_rawDescGZIP(), []int{192} } func (x *RelayFrame) GetPayload() isRelayFrame_Payload { @@ -15474,7 +15385,7 @@ type PeerRelayInit struct { func (x *PeerRelayInit) Reset() { *x = PeerRelayInit{} - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15486,7 +15397,7 @@ func (x *PeerRelayInit) String() string { func (*PeerRelayInit) ProtoMessage() {} func (x *PeerRelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[193] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15499,7 +15410,7 @@ func (x *PeerRelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerRelayInit.ProtoReflect.Descriptor instead. func (*PeerRelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{194} + return file_openshell_proto_rawDescGZIP(), []int{193} } func (x *PeerRelayInit) GetSandboxId() string { @@ -15537,7 +15448,7 @@ type PeerRelayFrame struct { func (x *PeerRelayFrame) Reset() { *x = PeerRelayFrame{} - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15549,7 +15460,7 @@ func (x *PeerRelayFrame) String() string { func (*PeerRelayFrame) ProtoMessage() {} func (x *PeerRelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[194] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15562,7 +15473,7 @@ func (x *PeerRelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerRelayFrame.ProtoReflect.Descriptor instead. func (*PeerRelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{195} + return file_openshell_proto_rawDescGZIP(), []int{194} } func (x *PeerRelayFrame) GetPayload() isPeerRelayFrame_Payload { @@ -15617,7 +15528,7 @@ type PeerConfigSandboxTarget struct { func (x *PeerConfigSandboxTarget) Reset() { *x = PeerConfigSandboxTarget{} - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15629,7 +15540,7 @@ func (x *PeerConfigSandboxTarget) String() string { func (*PeerConfigSandboxTarget) ProtoMessage() {} func (x *PeerConfigSandboxTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[195] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15642,7 +15553,7 @@ func (x *PeerConfigSandboxTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerConfigSandboxTarget.ProtoReflect.Descriptor instead. func (*PeerConfigSandboxTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{196} + return file_openshell_proto_rawDescGZIP(), []int{195} } func (x *PeerConfigSandboxTarget) GetSandboxId() string { @@ -15670,7 +15581,7 @@ type PeerConfigProviderTarget struct { func (x *PeerConfigProviderTarget) Reset() { *x = PeerConfigProviderTarget{} - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15682,7 +15593,7 @@ func (x *PeerConfigProviderTarget) String() string { func (*PeerConfigProviderTarget) ProtoMessage() {} func (x *PeerConfigProviderTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[196] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15695,7 +15606,7 @@ func (x *PeerConfigProviderTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerConfigProviderTarget.ProtoReflect.Descriptor instead. func (*PeerConfigProviderTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{197} + return file_openshell_proto_rawDescGZIP(), []int{196} } func (x *PeerConfigProviderTarget) GetWorkspace() string { @@ -15727,7 +15638,7 @@ type PeerNotifyConfigUpdateRequest struct { func (x *PeerNotifyConfigUpdateRequest) Reset() { *x = PeerNotifyConfigUpdateRequest{} - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15739,7 +15650,7 @@ func (x *PeerNotifyConfigUpdateRequest) String() string { func (*PeerNotifyConfigUpdateRequest) ProtoMessage() {} func (x *PeerNotifyConfigUpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[197] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15752,7 +15663,7 @@ func (x *PeerNotifyConfigUpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerNotifyConfigUpdateRequest.ProtoReflect.Descriptor instead. func (*PeerNotifyConfigUpdateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{198} + return file_openshell_proto_rawDescGZIP(), []int{197} } func (x *PeerNotifyConfigUpdateRequest) GetScope() isPeerNotifyConfigUpdateRequest_Scope { @@ -15836,7 +15747,7 @@ type PeerNotifyConfigUpdateResponse struct { func (x *PeerNotifyConfigUpdateResponse) Reset() { *x = PeerNotifyConfigUpdateResponse{} - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15848,7 +15759,7 @@ func (x *PeerNotifyConfigUpdateResponse) String() string { func (*PeerNotifyConfigUpdateResponse) ProtoMessage() {} func (x *PeerNotifyConfigUpdateResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[198] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15861,7 +15772,7 @@ func (x *PeerNotifyConfigUpdateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerNotifyConfigUpdateResponse.ProtoReflect.Descriptor instead. func (*PeerNotifyConfigUpdateResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{199} + return file_openshell_proto_rawDescGZIP(), []int{198} } func (x *PeerNotifyConfigUpdateResponse) GetStaleOwner() bool { @@ -15886,7 +15797,7 @@ type RelayOpenResult struct { func (x *RelayOpenResult) Reset() { *x = RelayOpenResult{} - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15898,7 +15809,7 @@ func (x *RelayOpenResult) String() string { func (*RelayOpenResult) ProtoMessage() {} func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[199] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15911,7 +15822,7 @@ func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpenResult.ProtoReflect.Descriptor instead. func (*RelayOpenResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{200} + return file_openshell_proto_rawDescGZIP(), []int{199} } func (x *RelayOpenResult) GetChannelId() string { @@ -15948,7 +15859,7 @@ type RelayClose struct { func (x *RelayClose) Reset() { *x = RelayClose{} - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[200] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15960,7 +15871,7 @@ func (x *RelayClose) String() string { func (*RelayClose) ProtoMessage() {} func (x *RelayClose) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[200] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15973,7 +15884,7 @@ func (x *RelayClose) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayClose.ProtoReflect.Descriptor instead. func (*RelayClose) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{201} + return file_openshell_proto_rawDescGZIP(), []int{200} } func (x *RelayClose) GetChannelId() string { @@ -16007,7 +15918,7 @@ type L7RequestSample struct { func (x *L7RequestSample) Reset() { *x = L7RequestSample{} - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[201] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16019,7 +15930,7 @@ func (x *L7RequestSample) String() string { func (*L7RequestSample) ProtoMessage() {} func (x *L7RequestSample) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[201] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16032,7 +15943,7 @@ func (x *L7RequestSample) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RequestSample.ProtoReflect.Descriptor instead. func (*L7RequestSample) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{202} + return file_openshell_proto_rawDescGZIP(), []int{201} } func (x *L7RequestSample) GetMethod() string { @@ -16106,7 +16017,7 @@ type DenialSummary struct { func (x *DenialSummary) Reset() { *x = DenialSummary{} - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[202] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16118,7 +16029,7 @@ func (x *DenialSummary) String() string { func (*DenialSummary) ProtoMessage() {} func (x *DenialSummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[202] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16131,7 +16042,7 @@ func (x *DenialSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialSummary.ProtoReflect.Descriptor instead. func (*DenialSummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{203} + return file_openshell_proto_rawDescGZIP(), []int{202} } func (x *DenialSummary) GetSandboxId() string { @@ -16266,7 +16177,7 @@ type DenialGroupCount struct { func (x *DenialGroupCount) Reset() { *x = DenialGroupCount{} - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[203] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16278,7 +16189,7 @@ func (x *DenialGroupCount) String() string { func (*DenialGroupCount) ProtoMessage() {} func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[203] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16291,7 +16202,7 @@ func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialGroupCount.ProtoReflect.Descriptor instead. func (*DenialGroupCount) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{204} + return file_openshell_proto_rawDescGZIP(), []int{203} } func (x *DenialGroupCount) GetDenyGroup() string { @@ -16324,7 +16235,7 @@ type NetworkActivitySummary struct { func (x *NetworkActivitySummary) Reset() { *x = NetworkActivitySummary{} - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[204] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16336,7 +16247,7 @@ func (x *NetworkActivitySummary) String() string { func (*NetworkActivitySummary) ProtoMessage() {} func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[204] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16349,7 +16260,7 @@ func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkActivitySummary.ProtoReflect.Descriptor instead. func (*NetworkActivitySummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{205} + return file_openshell_proto_rawDescGZIP(), []int{204} } func (x *NetworkActivitySummary) GetNetworkActivityCount() uint32 { @@ -16437,7 +16348,7 @@ type PolicyChunk struct { func (x *PolicyChunk) Reset() { *x = PolicyChunk{} - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[205] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16449,7 +16360,7 @@ func (x *PolicyChunk) String() string { func (*PolicyChunk) ProtoMessage() {} func (x *PolicyChunk) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[205] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16462,7 +16373,7 @@ func (x *PolicyChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyChunk.ProtoReflect.Descriptor instead. func (*PolicyChunk) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{206} + return file_openshell_proto_rawDescGZIP(), []int{205} } func (x *PolicyChunk) GetId() string { @@ -16650,7 +16561,7 @@ type DraftPolicyUpdate struct { func (x *DraftPolicyUpdate) Reset() { *x = DraftPolicyUpdate{} - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[206] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16662,7 +16573,7 @@ func (x *DraftPolicyUpdate) String() string { func (*DraftPolicyUpdate) ProtoMessage() {} func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[206] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16675,7 +16586,7 @@ func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftPolicyUpdate.ProtoReflect.Descriptor instead. func (*DraftPolicyUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{207} + return file_openshell_proto_rawDescGZIP(), []int{206} } func (x *DraftPolicyUpdate) GetDraftVersion() uint64 { @@ -16734,7 +16645,7 @@ type SubmitPolicyAnalysisRequest struct { func (x *SubmitPolicyAnalysisRequest) Reset() { *x = SubmitPolicyAnalysisRequest{} - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[207] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16746,7 +16657,7 @@ func (x *SubmitPolicyAnalysisRequest) String() string { func (*SubmitPolicyAnalysisRequest) ProtoMessage() {} func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[207] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16759,7 +16670,7 @@ func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisRequest.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{208} + return file_openshell_proto_rawDescGZIP(), []int{207} } func (x *SubmitPolicyAnalysisRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16822,7 +16733,7 @@ type SubmitPolicyAnalysisResponse struct { func (x *SubmitPolicyAnalysisResponse) Reset() { *x = SubmitPolicyAnalysisResponse{} - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[208] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16834,7 +16745,7 @@ func (x *SubmitPolicyAnalysisResponse) String() string { func (*SubmitPolicyAnalysisResponse) ProtoMessage() {} func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[208] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16847,7 +16758,7 @@ func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisResponse.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{209} + return file_openshell_proto_rawDescGZIP(), []int{208} } func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunks() uint32 { @@ -16892,7 +16803,7 @@ type GetDraftPolicyRequest struct { func (x *GetDraftPolicyRequest) Reset() { *x = GetDraftPolicyRequest{} - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[209] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16904,7 +16815,7 @@ func (x *GetDraftPolicyRequest) String() string { func (*GetDraftPolicyRequest) ProtoMessage() {} func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[209] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16917,7 +16828,7 @@ func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyRequest.ProtoReflect.Descriptor instead. func (*GetDraftPolicyRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{210} + return file_openshell_proto_rawDescGZIP(), []int{209} } func (x *GetDraftPolicyRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16957,7 +16868,7 @@ type GetDraftPolicyResponse struct { func (x *GetDraftPolicyResponse) Reset() { *x = GetDraftPolicyResponse{} - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[210] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16969,7 +16880,7 @@ func (x *GetDraftPolicyResponse) String() string { func (*GetDraftPolicyResponse) ProtoMessage() {} func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[210] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16982,7 +16893,7 @@ func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyResponse.ProtoReflect.Descriptor instead. func (*GetDraftPolicyResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{211} + return file_openshell_proto_rawDescGZIP(), []int{210} } func (x *GetDraftPolicyResponse) GetChunks() []*PolicyChunk { @@ -17033,7 +16944,7 @@ type ApproveDraftChunkRequest struct { func (x *ApproveDraftChunkRequest) Reset() { *x = ApproveDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[211] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17045,7 +16956,7 @@ func (x *ApproveDraftChunkRequest) String() string { func (*ApproveDraftChunkRequest) ProtoMessage() {} func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[211] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17058,7 +16969,7 @@ func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkRequest.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{212} + return file_openshell_proto_rawDescGZIP(), []int{211} } func (x *ApproveDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17108,7 +17019,7 @@ type ApproveDraftChunkResponse struct { func (x *ApproveDraftChunkResponse) Reset() { *x = ApproveDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[212] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17120,7 +17031,7 @@ func (x *ApproveDraftChunkResponse) String() string { func (*ApproveDraftChunkResponse) ProtoMessage() {} func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[212] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17133,7 +17044,7 @@ func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkResponse.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{213} + return file_openshell_proto_rawDescGZIP(), []int{212} } func (x *ApproveDraftChunkResponse) GetPolicyVersion() uint32 { @@ -17169,7 +17080,7 @@ type RejectDraftChunkRequest struct { func (x *RejectDraftChunkRequest) Reset() { *x = RejectDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[213] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17181,7 +17092,7 @@ func (x *RejectDraftChunkRequest) String() string { func (*RejectDraftChunkRequest) ProtoMessage() {} func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[213] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17194,7 +17105,7 @@ func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkRequest.ProtoReflect.Descriptor instead. func (*RejectDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{214} + return file_openshell_proto_rawDescGZIP(), []int{213} } func (x *RejectDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17240,7 +17151,7 @@ type RejectDraftChunkResponse struct { func (x *RejectDraftChunkResponse) Reset() { *x = RejectDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[214] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17252,7 +17163,7 @@ func (x *RejectDraftChunkResponse) String() string { func (*RejectDraftChunkResponse) ProtoMessage() {} func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[214] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17265,7 +17176,7 @@ func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkResponse.ProtoReflect.Descriptor instead. func (*RejectDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{215} + return file_openshell_proto_rawDescGZIP(), []int{214} } // Approve all pending chunks. @@ -17279,7 +17190,7 @@ type DraftChunkApproval struct { func (x *DraftChunkApproval) Reset() { *x = DraftChunkApproval{} - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[215] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17291,7 +17202,7 @@ func (x *DraftChunkApproval) String() string { func (*DraftChunkApproval) ProtoMessage() {} func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[215] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17304,7 +17215,7 @@ func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftChunkApproval.ProtoReflect.Descriptor instead. func (*DraftChunkApproval) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{216} + return file_openshell_proto_rawDescGZIP(), []int{215} } func (x *DraftChunkApproval) GetChunkId() string { @@ -17340,7 +17251,7 @@ type ApproveAllDraftChunksRequest struct { func (x *ApproveAllDraftChunksRequest) Reset() { *x = ApproveAllDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[216] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17352,7 +17263,7 @@ func (x *ApproveAllDraftChunksRequest) String() string { func (*ApproveAllDraftChunksRequest) ProtoMessage() {} func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[216] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17365,7 +17276,7 @@ func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{217} + return file_openshell_proto_rawDescGZIP(), []int{216} } func (x *ApproveAllDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17420,7 +17331,7 @@ type ApproveAllDraftChunksResponse struct { func (x *ApproveAllDraftChunksResponse) Reset() { *x = ApproveAllDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[217] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17432,7 +17343,7 @@ func (x *ApproveAllDraftChunksResponse) String() string { func (*ApproveAllDraftChunksResponse) ProtoMessage() {} func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[217] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17445,7 +17356,7 @@ func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{218} + return file_openshell_proto_rawDescGZIP(), []int{217} } func (x *ApproveAllDraftChunksResponse) GetPolicyVersion() uint32 { @@ -17495,7 +17406,7 @@ type EditDraftChunkRequest struct { func (x *EditDraftChunkRequest) Reset() { *x = EditDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[218] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17507,7 +17418,7 @@ func (x *EditDraftChunkRequest) String() string { func (*EditDraftChunkRequest) ProtoMessage() {} func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[218] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17520,7 +17431,7 @@ func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkRequest.ProtoReflect.Descriptor instead. func (*EditDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{219} + return file_openshell_proto_rawDescGZIP(), []int{218} } func (x *EditDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17566,7 +17477,7 @@ type EditDraftChunkResponse struct { func (x *EditDraftChunkResponse) Reset() { *x = EditDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[219] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17578,7 +17489,7 @@ func (x *EditDraftChunkResponse) String() string { func (*EditDraftChunkResponse) ProtoMessage() {} func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[219] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17591,7 +17502,7 @@ func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkResponse.ProtoReflect.Descriptor instead. func (*EditDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{220} + return file_openshell_proto_rawDescGZIP(), []int{219} } // Reverse an approval (remove merged rule from active policy). @@ -17611,7 +17522,7 @@ type UndoDraftChunkRequest struct { func (x *UndoDraftChunkRequest) Reset() { *x = UndoDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[220] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17623,7 +17534,7 @@ func (x *UndoDraftChunkRequest) String() string { func (*UndoDraftChunkRequest) ProtoMessage() {} func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[220] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17636,7 +17547,7 @@ func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkRequest.ProtoReflect.Descriptor instead. func (*UndoDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{221} + return file_openshell_proto_rawDescGZIP(), []int{220} } func (x *UndoDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17679,7 +17590,7 @@ type UndoDraftChunkResponse struct { func (x *UndoDraftChunkResponse) Reset() { *x = UndoDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[221] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17691,7 +17602,7 @@ func (x *UndoDraftChunkResponse) String() string { func (*UndoDraftChunkResponse) ProtoMessage() {} func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[221] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17704,7 +17615,7 @@ func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkResponse.ProtoReflect.Descriptor instead. func (*UndoDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{222} + return file_openshell_proto_rawDescGZIP(), []int{221} } func (x *UndoDraftChunkResponse) GetPolicyVersion() uint32 { @@ -17736,7 +17647,7 @@ type ClearDraftChunksRequest struct { func (x *ClearDraftChunksRequest) Reset() { *x = ClearDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[222] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17748,7 +17659,7 @@ func (x *ClearDraftChunksRequest) String() string { func (*ClearDraftChunksRequest) ProtoMessage() {} func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[222] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17761,7 +17672,7 @@ func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ClearDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{223} + return file_openshell_proto_rawDescGZIP(), []int{222} } func (x *ClearDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17795,7 +17706,7 @@ type ClearDraftChunksResponse struct { func (x *ClearDraftChunksResponse) Reset() { *x = ClearDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[223] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17807,7 +17718,7 @@ func (x *ClearDraftChunksResponse) String() string { func (*ClearDraftChunksResponse) ProtoMessage() {} func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[223] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17820,7 +17731,7 @@ func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ClearDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{224} + return file_openshell_proto_rawDescGZIP(), []int{223} } func (x *ClearDraftChunksResponse) GetChunksCleared() uint32 { @@ -17842,7 +17753,7 @@ type GetDraftHistoryRequest struct { func (x *GetDraftHistoryRequest) Reset() { *x = GetDraftHistoryRequest{} - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[224] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17854,7 +17765,7 @@ func (x *GetDraftHistoryRequest) String() string { func (*GetDraftHistoryRequest) ProtoMessage() {} func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[224] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17867,7 +17778,7 @@ func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryRequest.ProtoReflect.Descriptor instead. func (*GetDraftHistoryRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{225} + return file_openshell_proto_rawDescGZIP(), []int{224} } func (x *GetDraftHistoryRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17901,7 +17812,7 @@ type DraftHistoryEntry struct { func (x *DraftHistoryEntry) Reset() { *x = DraftHistoryEntry{} - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[225] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17913,7 +17824,7 @@ func (x *DraftHistoryEntry) String() string { func (*DraftHistoryEntry) ProtoMessage() {} func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[225] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17926,7 +17837,7 @@ func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftHistoryEntry.ProtoReflect.Descriptor instead. func (*DraftHistoryEntry) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{226} + return file_openshell_proto_rawDescGZIP(), []int{225} } func (x *DraftHistoryEntry) GetEventTime() *timestamppb.Timestamp { @@ -17967,7 +17878,7 @@ type GetDraftHistoryResponse struct { func (x *GetDraftHistoryResponse) Reset() { *x = GetDraftHistoryResponse{} - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[226] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17979,7 +17890,7 @@ func (x *GetDraftHistoryResponse) String() string { func (*GetDraftHistoryResponse) ProtoMessage() {} func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[226] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17992,7 +17903,7 @@ func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryResponse.ProtoReflect.Descriptor instead. func (*GetDraftHistoryResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{227} + return file_openshell_proto_rawDescGZIP(), []int{226} } func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry { @@ -18017,7 +17928,7 @@ type CreateWorkspaceRequest struct { func (x *CreateWorkspaceRequest) Reset() { *x = CreateWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[227] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18029,7 +17940,7 @@ func (x *CreateWorkspaceRequest) String() string { func (*CreateWorkspaceRequest) ProtoMessage() {} func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[227] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18042,7 +17953,7 @@ func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceRequest.ProtoReflect.Descriptor instead. func (*CreateWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{228} + return file_openshell_proto_rawDescGZIP(), []int{227} } func (x *CreateWorkspaceRequest) GetName() string { @@ -18076,7 +17987,7 @@ type CreateWorkspaceResponse struct { func (x *CreateWorkspaceResponse) Reset() { *x = CreateWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[228] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18088,7 +17999,7 @@ func (x *CreateWorkspaceResponse) String() string { func (*CreateWorkspaceResponse) ProtoMessage() {} func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[228] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18101,7 +18012,7 @@ func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceResponse.ProtoReflect.Descriptor instead. func (*CreateWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{229} + return file_openshell_proto_rawDescGZIP(), []int{228} } func (x *CreateWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -18122,7 +18033,7 @@ type GetWorkspaceRequest struct { func (x *GetWorkspaceRequest) Reset() { *x = GetWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[229] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18134,7 +18045,7 @@ func (x *GetWorkspaceRequest) String() string { func (*GetWorkspaceRequest) ProtoMessage() {} func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[229] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18147,7 +18058,7 @@ func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceRequest.ProtoReflect.Descriptor instead. func (*GetWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{230} + return file_openshell_proto_rawDescGZIP(), []int{229} } func (x *GetWorkspaceRequest) GetName() string { @@ -18167,7 +18078,7 @@ type GetWorkspaceResponse struct { func (x *GetWorkspaceResponse) Reset() { *x = GetWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[231] + mi := &file_openshell_proto_msgTypes[230] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18179,7 +18090,7 @@ func (x *GetWorkspaceResponse) String() string { func (*GetWorkspaceResponse) ProtoMessage() {} func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[231] + mi := &file_openshell_proto_msgTypes[230] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18192,7 +18103,7 @@ func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceResponse.ProtoReflect.Descriptor instead. func (*GetWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{231} + return file_openshell_proto_rawDescGZIP(), []int{230} } func (x *GetWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -18219,7 +18130,7 @@ type ListWorkspacesRequest struct { func (x *ListWorkspacesRequest) Reset() { *x = ListWorkspacesRequest{} - mi := &file_openshell_proto_msgTypes[232] + mi := &file_openshell_proto_msgTypes[231] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18231,7 +18142,7 @@ func (x *ListWorkspacesRequest) String() string { func (*ListWorkspacesRequest) ProtoMessage() {} func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[232] + mi := &file_openshell_proto_msgTypes[231] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18244,7 +18155,7 @@ func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesRequest.ProtoReflect.Descriptor instead. func (*ListWorkspacesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{232} + return file_openshell_proto_rawDescGZIP(), []int{231} } func (x *ListWorkspacesRequest) GetPageSize() int32 { @@ -18280,7 +18191,7 @@ type ListWorkspacesResponse struct { func (x *ListWorkspacesResponse) Reset() { *x = ListWorkspacesResponse{} - mi := &file_openshell_proto_msgTypes[233] + mi := &file_openshell_proto_msgTypes[232] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18292,7 +18203,7 @@ func (x *ListWorkspacesResponse) String() string { func (*ListWorkspacesResponse) ProtoMessage() {} func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[233] + mi := &file_openshell_proto_msgTypes[232] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18305,7 +18216,7 @@ func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesResponse.ProtoReflect.Descriptor instead. func (*ListWorkspacesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{233} + return file_openshell_proto_rawDescGZIP(), []int{232} } func (x *ListWorkspacesResponse) GetWorkspaces() []*datamodelv1.Workspace { @@ -18336,7 +18247,7 @@ type DeleteWorkspaceRequest struct { func (x *DeleteWorkspaceRequest) Reset() { *x = DeleteWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[234] + mi := &file_openshell_proto_msgTypes[233] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18348,7 +18259,7 @@ func (x *DeleteWorkspaceRequest) String() string { func (*DeleteWorkspaceRequest) ProtoMessage() {} func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[234] + mi := &file_openshell_proto_msgTypes[233] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18361,7 +18272,7 @@ func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{234} + return file_openshell_proto_rawDescGZIP(), []int{233} } func (x *DeleteWorkspaceRequest) GetName() string { @@ -18395,7 +18306,7 @@ type DeleteWorkspaceResponse struct { func (x *DeleteWorkspaceResponse) Reset() { *x = DeleteWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[235] + mi := &file_openshell_proto_msgTypes[234] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18407,7 +18318,7 @@ func (x *DeleteWorkspaceResponse) String() string { func (*DeleteWorkspaceResponse) ProtoMessage() {} func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[235] + mi := &file_openshell_proto_msgTypes[234] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18420,7 +18331,7 @@ func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceResponse.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{235} + return file_openshell_proto_rawDescGZIP(), []int{234} } func (x *DeleteWorkspaceResponse) GetOutcome() DeletionOutcome { @@ -18444,7 +18355,7 @@ type WorkspaceMember struct { func (x *WorkspaceMember) Reset() { *x = WorkspaceMember{} - mi := &file_openshell_proto_msgTypes[236] + mi := &file_openshell_proto_msgTypes[235] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18456,7 +18367,7 @@ func (x *WorkspaceMember) String() string { func (*WorkspaceMember) ProtoMessage() {} func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[236] + mi := &file_openshell_proto_msgTypes[235] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18469,7 +18380,7 @@ func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkspaceMember.ProtoReflect.Descriptor instead. func (*WorkspaceMember) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{236} + return file_openshell_proto_rawDescGZIP(), []int{235} } func (x *WorkspaceMember) GetMetadata() *datamodelv1.ObjectMeta { @@ -18510,7 +18421,7 @@ type AddWorkspaceMemberRequest struct { func (x *AddWorkspaceMemberRequest) Reset() { *x = AddWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[237] + mi := &file_openshell_proto_msgTypes[236] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18522,7 +18433,7 @@ func (x *AddWorkspaceMemberRequest) String() string { func (*AddWorkspaceMemberRequest) ProtoMessage() {} func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[237] + mi := &file_openshell_proto_msgTypes[236] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18535,7 +18446,7 @@ func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{237} + return file_openshell_proto_rawDescGZIP(), []int{236} } func (x *AddWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18576,7 +18487,7 @@ type AddWorkspaceMemberResponse struct { func (x *AddWorkspaceMemberResponse) Reset() { *x = AddWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[238] + mi := &file_openshell_proto_msgTypes[237] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18588,7 +18499,7 @@ func (x *AddWorkspaceMemberResponse) String() string { func (*AddWorkspaceMemberResponse) ProtoMessage() {} func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[238] + mi := &file_openshell_proto_msgTypes[237] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18601,7 +18512,7 @@ func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{238} + return file_openshell_proto_rawDescGZIP(), []int{237} } func (x *AddWorkspaceMemberResponse) GetMember() *WorkspaceMember { @@ -18627,7 +18538,7 @@ type RemoveWorkspaceMemberRequest struct { func (x *RemoveWorkspaceMemberRequest) Reset() { *x = RemoveWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[239] + mi := &file_openshell_proto_msgTypes[238] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18639,7 +18550,7 @@ func (x *RemoveWorkspaceMemberRequest) String() string { func (*RemoveWorkspaceMemberRequest) ProtoMessage() {} func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[239] + mi := &file_openshell_proto_msgTypes[238] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18652,7 +18563,7 @@ func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{239} + return file_openshell_proto_rawDescGZIP(), []int{238} } func (x *RemoveWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18693,7 +18604,7 @@ type RemoveWorkspaceMemberResponse struct { func (x *RemoveWorkspaceMemberResponse) Reset() { *x = RemoveWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[240] + mi := &file_openshell_proto_msgTypes[239] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18705,7 +18616,7 @@ func (x *RemoveWorkspaceMemberResponse) String() string { func (*RemoveWorkspaceMemberResponse) ProtoMessage() {} func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[240] + mi := &file_openshell_proto_msgTypes[239] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18718,7 +18629,7 @@ func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{240} + return file_openshell_proto_rawDescGZIP(), []int{239} } func (x *RemoveWorkspaceMemberResponse) GetOutcome() DeletionOutcome { @@ -18745,7 +18656,7 @@ type ListWorkspaceMembersRequest struct { func (x *ListWorkspaceMembersRequest) Reset() { *x = ListWorkspaceMembersRequest{} - mi := &file_openshell_proto_msgTypes[241] + mi := &file_openshell_proto_msgTypes[240] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18757,7 +18668,7 @@ func (x *ListWorkspaceMembersRequest) String() string { func (*ListWorkspaceMembersRequest) ProtoMessage() {} func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[241] + mi := &file_openshell_proto_msgTypes[240] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18770,7 +18681,7 @@ func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersRequest.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{241} + return file_openshell_proto_rawDescGZIP(), []int{240} } func (x *ListWorkspaceMembersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18806,7 +18717,7 @@ type ListWorkspaceMembersResponse struct { func (x *ListWorkspaceMembersResponse) Reset() { *x = ListWorkspaceMembersResponse{} - mi := &file_openshell_proto_msgTypes[242] + mi := &file_openshell_proto_msgTypes[241] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18818,7 +18729,7 @@ func (x *ListWorkspaceMembersResponse) String() string { func (*ListWorkspaceMembersResponse) ProtoMessage() {} func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[242] + mi := &file_openshell_proto_msgTypes[241] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18831,7 +18742,7 @@ func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersResponse.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{242} + return file_openshell_proto_rawDescGZIP(), []int{241} } func (x *ListWorkspaceMembersResponse) GetMembers() []*WorkspaceMember { @@ -18866,7 +18777,7 @@ type ExtensionServiceCredential struct { func (x *ExtensionServiceCredential) Reset() { *x = ExtensionServiceCredential{} - mi := &file_openshell_proto_msgTypes[243] + mi := &file_openshell_proto_msgTypes[242] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18878,7 +18789,7 @@ func (x *ExtensionServiceCredential) String() string { func (*ExtensionServiceCredential) ProtoMessage() {} func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[243] + mi := &file_openshell_proto_msgTypes[242] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18891,7 +18802,7 @@ func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionServiceCredential.ProtoReflect.Descriptor instead. func (*ExtensionServiceCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{243} + return file_openshell_proto_rawDescGZIP(), []int{242} } func (x *ExtensionServiceCredential) GetServiceName() string { @@ -18931,7 +18842,7 @@ type EndpointObservation struct { func (x *EndpointObservation) Reset() { *x = EndpointObservation{} - mi := &file_openshell_proto_msgTypes[244] + mi := &file_openshell_proto_msgTypes[243] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18943,7 +18854,7 @@ func (x *EndpointObservation) String() string { func (*EndpointObservation) ProtoMessage() {} func (x *EndpointObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[244] + mi := &file_openshell_proto_msgTypes[243] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18956,7 +18867,7 @@ func (x *EndpointObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointObservation.ProtoReflect.Descriptor instead. func (*EndpointObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{244} + return file_openshell_proto_rawDescGZIP(), []int{243} } func (x *EndpointObservation) GetEndpointId() string { @@ -19009,7 +18920,7 @@ type ReportEndpointStatusRequest struct { func (x *ReportEndpointStatusRequest) Reset() { *x = ReportEndpointStatusRequest{} - mi := &file_openshell_proto_msgTypes[245] + mi := &file_openshell_proto_msgTypes[244] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19021,7 +18932,7 @@ func (x *ReportEndpointStatusRequest) String() string { func (*ReportEndpointStatusRequest) ProtoMessage() {} func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[245] + mi := &file_openshell_proto_msgTypes[244] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19034,7 +18945,7 @@ func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusRequest.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{245} + return file_openshell_proto_rawDescGZIP(), []int{244} } func (x *ReportEndpointStatusRequest) GetSandboxId() string { @@ -19103,7 +19014,7 @@ type TokenGrantStatus struct { func (x *TokenGrantStatus) Reset() { *x = TokenGrantStatus{} - mi := &file_openshell_proto_msgTypes[246] + mi := &file_openshell_proto_msgTypes[245] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19115,7 +19026,7 @@ func (x *TokenGrantStatus) String() string { func (*TokenGrantStatus) ProtoMessage() {} func (x *TokenGrantStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[246] + mi := &file_openshell_proto_msgTypes[245] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19128,7 +19039,7 @@ func (x *TokenGrantStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use TokenGrantStatus.ProtoReflect.Descriptor instead. func (*TokenGrantStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{246} + return file_openshell_proto_rawDescGZIP(), []int{245} } func (x *TokenGrantStatus) GetLastFailure() *TokenGrantFailureObservation { @@ -19155,7 +19066,7 @@ type TokenGrantFailureObservation struct { func (x *TokenGrantFailureObservation) Reset() { *x = TokenGrantFailureObservation{} - mi := &file_openshell_proto_msgTypes[247] + mi := &file_openshell_proto_msgTypes[246] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19167,7 +19078,7 @@ func (x *TokenGrantFailureObservation) String() string { func (*TokenGrantFailureObservation) ProtoMessage() {} func (x *TokenGrantFailureObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[247] + mi := &file_openshell_proto_msgTypes[246] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19180,7 +19091,7 @@ func (x *TokenGrantFailureObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use TokenGrantFailureObservation.ProtoReflect.Descriptor instead. func (*TokenGrantFailureObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{247} + return file_openshell_proto_rawDescGZIP(), []int{246} } func (x *TokenGrantFailureObservation) GetDestinationHost() string { @@ -19213,7 +19124,7 @@ type ReportEndpointStatusResponse struct { func (x *ReportEndpointStatusResponse) Reset() { *x = ReportEndpointStatusResponse{} - mi := &file_openshell_proto_msgTypes[248] + mi := &file_openshell_proto_msgTypes[247] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19225,7 +19136,7 @@ func (x *ReportEndpointStatusResponse) String() string { func (*ReportEndpointStatusResponse) ProtoMessage() {} func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[248] + mi := &file_openshell_proto_msgTypes[247] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19238,7 +19149,7 @@ func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusResponse.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{248} + return file_openshell_proto_rawDescGZIP(), []int{247} } // A configured endpoint and its last accepted network result in one record. @@ -19272,7 +19183,7 @@ type EndpointStatus struct { func (x *EndpointStatus) Reset() { *x = EndpointStatus{} - mi := &file_openshell_proto_msgTypes[249] + mi := &file_openshell_proto_msgTypes[248] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19284,7 +19195,7 @@ func (x *EndpointStatus) String() string { func (*EndpointStatus) ProtoMessage() {} func (x *EndpointStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[249] + mi := &file_openshell_proto_msgTypes[248] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19297,7 +19208,7 @@ func (x *EndpointStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointStatus.ProtoReflect.Descriptor instead. func (*EndpointStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{249} + return file_openshell_proto_rawDescGZIP(), []int{248} } func (x *EndpointStatus) GetEndpointId() string { @@ -19392,7 +19303,7 @@ type SandboxProvisioning struct { func (x *SandboxProvisioning) Reset() { *x = SandboxProvisioning{} - mi := &file_openshell_proto_msgTypes[250] + mi := &file_openshell_proto_msgTypes[249] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19404,7 +19315,7 @@ func (x *SandboxProvisioning) String() string { func (*SandboxProvisioning) ProtoMessage() {} func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[250] + mi := &file_openshell_proto_msgTypes[249] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19417,7 +19328,7 @@ func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxProvisioning.ProtoReflect.Descriptor instead. func (*SandboxProvisioning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{250} + return file_openshell_proto_rawDescGZIP(), []int{249} } func (x *SandboxProvisioning) GetAttemptId() string { @@ -19540,7 +19451,7 @@ type SandboxServiceExposure struct { func (x *SandboxServiceExposure) Reset() { *x = SandboxServiceExposure{} - mi := &file_openshell_proto_msgTypes[251] + mi := &file_openshell_proto_msgTypes[250] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19552,7 +19463,7 @@ func (x *SandboxServiceExposure) String() string { func (*SandboxServiceExposure) ProtoMessage() {} func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[251] + mi := &file_openshell_proto_msgTypes[250] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19565,7 +19476,7 @@ func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxServiceExposure.ProtoReflect.Descriptor instead. func (*SandboxServiceExposure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{251} + return file_openshell_proto_rawDescGZIP(), []int{250} } func (x *SandboxServiceExposure) GetService() string { @@ -19619,7 +19530,7 @@ type EndpointFailure struct { func (x *EndpointFailure) Reset() { *x = EndpointFailure{} - mi := &file_openshell_proto_msgTypes[252] + mi := &file_openshell_proto_msgTypes[251] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19631,7 +19542,7 @@ func (x *EndpointFailure) String() string { func (*EndpointFailure) ProtoMessage() {} func (x *EndpointFailure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[252] + mi := &file_openshell_proto_msgTypes[251] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19644,7 +19555,7 @@ func (x *EndpointFailure) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointFailure.ProtoReflect.Descriptor instead. func (*EndpointFailure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{252} + return file_openshell_proto_rawDescGZIP(), []int{251} } func (x *EndpointFailure) GetDomain() EndpointFailureDomain { @@ -19844,7 +19755,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\"\xde\b\n" + + "\x10resource_version\x18\x02 \x01(\tR\x0fresourceVersion\"\xf2\a\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" + @@ -19865,17 +19776,10 @@ 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\x15lastTokenGrantFailure\x12C\n" + - "\fimage_update\x18\x12 \x01(\v2 .openshell.v1.SandboxImageUpdateR\vimageUpdate\x12%\n" + - "\x0eimage_revision\x18\x13 \x01(\x04R\rimageRevisionB\f\n" + + "\x18last_token_grant_failure\x18\x11 \x01(\v2*.openshell.v1.TokenGrantFailureObservationR\x15lastTokenGrantFailureB\f\n" + "\n" + "_exit_codeB\x1a\n" + - "\x18_configuration_activated\"\x90\x01\n" + - "\x12SandboxImageUpdate\x12!\n" + - "\foperation_id\x18\x01 \x01(\tR\voperationId\x12%\n" + - "\x0eprevious_image\x18\x02 \x01(\tR\rpreviousImage\x12\x14\n" + - "\x05image\x18\x03 \x01(\tR\x05image\x12\x1a\n" + - "\brevision\x18\x04 \x01(\x04R\brevision\"\xd1\x01\n" + + "\x18_configuration_activated\"\xd1\x01\n" + "\x10SandboxCondition\x12\x12\n" + "\x04type\x18\x01 \x01(\tR\x04type\x12\x16\n" + "\x06status\x18\x02 \x01(\tR\x06status\x12\x16\n" + @@ -21331,7 +21235,7 @@ const file_openshell_proto_rawDesc = "" + "-SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH\x10\x02*i\n" + "\x15EndpointFailureDomain\x12'\n" + "#ENDPOINT_FAILURE_DOMAIN_UNSPECIFIED\x10\x00\x12'\n" + - "#ENDPOINT_FAILURE_DOMAIN_TOKEN_GRANT\x10\x012\x9dZ\n" + + "#ENDPOINT_FAILURE_DOMAIN_TOKEN_GRANT\x10\x012\xa6Y\n" + "\tOpenShell\x12Z\n" + "\x06Health\x12\x1b.openshell.v1.HealthRequest\x1a\x1c.openshell.v1.HealthResponse\"\x15\x82\xb5\x18\x11\n" + "\x0funauthenticated\x12i\n" + @@ -21340,8 +21244,6 @@ const file_openshell_proto_rawDesc = "" + "\x0eGetGatewayInfo\x12#.openshell.v1.GetGatewayInfoRequest\x1a$.openshell.v1.GetGatewayInfoResponse\")\x82\xb5\x18%\n" + "\x06bearer\x1a\x0eplatform_admin\"\vconfig:read\x12u\n" + "\rCreateSandbox\x12\".openshell.v1.CreateSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\"!\x82\xb5\x18\x1d\n" + - "\x06bearer\x12\x04user\"\rsandbox:write\x12u\n" + - "\rUpdateSandbox\x12\".openshell.v1.UpdateSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\"!\x82\xb5\x18\x1d\n" + "\x06bearer\x12\x04user\"\rsandbox:write\x12\x93\x01\n" + "\x15BeginRootfsTarStaging\x12*.openshell.v1.BeginRootfsTarStagingRequest\x1a+.openshell.v1.BeginRootfsTarStagingResponse\"!\x82\xb5\x18\x1d\n" + "\x06bearer\x12\x04user\"\rsandbox:write\x12n\n" + @@ -21515,7 +21417,10 @@ const file_openshell_proto_rawDesc = "" + "\x15RemoveWorkspaceMember\x12*.openshell.v1.RemoveWorkspaceMemberRequest\x1a+.openshell.v1.RemoveWorkspaceMemberResponse\"$\x82\xb5\x18 \n" + "\x06bearer\x12\x05admin\"\x0fworkspace:write\x12\x91\x01\n" + "\x14ListWorkspaceMembers\x12).openshell.v1.ListWorkspaceMembersRequest\x1a*.openshell.v1.ListWorkspaceMembersResponse\"\"\x82\xb5\x18\x1e\n" + - "\x06bearer\x12\x04user\"\x0eworkspace:readb\x06proto3" + "\x06bearer\x12\x04user\"\x0eworkspace:read2\x87\x01\n" + + "\x0eSandboxUpdates\x12u\n" + + "\rUpdateSandbox\x12\".openshell.v1.UpdateSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\"!\x82\xb5\x18\x1d\n" + + "\x06bearer\x12\x04user\"\rsandbox:writeb\x06proto3" var ( file_openshell_proto_rawDescOnce sync.Once @@ -21530,7 +21435,7 @@ func file_openshell_proto_rawDescGZIP() []byte { } var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 22) -var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 279) +var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 278) var file_openshell_proto_goTypes = []any{ (ExtensionKind)(0), // 0: openshell.v1.ExtensionKind (SandboxPhase)(0), // 1: openshell.v1.SandboxPhase @@ -21584,281 +21489,280 @@ var file_openshell_proto_goTypes = []any{ (*SandboxStartup)(nil), // 49: openshell.v1.SandboxStartup (*SandboxWorkloadTemplateProvenance)(nil), // 50: openshell.v1.SandboxWorkloadTemplateProvenance (*SandboxStatus)(nil), // 51: openshell.v1.SandboxStatus - (*SandboxImageUpdate)(nil), // 52: openshell.v1.SandboxImageUpdate - (*SandboxCondition)(nil), // 53: openshell.v1.SandboxCondition - (*PlatformEvent)(nil), // 54: openshell.v1.PlatformEvent - (*CreateSandboxRequest)(nil), // 55: openshell.v1.CreateSandboxRequest - (*UpdateSandboxRequest)(nil), // 56: openshell.v1.UpdateSandboxRequest - (*CreateSandboxTemplateRequest)(nil), // 57: openshell.v1.CreateSandboxTemplateRequest - (*GetSandboxTemplateRequest)(nil), // 58: openshell.v1.GetSandboxTemplateRequest - (*ListSandboxTemplatesRequest)(nil), // 59: openshell.v1.ListSandboxTemplatesRequest - (*DeleteSandboxTemplateRequest)(nil), // 60: openshell.v1.DeleteSandboxTemplateRequest - (*SandboxTemplateResponse)(nil), // 61: openshell.v1.SandboxTemplateResponse - (*ListSandboxTemplatesResponse)(nil), // 62: openshell.v1.ListSandboxTemplatesResponse - (*DeleteSandboxTemplateResponse)(nil), // 63: openshell.v1.DeleteSandboxTemplateResponse - (*BeginRootfsTarStagingRequest)(nil), // 64: openshell.v1.BeginRootfsTarStagingRequest - (*BeginRootfsTarStagingResponse)(nil), // 65: openshell.v1.BeginRootfsTarStagingResponse - (*GetSandboxRequest)(nil), // 66: openshell.v1.GetSandboxRequest - (*ListSandboxesRequest)(nil), // 67: openshell.v1.ListSandboxesRequest - (*ListSandboxProvidersRequest)(nil), // 68: openshell.v1.ListSandboxProvidersRequest - (*AttachSandboxProviderRequest)(nil), // 69: openshell.v1.AttachSandboxProviderRequest - (*DetachSandboxProviderRequest)(nil), // 70: openshell.v1.DetachSandboxProviderRequest - (*DeleteSandboxRequest)(nil), // 71: openshell.v1.DeleteSandboxRequest - (*StopSandboxRequest)(nil), // 72: openshell.v1.StopSandboxRequest - (*StartSandboxRequest)(nil), // 73: openshell.v1.StartSandboxRequest - (*SuspendSandboxRequest)(nil), // 74: openshell.v1.SuspendSandboxRequest - (*ResumeSandboxRequest)(nil), // 75: openshell.v1.ResumeSandboxRequest - (*SandboxResponse)(nil), // 76: openshell.v1.SandboxResponse - (*ListSandboxesResponse)(nil), // 77: openshell.v1.ListSandboxesResponse - (*ListSandboxProvidersResponse)(nil), // 78: openshell.v1.ListSandboxProvidersResponse - (*AttachSandboxProviderResponse)(nil), // 79: openshell.v1.AttachSandboxProviderResponse - (*DetachSandboxProviderResponse)(nil), // 80: openshell.v1.DetachSandboxProviderResponse - (*ProviderDesiredIdentity)(nil), // 81: openshell.v1.ProviderDesiredIdentity - (*ConfigSnapshotRevision)(nil), // 82: openshell.v1.ConfigSnapshotRevision - (*SandboxConfigRevision)(nil), // 83: openshell.v1.SandboxConfigRevision - (*ConfigUpdateOperation)(nil), // 84: openshell.v1.ConfigUpdateOperation - (*ProviderMutationReceipt)(nil), // 85: openshell.v1.ProviderMutationReceipt - (*ProviderReadinessObservation)(nil), // 86: openshell.v1.ProviderReadinessObservation - (*ProviderReadinessStatus)(nil), // 87: openshell.v1.ProviderReadinessStatus - (*GetSandboxProviderStatusRequest)(nil), // 88: openshell.v1.GetSandboxProviderStatusRequest - (*GetSandboxProviderStatusResponse)(nil), // 89: openshell.v1.GetSandboxProviderStatusResponse - (*ReportProviderReadinessRequest)(nil), // 90: openshell.v1.ReportProviderReadinessRequest - (*ReportProviderReadinessResponse)(nil), // 91: openshell.v1.ReportProviderReadinessResponse - (*DeleteSandboxResponse)(nil), // 92: openshell.v1.DeleteSandboxResponse - (*CreateSshSessionRequest)(nil), // 93: openshell.v1.CreateSshSessionRequest - (*CreateSshSessionResponse)(nil), // 94: openshell.v1.CreateSshSessionResponse - (*ExposeServiceRequest)(nil), // 95: openshell.v1.ExposeServiceRequest - (*GetServiceRequest)(nil), // 96: openshell.v1.GetServiceRequest - (*ListServicesRequest)(nil), // 97: openshell.v1.ListServicesRequest - (*ListServicesResponse)(nil), // 98: openshell.v1.ListServicesResponse - (*DeleteServiceRequest)(nil), // 99: openshell.v1.DeleteServiceRequest - (*DeleteServiceResponse)(nil), // 100: openshell.v1.DeleteServiceResponse - (*ServiceEndpoint)(nil), // 101: openshell.v1.ServiceEndpoint - (*ServiceEndpointResponse)(nil), // 102: openshell.v1.ServiceEndpointResponse - (*RevokeSshSessionRequest)(nil), // 103: openshell.v1.RevokeSshSessionRequest - (*RevokeSshSessionResponse)(nil), // 104: openshell.v1.RevokeSshSessionResponse - (*ExecSandboxRequest)(nil), // 105: openshell.v1.ExecSandboxRequest - (*ExecSandboxStdout)(nil), // 106: openshell.v1.ExecSandboxStdout - (*ExecSandboxStderr)(nil), // 107: openshell.v1.ExecSandboxStderr - (*ExecSandboxExit)(nil), // 108: openshell.v1.ExecSandboxExit - (*ExecSandboxEvent)(nil), // 109: openshell.v1.ExecSandboxEvent - (*TcpForwardInit)(nil), // 110: openshell.v1.TcpForwardInit - (*TcpForwardFrame)(nil), // 111: openshell.v1.TcpForwardFrame - (*ExecSandboxInput)(nil), // 112: openshell.v1.ExecSandboxInput - (*ExecSandboxWindowResize)(nil), // 113: openshell.v1.ExecSandboxWindowResize - (*SshSession)(nil), // 114: openshell.v1.SshSession - (*WatchSandboxRequest)(nil), // 115: openshell.v1.WatchSandboxRequest - (*SandboxStreamEvent)(nil), // 116: openshell.v1.SandboxStreamEvent - (*SandboxLogLine)(nil), // 117: openshell.v1.SandboxLogLine - (*SandboxStreamWarning)(nil), // 118: openshell.v1.SandboxStreamWarning - (*CreateProviderRequest)(nil), // 119: openshell.v1.CreateProviderRequest - (*GetProviderRequest)(nil), // 120: openshell.v1.GetProviderRequest - (*GetProviderCredentialsRequest)(nil), // 121: openshell.v1.GetProviderCredentialsRequest - (*ProviderCredentialValue)(nil), // 122: openshell.v1.ProviderCredentialValue - (*GetProviderCredentialsResponse)(nil), // 123: openshell.v1.GetProviderCredentialsResponse - (*ListProvidersRequest)(nil), // 124: openshell.v1.ListProvidersRequest - (*UpdateProviderRequest)(nil), // 125: openshell.v1.UpdateProviderRequest - (*DeleteProviderRequest)(nil), // 126: openshell.v1.DeleteProviderRequest - (*ProviderResponse)(nil), // 127: openshell.v1.ProviderResponse - (*ListProvidersResponse)(nil), // 128: openshell.v1.ListProvidersResponse - (*ListProviderProfilesRequest)(nil), // 129: openshell.v1.ListProviderProfilesRequest - (*GetProviderProfileRequest)(nil), // 130: openshell.v1.GetProviderProfileRequest - (*ProviderProfileImportItem)(nil), // 131: openshell.v1.ProviderProfileImportItem - (*ProviderProfileDiagnostic)(nil), // 132: openshell.v1.ProviderProfileDiagnostic - (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 133: openshell.v1.ProviderCredentialTokenGrantAudienceOverride - (*ProviderCredentialTokenGrantSubjectToken)(nil), // 134: openshell.v1.ProviderCredentialTokenGrantSubjectToken - (*ProviderCredentialTokenGrant)(nil), // 135: openshell.v1.ProviderCredentialTokenGrant - (*ProviderProfileCredential)(nil), // 136: openshell.v1.ProviderProfileCredential - (*ProviderCredentialRefreshMaterial)(nil), // 137: openshell.v1.ProviderCredentialRefreshMaterial - (*ProviderCredentialRefreshOutput)(nil), // 138: openshell.v1.ProviderCredentialRefreshOutput - (*ProviderCredentialRefresh)(nil), // 139: openshell.v1.ProviderCredentialRefresh - (*ProviderCredentialRefreshStatus)(nil), // 140: openshell.v1.ProviderCredentialRefreshStatus - (*ProviderProfileDiscovery)(nil), // 141: openshell.v1.ProviderProfileDiscovery - (*GetProviderRefreshStatusRequest)(nil), // 142: openshell.v1.GetProviderRefreshStatusRequest - (*GetProviderRefreshStatusResponse)(nil), // 143: openshell.v1.GetProviderRefreshStatusResponse - (*ConfigureProviderRefreshRequest)(nil), // 144: openshell.v1.ConfigureProviderRefreshRequest - (*ConfigureProviderRefreshResponse)(nil), // 145: openshell.v1.ConfigureProviderRefreshResponse - (*RotateProviderCredentialRequest)(nil), // 146: openshell.v1.RotateProviderCredentialRequest - (*RotateProviderCredentialResponse)(nil), // 147: openshell.v1.RotateProviderCredentialResponse - (*DeleteProviderRefreshRequest)(nil), // 148: openshell.v1.DeleteProviderRefreshRequest - (*DeleteProviderRefreshResponse)(nil), // 149: openshell.v1.DeleteProviderRefreshResponse - (*ProviderProfile)(nil), // 150: openshell.v1.ProviderProfile - (*ProviderProfileFile)(nil), // 151: openshell.v1.ProviderProfileFile - (*ProviderProfileResponse)(nil), // 152: openshell.v1.ProviderProfileResponse - (*ListProviderProfilesResponse)(nil), // 153: openshell.v1.ListProviderProfilesResponse - (*ImportProviderProfilesRequest)(nil), // 154: openshell.v1.ImportProviderProfilesRequest - (*ImportProviderProfilesResponse)(nil), // 155: openshell.v1.ImportProviderProfilesResponse - (*UpdateProviderProfilesRequest)(nil), // 156: openshell.v1.UpdateProviderProfilesRequest - (*UpdateProviderProfilesResponse)(nil), // 157: openshell.v1.UpdateProviderProfilesResponse - (*LintProviderProfilesRequest)(nil), // 158: openshell.v1.LintProviderProfilesRequest - (*LintProviderProfilesResponse)(nil), // 159: openshell.v1.LintProviderProfilesResponse - (*DeleteProviderResponse)(nil), // 160: openshell.v1.DeleteProviderResponse - (*DeleteProviderProfileRequest)(nil), // 161: openshell.v1.DeleteProviderProfileRequest - (*DeleteProviderProfileResponse)(nil), // 162: openshell.v1.DeleteProviderProfileResponse - (*GetSandboxProviderEnvironmentRequest)(nil), // 163: openshell.v1.GetSandboxProviderEnvironmentRequest - (*StaticCredentialEndpointBinding)(nil), // 164: openshell.v1.StaticCredentialEndpointBinding - (*StaticCredentialBinding)(nil), // 165: openshell.v1.StaticCredentialBinding - (*GetSandboxProviderEnvironmentResponse)(nil), // 166: openshell.v1.GetSandboxProviderEnvironmentResponse - (*ProviderEnvironmentValue)(nil), // 167: openshell.v1.ProviderEnvironmentValue - (*ProviderEnvironmentSnapshot)(nil), // 168: openshell.v1.ProviderEnvironmentSnapshot - (*ExchangeProviderSubjectTokenRequest)(nil), // 169: openshell.v1.ExchangeProviderSubjectTokenRequest - (*ExchangeProviderSubjectTokenResponse)(nil), // 170: openshell.v1.ExchangeProviderSubjectTokenResponse - (*UpdateConfigRequest)(nil), // 171: openshell.v1.UpdateConfigRequest - (*PolicyMergeOperation)(nil), // 172: openshell.v1.PolicyMergeOperation - (*AddNetworkRule)(nil), // 173: openshell.v1.AddNetworkRule - (*RemoveNetworkEndpoint)(nil), // 174: openshell.v1.RemoveNetworkEndpoint - (*RemoveNetworkRule)(nil), // 175: openshell.v1.RemoveNetworkRule - (*L7RuleTarget)(nil), // 176: openshell.v1.L7RuleTarget - (*AddDenyRules)(nil), // 177: openshell.v1.AddDenyRules - (*AddAllowRules)(nil), // 178: openshell.v1.AddAllowRules - (*RemoveNetworkBinary)(nil), // 179: openshell.v1.RemoveNetworkBinary - (*UpdateConfigResponse)(nil), // 180: openshell.v1.UpdateConfigResponse - (*GetSandboxPolicyStatusRequest)(nil), // 181: openshell.v1.GetSandboxPolicyStatusRequest - (*GetSandboxPolicyStatusResponse)(nil), // 182: openshell.v1.GetSandboxPolicyStatusResponse - (*ListSandboxPoliciesRequest)(nil), // 183: openshell.v1.ListSandboxPoliciesRequest - (*ListSandboxPoliciesResponse)(nil), // 184: openshell.v1.ListSandboxPoliciesResponse - (*ReportPolicyStatusRequest)(nil), // 185: openshell.v1.ReportPolicyStatusRequest - (*ReportPolicyStatusResponse)(nil), // 186: openshell.v1.ReportPolicyStatusResponse - (*SandboxConfigurationAdmission)(nil), // 187: openshell.v1.SandboxConfigurationAdmission - (*ReportSandboxConfigurationRequest)(nil), // 188: openshell.v1.ReportSandboxConfigurationRequest - (*ReportSandboxConfigurationResponse)(nil), // 189: openshell.v1.ReportSandboxConfigurationResponse - (*SandboxPolicyRevision)(nil), // 190: openshell.v1.SandboxPolicyRevision - (*GetSandboxLogsRequest)(nil), // 191: openshell.v1.GetSandboxLogsRequest - (*PushSandboxLogsRequest)(nil), // 192: openshell.v1.PushSandboxLogsRequest - (*PushSandboxLogsResponse)(nil), // 193: openshell.v1.PushSandboxLogsResponse - (*GetSandboxLogsResponse)(nil), // 194: openshell.v1.GetSandboxLogsResponse - (*SupervisorMessage)(nil), // 195: openshell.v1.SupervisorMessage - (*GatewayMessage)(nil), // 196: openshell.v1.GatewayMessage - (*SupervisorHello)(nil), // 197: openshell.v1.SupervisorHello - (*SessionAccepted)(nil), // 198: openshell.v1.SessionAccepted - (*ConfigUpdate)(nil), // 199: openshell.v1.ConfigUpdate - (*ConfigApplyFailure)(nil), // 200: openshell.v1.ConfigApplyFailure - (*ConfigUpdateResult)(nil), // 201: openshell.v1.ConfigUpdateResult - (*PolicyLoadResult)(nil), // 202: openshell.v1.PolicyLoadResult - (*SessionRejected)(nil), // 203: openshell.v1.SessionRejected - (*SessionRedirect)(nil), // 204: openshell.v1.SessionRedirect - (*SupervisorHeartbeat)(nil), // 205: openshell.v1.SupervisorHeartbeat - (*GatewayHeartbeat)(nil), // 206: openshell.v1.GatewayHeartbeat - (*ReportMainProcessExitRequest)(nil), // 207: openshell.v1.ReportMainProcessExitRequest - (*ReportMainProcessExitResponse)(nil), // 208: openshell.v1.ReportMainProcessExitResponse - (*FinalizeMainProcessExitRequest)(nil), // 209: openshell.v1.FinalizeMainProcessExitRequest - (*FinalizeMainProcessExitResponse)(nil), // 210: openshell.v1.FinalizeMainProcessExitResponse - (*RelayOpen)(nil), // 211: openshell.v1.RelayOpen - (*SshRelayTarget)(nil), // 212: openshell.v1.SshRelayTarget - (*TcpRelayTarget)(nil), // 213: openshell.v1.TcpRelayTarget - (*RelayInit)(nil), // 214: openshell.v1.RelayInit - (*RelayFrame)(nil), // 215: openshell.v1.RelayFrame - (*PeerRelayInit)(nil), // 216: openshell.v1.PeerRelayInit - (*PeerRelayFrame)(nil), // 217: openshell.v1.PeerRelayFrame - (*PeerConfigSandboxTarget)(nil), // 218: openshell.v1.PeerConfigSandboxTarget - (*PeerConfigProviderTarget)(nil), // 219: openshell.v1.PeerConfigProviderTarget - (*PeerNotifyConfigUpdateRequest)(nil), // 220: openshell.v1.PeerNotifyConfigUpdateRequest - (*PeerNotifyConfigUpdateResponse)(nil), // 221: openshell.v1.PeerNotifyConfigUpdateResponse - (*RelayOpenResult)(nil), // 222: openshell.v1.RelayOpenResult - (*RelayClose)(nil), // 223: openshell.v1.RelayClose - (*L7RequestSample)(nil), // 224: openshell.v1.L7RequestSample - (*DenialSummary)(nil), // 225: openshell.v1.DenialSummary - (*DenialGroupCount)(nil), // 226: openshell.v1.DenialGroupCount - (*NetworkActivitySummary)(nil), // 227: openshell.v1.NetworkActivitySummary - (*PolicyChunk)(nil), // 228: openshell.v1.PolicyChunk - (*DraftPolicyUpdate)(nil), // 229: openshell.v1.DraftPolicyUpdate - (*SubmitPolicyAnalysisRequest)(nil), // 230: openshell.v1.SubmitPolicyAnalysisRequest - (*SubmitPolicyAnalysisResponse)(nil), // 231: openshell.v1.SubmitPolicyAnalysisResponse - (*GetDraftPolicyRequest)(nil), // 232: openshell.v1.GetDraftPolicyRequest - (*GetDraftPolicyResponse)(nil), // 233: openshell.v1.GetDraftPolicyResponse - (*ApproveDraftChunkRequest)(nil), // 234: openshell.v1.ApproveDraftChunkRequest - (*ApproveDraftChunkResponse)(nil), // 235: openshell.v1.ApproveDraftChunkResponse - (*RejectDraftChunkRequest)(nil), // 236: openshell.v1.RejectDraftChunkRequest - (*RejectDraftChunkResponse)(nil), // 237: openshell.v1.RejectDraftChunkResponse - (*DraftChunkApproval)(nil), // 238: openshell.v1.DraftChunkApproval - (*ApproveAllDraftChunksRequest)(nil), // 239: openshell.v1.ApproveAllDraftChunksRequest - (*ApproveAllDraftChunksResponse)(nil), // 240: openshell.v1.ApproveAllDraftChunksResponse - (*EditDraftChunkRequest)(nil), // 241: openshell.v1.EditDraftChunkRequest - (*EditDraftChunkResponse)(nil), // 242: openshell.v1.EditDraftChunkResponse - (*UndoDraftChunkRequest)(nil), // 243: openshell.v1.UndoDraftChunkRequest - (*UndoDraftChunkResponse)(nil), // 244: openshell.v1.UndoDraftChunkResponse - (*ClearDraftChunksRequest)(nil), // 245: openshell.v1.ClearDraftChunksRequest - (*ClearDraftChunksResponse)(nil), // 246: openshell.v1.ClearDraftChunksResponse - (*GetDraftHistoryRequest)(nil), // 247: openshell.v1.GetDraftHistoryRequest - (*DraftHistoryEntry)(nil), // 248: openshell.v1.DraftHistoryEntry - (*GetDraftHistoryResponse)(nil), // 249: openshell.v1.GetDraftHistoryResponse - (*CreateWorkspaceRequest)(nil), // 250: openshell.v1.CreateWorkspaceRequest - (*CreateWorkspaceResponse)(nil), // 251: openshell.v1.CreateWorkspaceResponse - (*GetWorkspaceRequest)(nil), // 252: openshell.v1.GetWorkspaceRequest - (*GetWorkspaceResponse)(nil), // 253: openshell.v1.GetWorkspaceResponse - (*ListWorkspacesRequest)(nil), // 254: openshell.v1.ListWorkspacesRequest - (*ListWorkspacesResponse)(nil), // 255: openshell.v1.ListWorkspacesResponse - (*DeleteWorkspaceRequest)(nil), // 256: openshell.v1.DeleteWorkspaceRequest - (*DeleteWorkspaceResponse)(nil), // 257: openshell.v1.DeleteWorkspaceResponse - (*WorkspaceMember)(nil), // 258: openshell.v1.WorkspaceMember - (*AddWorkspaceMemberRequest)(nil), // 259: openshell.v1.AddWorkspaceMemberRequest - (*AddWorkspaceMemberResponse)(nil), // 260: openshell.v1.AddWorkspaceMemberResponse - (*RemoveWorkspaceMemberRequest)(nil), // 261: openshell.v1.RemoveWorkspaceMemberRequest - (*RemoveWorkspaceMemberResponse)(nil), // 262: openshell.v1.RemoveWorkspaceMemberResponse - (*ListWorkspaceMembersRequest)(nil), // 263: openshell.v1.ListWorkspaceMembersRequest - (*ListWorkspaceMembersResponse)(nil), // 264: openshell.v1.ListWorkspaceMembersResponse - (*ExtensionServiceCredential)(nil), // 265: openshell.v1.ExtensionServiceCredential - (*EndpointObservation)(nil), // 266: openshell.v1.EndpointObservation - (*ReportEndpointStatusRequest)(nil), // 267: openshell.v1.ReportEndpointStatusRequest - (*TokenGrantStatus)(nil), // 268: openshell.v1.TokenGrantStatus - (*TokenGrantFailureObservation)(nil), // 269: openshell.v1.TokenGrantFailureObservation - (*ReportEndpointStatusResponse)(nil), // 270: openshell.v1.ReportEndpointStatusResponse - (*EndpointStatus)(nil), // 271: openshell.v1.EndpointStatus - (*SandboxProvisioning)(nil), // 272: openshell.v1.SandboxProvisioning - (*SandboxServiceExposure)(nil), // 273: openshell.v1.SandboxServiceExposure - (*EndpointFailure)(nil), // 274: openshell.v1.EndpointFailure - nil, // 275: openshell.v1.SandboxSpec.EnvironmentEntry - nil, // 276: openshell.v1.SandboxTemplate.LabelsEntry - nil, // 277: openshell.v1.SandboxTemplate.AnnotationsEntry - nil, // 278: openshell.v1.SandboxTemplate.EnvironmentEntry - nil, // 279: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - nil, // 280: openshell.v1.PlatformEvent.MetadataEntry - nil, // 281: openshell.v1.CreateSandboxRequest.LabelsEntry - nil, // 282: openshell.v1.CreateSandboxRequest.AnnotationsEntry - nil, // 283: openshell.v1.SandboxResponse.ServiceUrlsEntry - nil, // 284: openshell.v1.ExecSandboxRequest.EnvironmentEntry - nil, // 285: openshell.v1.SandboxLogLine.FieldsEntry - nil, // 286: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry - nil, // 287: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - nil, // 288: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - nil, // 289: openshell.v1.ProviderProfile.AnnotationsEntry - nil, // 290: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - nil, // 291: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - nil, // 292: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - nil, // 293: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - nil, // 294: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - nil, // 295: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry - nil, // 296: openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - nil, // 297: openshell.v1.UpdateConfigRequest.AnnotationsEntry - nil, // 298: openshell.v1.UpdateConfigResponse.AnnotationsEntry - nil, // 299: openshell.v1.SandboxPolicyRevision.ProvenanceEntry - nil, // 300: openshell.v1.CreateWorkspaceRequest.LabelsEntry - (*timestamppb.Timestamp)(nil), // 301: google.protobuf.Timestamp - (*datamodelv1.ObjectMeta)(nil), // 302: openshell.datamodel.v1.ObjectMeta - (*sandboxv1.SandboxPolicy)(nil), // 303: openshell.sandbox.v1.SandboxPolicy - (*structpb.Struct)(nil), // 304: google.protobuf.Struct - (*durationpb.Duration)(nil), // 305: google.protobuf.Duration - (*datamodelv1.WorkspaceSelector)(nil), // 306: openshell.datamodel.v1.WorkspaceSelector - (*datamodelv1.Provider)(nil), // 307: openshell.datamodel.v1.Provider - (sandboxv1.PolicySource)(0), // 308: openshell.sandbox.v1.PolicySource - (*sandboxv1.NetworkEndpoint)(nil), // 309: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 310: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 311: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 312: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 313: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 314: openshell.sandbox.v1.L7Rule - (*sandboxv1.SandboxConfigSnapshot)(nil), // 315: openshell.sandbox.v1.SandboxConfigSnapshot - (*datamodelv1.Workspace)(nil), // 316: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 317: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 318: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 319: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 320: openshell.sandbox.v1.GetGatewayConfigResponse + (*SandboxCondition)(nil), // 52: openshell.v1.SandboxCondition + (*PlatformEvent)(nil), // 53: openshell.v1.PlatformEvent + (*CreateSandboxRequest)(nil), // 54: openshell.v1.CreateSandboxRequest + (*UpdateSandboxRequest)(nil), // 55: openshell.v1.UpdateSandboxRequest + (*CreateSandboxTemplateRequest)(nil), // 56: openshell.v1.CreateSandboxTemplateRequest + (*GetSandboxTemplateRequest)(nil), // 57: openshell.v1.GetSandboxTemplateRequest + (*ListSandboxTemplatesRequest)(nil), // 58: openshell.v1.ListSandboxTemplatesRequest + (*DeleteSandboxTemplateRequest)(nil), // 59: openshell.v1.DeleteSandboxTemplateRequest + (*SandboxTemplateResponse)(nil), // 60: openshell.v1.SandboxTemplateResponse + (*ListSandboxTemplatesResponse)(nil), // 61: openshell.v1.ListSandboxTemplatesResponse + (*DeleteSandboxTemplateResponse)(nil), // 62: openshell.v1.DeleteSandboxTemplateResponse + (*BeginRootfsTarStagingRequest)(nil), // 63: openshell.v1.BeginRootfsTarStagingRequest + (*BeginRootfsTarStagingResponse)(nil), // 64: openshell.v1.BeginRootfsTarStagingResponse + (*GetSandboxRequest)(nil), // 65: openshell.v1.GetSandboxRequest + (*ListSandboxesRequest)(nil), // 66: openshell.v1.ListSandboxesRequest + (*ListSandboxProvidersRequest)(nil), // 67: openshell.v1.ListSandboxProvidersRequest + (*AttachSandboxProviderRequest)(nil), // 68: openshell.v1.AttachSandboxProviderRequest + (*DetachSandboxProviderRequest)(nil), // 69: openshell.v1.DetachSandboxProviderRequest + (*DeleteSandboxRequest)(nil), // 70: openshell.v1.DeleteSandboxRequest + (*StopSandboxRequest)(nil), // 71: openshell.v1.StopSandboxRequest + (*StartSandboxRequest)(nil), // 72: openshell.v1.StartSandboxRequest + (*SuspendSandboxRequest)(nil), // 73: openshell.v1.SuspendSandboxRequest + (*ResumeSandboxRequest)(nil), // 74: openshell.v1.ResumeSandboxRequest + (*SandboxResponse)(nil), // 75: openshell.v1.SandboxResponse + (*ListSandboxesResponse)(nil), // 76: openshell.v1.ListSandboxesResponse + (*ListSandboxProvidersResponse)(nil), // 77: openshell.v1.ListSandboxProvidersResponse + (*AttachSandboxProviderResponse)(nil), // 78: openshell.v1.AttachSandboxProviderResponse + (*DetachSandboxProviderResponse)(nil), // 79: openshell.v1.DetachSandboxProviderResponse + (*ProviderDesiredIdentity)(nil), // 80: openshell.v1.ProviderDesiredIdentity + (*ConfigSnapshotRevision)(nil), // 81: openshell.v1.ConfigSnapshotRevision + (*SandboxConfigRevision)(nil), // 82: openshell.v1.SandboxConfigRevision + (*ConfigUpdateOperation)(nil), // 83: openshell.v1.ConfigUpdateOperation + (*ProviderMutationReceipt)(nil), // 84: openshell.v1.ProviderMutationReceipt + (*ProviderReadinessObservation)(nil), // 85: openshell.v1.ProviderReadinessObservation + (*ProviderReadinessStatus)(nil), // 86: openshell.v1.ProviderReadinessStatus + (*GetSandboxProviderStatusRequest)(nil), // 87: openshell.v1.GetSandboxProviderStatusRequest + (*GetSandboxProviderStatusResponse)(nil), // 88: openshell.v1.GetSandboxProviderStatusResponse + (*ReportProviderReadinessRequest)(nil), // 89: openshell.v1.ReportProviderReadinessRequest + (*ReportProviderReadinessResponse)(nil), // 90: openshell.v1.ReportProviderReadinessResponse + (*DeleteSandboxResponse)(nil), // 91: openshell.v1.DeleteSandboxResponse + (*CreateSshSessionRequest)(nil), // 92: openshell.v1.CreateSshSessionRequest + (*CreateSshSessionResponse)(nil), // 93: openshell.v1.CreateSshSessionResponse + (*ExposeServiceRequest)(nil), // 94: openshell.v1.ExposeServiceRequest + (*GetServiceRequest)(nil), // 95: openshell.v1.GetServiceRequest + (*ListServicesRequest)(nil), // 96: openshell.v1.ListServicesRequest + (*ListServicesResponse)(nil), // 97: openshell.v1.ListServicesResponse + (*DeleteServiceRequest)(nil), // 98: openshell.v1.DeleteServiceRequest + (*DeleteServiceResponse)(nil), // 99: openshell.v1.DeleteServiceResponse + (*ServiceEndpoint)(nil), // 100: openshell.v1.ServiceEndpoint + (*ServiceEndpointResponse)(nil), // 101: openshell.v1.ServiceEndpointResponse + (*RevokeSshSessionRequest)(nil), // 102: openshell.v1.RevokeSshSessionRequest + (*RevokeSshSessionResponse)(nil), // 103: openshell.v1.RevokeSshSessionResponse + (*ExecSandboxRequest)(nil), // 104: openshell.v1.ExecSandboxRequest + (*ExecSandboxStdout)(nil), // 105: openshell.v1.ExecSandboxStdout + (*ExecSandboxStderr)(nil), // 106: openshell.v1.ExecSandboxStderr + (*ExecSandboxExit)(nil), // 107: openshell.v1.ExecSandboxExit + (*ExecSandboxEvent)(nil), // 108: openshell.v1.ExecSandboxEvent + (*TcpForwardInit)(nil), // 109: openshell.v1.TcpForwardInit + (*TcpForwardFrame)(nil), // 110: openshell.v1.TcpForwardFrame + (*ExecSandboxInput)(nil), // 111: openshell.v1.ExecSandboxInput + (*ExecSandboxWindowResize)(nil), // 112: openshell.v1.ExecSandboxWindowResize + (*SshSession)(nil), // 113: openshell.v1.SshSession + (*WatchSandboxRequest)(nil), // 114: openshell.v1.WatchSandboxRequest + (*SandboxStreamEvent)(nil), // 115: openshell.v1.SandboxStreamEvent + (*SandboxLogLine)(nil), // 116: openshell.v1.SandboxLogLine + (*SandboxStreamWarning)(nil), // 117: openshell.v1.SandboxStreamWarning + (*CreateProviderRequest)(nil), // 118: openshell.v1.CreateProviderRequest + (*GetProviderRequest)(nil), // 119: openshell.v1.GetProviderRequest + (*GetProviderCredentialsRequest)(nil), // 120: openshell.v1.GetProviderCredentialsRequest + (*ProviderCredentialValue)(nil), // 121: openshell.v1.ProviderCredentialValue + (*GetProviderCredentialsResponse)(nil), // 122: openshell.v1.GetProviderCredentialsResponse + (*ListProvidersRequest)(nil), // 123: openshell.v1.ListProvidersRequest + (*UpdateProviderRequest)(nil), // 124: openshell.v1.UpdateProviderRequest + (*DeleteProviderRequest)(nil), // 125: openshell.v1.DeleteProviderRequest + (*ProviderResponse)(nil), // 126: openshell.v1.ProviderResponse + (*ListProvidersResponse)(nil), // 127: openshell.v1.ListProvidersResponse + (*ListProviderProfilesRequest)(nil), // 128: openshell.v1.ListProviderProfilesRequest + (*GetProviderProfileRequest)(nil), // 129: openshell.v1.GetProviderProfileRequest + (*ProviderProfileImportItem)(nil), // 130: openshell.v1.ProviderProfileImportItem + (*ProviderProfileDiagnostic)(nil), // 131: openshell.v1.ProviderProfileDiagnostic + (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 132: openshell.v1.ProviderCredentialTokenGrantAudienceOverride + (*ProviderCredentialTokenGrantSubjectToken)(nil), // 133: openshell.v1.ProviderCredentialTokenGrantSubjectToken + (*ProviderCredentialTokenGrant)(nil), // 134: openshell.v1.ProviderCredentialTokenGrant + (*ProviderProfileCredential)(nil), // 135: openshell.v1.ProviderProfileCredential + (*ProviderCredentialRefreshMaterial)(nil), // 136: openshell.v1.ProviderCredentialRefreshMaterial + (*ProviderCredentialRefreshOutput)(nil), // 137: openshell.v1.ProviderCredentialRefreshOutput + (*ProviderCredentialRefresh)(nil), // 138: openshell.v1.ProviderCredentialRefresh + (*ProviderCredentialRefreshStatus)(nil), // 139: openshell.v1.ProviderCredentialRefreshStatus + (*ProviderProfileDiscovery)(nil), // 140: openshell.v1.ProviderProfileDiscovery + (*GetProviderRefreshStatusRequest)(nil), // 141: openshell.v1.GetProviderRefreshStatusRequest + (*GetProviderRefreshStatusResponse)(nil), // 142: openshell.v1.GetProviderRefreshStatusResponse + (*ConfigureProviderRefreshRequest)(nil), // 143: openshell.v1.ConfigureProviderRefreshRequest + (*ConfigureProviderRefreshResponse)(nil), // 144: openshell.v1.ConfigureProviderRefreshResponse + (*RotateProviderCredentialRequest)(nil), // 145: openshell.v1.RotateProviderCredentialRequest + (*RotateProviderCredentialResponse)(nil), // 146: openshell.v1.RotateProviderCredentialResponse + (*DeleteProviderRefreshRequest)(nil), // 147: openshell.v1.DeleteProviderRefreshRequest + (*DeleteProviderRefreshResponse)(nil), // 148: openshell.v1.DeleteProviderRefreshResponse + (*ProviderProfile)(nil), // 149: openshell.v1.ProviderProfile + (*ProviderProfileFile)(nil), // 150: openshell.v1.ProviderProfileFile + (*ProviderProfileResponse)(nil), // 151: openshell.v1.ProviderProfileResponse + (*ListProviderProfilesResponse)(nil), // 152: openshell.v1.ListProviderProfilesResponse + (*ImportProviderProfilesRequest)(nil), // 153: openshell.v1.ImportProviderProfilesRequest + (*ImportProviderProfilesResponse)(nil), // 154: openshell.v1.ImportProviderProfilesResponse + (*UpdateProviderProfilesRequest)(nil), // 155: openshell.v1.UpdateProviderProfilesRequest + (*UpdateProviderProfilesResponse)(nil), // 156: openshell.v1.UpdateProviderProfilesResponse + (*LintProviderProfilesRequest)(nil), // 157: openshell.v1.LintProviderProfilesRequest + (*LintProviderProfilesResponse)(nil), // 158: openshell.v1.LintProviderProfilesResponse + (*DeleteProviderResponse)(nil), // 159: openshell.v1.DeleteProviderResponse + (*DeleteProviderProfileRequest)(nil), // 160: openshell.v1.DeleteProviderProfileRequest + (*DeleteProviderProfileResponse)(nil), // 161: openshell.v1.DeleteProviderProfileResponse + (*GetSandboxProviderEnvironmentRequest)(nil), // 162: openshell.v1.GetSandboxProviderEnvironmentRequest + (*StaticCredentialEndpointBinding)(nil), // 163: openshell.v1.StaticCredentialEndpointBinding + (*StaticCredentialBinding)(nil), // 164: openshell.v1.StaticCredentialBinding + (*GetSandboxProviderEnvironmentResponse)(nil), // 165: openshell.v1.GetSandboxProviderEnvironmentResponse + (*ProviderEnvironmentValue)(nil), // 166: openshell.v1.ProviderEnvironmentValue + (*ProviderEnvironmentSnapshot)(nil), // 167: openshell.v1.ProviderEnvironmentSnapshot + (*ExchangeProviderSubjectTokenRequest)(nil), // 168: openshell.v1.ExchangeProviderSubjectTokenRequest + (*ExchangeProviderSubjectTokenResponse)(nil), // 169: openshell.v1.ExchangeProviderSubjectTokenResponse + (*UpdateConfigRequest)(nil), // 170: openshell.v1.UpdateConfigRequest + (*PolicyMergeOperation)(nil), // 171: openshell.v1.PolicyMergeOperation + (*AddNetworkRule)(nil), // 172: openshell.v1.AddNetworkRule + (*RemoveNetworkEndpoint)(nil), // 173: openshell.v1.RemoveNetworkEndpoint + (*RemoveNetworkRule)(nil), // 174: openshell.v1.RemoveNetworkRule + (*L7RuleTarget)(nil), // 175: openshell.v1.L7RuleTarget + (*AddDenyRules)(nil), // 176: openshell.v1.AddDenyRules + (*AddAllowRules)(nil), // 177: openshell.v1.AddAllowRules + (*RemoveNetworkBinary)(nil), // 178: openshell.v1.RemoveNetworkBinary + (*UpdateConfigResponse)(nil), // 179: openshell.v1.UpdateConfigResponse + (*GetSandboxPolicyStatusRequest)(nil), // 180: openshell.v1.GetSandboxPolicyStatusRequest + (*GetSandboxPolicyStatusResponse)(nil), // 181: openshell.v1.GetSandboxPolicyStatusResponse + (*ListSandboxPoliciesRequest)(nil), // 182: openshell.v1.ListSandboxPoliciesRequest + (*ListSandboxPoliciesResponse)(nil), // 183: openshell.v1.ListSandboxPoliciesResponse + (*ReportPolicyStatusRequest)(nil), // 184: openshell.v1.ReportPolicyStatusRequest + (*ReportPolicyStatusResponse)(nil), // 185: openshell.v1.ReportPolicyStatusResponse + (*SandboxConfigurationAdmission)(nil), // 186: openshell.v1.SandboxConfigurationAdmission + (*ReportSandboxConfigurationRequest)(nil), // 187: openshell.v1.ReportSandboxConfigurationRequest + (*ReportSandboxConfigurationResponse)(nil), // 188: openshell.v1.ReportSandboxConfigurationResponse + (*SandboxPolicyRevision)(nil), // 189: openshell.v1.SandboxPolicyRevision + (*GetSandboxLogsRequest)(nil), // 190: openshell.v1.GetSandboxLogsRequest + (*PushSandboxLogsRequest)(nil), // 191: openshell.v1.PushSandboxLogsRequest + (*PushSandboxLogsResponse)(nil), // 192: openshell.v1.PushSandboxLogsResponse + (*GetSandboxLogsResponse)(nil), // 193: openshell.v1.GetSandboxLogsResponse + (*SupervisorMessage)(nil), // 194: openshell.v1.SupervisorMessage + (*GatewayMessage)(nil), // 195: openshell.v1.GatewayMessage + (*SupervisorHello)(nil), // 196: openshell.v1.SupervisorHello + (*SessionAccepted)(nil), // 197: openshell.v1.SessionAccepted + (*ConfigUpdate)(nil), // 198: openshell.v1.ConfigUpdate + (*ConfigApplyFailure)(nil), // 199: openshell.v1.ConfigApplyFailure + (*ConfigUpdateResult)(nil), // 200: openshell.v1.ConfigUpdateResult + (*PolicyLoadResult)(nil), // 201: openshell.v1.PolicyLoadResult + (*SessionRejected)(nil), // 202: openshell.v1.SessionRejected + (*SessionRedirect)(nil), // 203: openshell.v1.SessionRedirect + (*SupervisorHeartbeat)(nil), // 204: openshell.v1.SupervisorHeartbeat + (*GatewayHeartbeat)(nil), // 205: openshell.v1.GatewayHeartbeat + (*ReportMainProcessExitRequest)(nil), // 206: openshell.v1.ReportMainProcessExitRequest + (*ReportMainProcessExitResponse)(nil), // 207: openshell.v1.ReportMainProcessExitResponse + (*FinalizeMainProcessExitRequest)(nil), // 208: openshell.v1.FinalizeMainProcessExitRequest + (*FinalizeMainProcessExitResponse)(nil), // 209: openshell.v1.FinalizeMainProcessExitResponse + (*RelayOpen)(nil), // 210: openshell.v1.RelayOpen + (*SshRelayTarget)(nil), // 211: openshell.v1.SshRelayTarget + (*TcpRelayTarget)(nil), // 212: openshell.v1.TcpRelayTarget + (*RelayInit)(nil), // 213: openshell.v1.RelayInit + (*RelayFrame)(nil), // 214: openshell.v1.RelayFrame + (*PeerRelayInit)(nil), // 215: openshell.v1.PeerRelayInit + (*PeerRelayFrame)(nil), // 216: openshell.v1.PeerRelayFrame + (*PeerConfigSandboxTarget)(nil), // 217: openshell.v1.PeerConfigSandboxTarget + (*PeerConfigProviderTarget)(nil), // 218: openshell.v1.PeerConfigProviderTarget + (*PeerNotifyConfigUpdateRequest)(nil), // 219: openshell.v1.PeerNotifyConfigUpdateRequest + (*PeerNotifyConfigUpdateResponse)(nil), // 220: openshell.v1.PeerNotifyConfigUpdateResponse + (*RelayOpenResult)(nil), // 221: openshell.v1.RelayOpenResult + (*RelayClose)(nil), // 222: openshell.v1.RelayClose + (*L7RequestSample)(nil), // 223: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 224: openshell.v1.DenialSummary + (*DenialGroupCount)(nil), // 225: openshell.v1.DenialGroupCount + (*NetworkActivitySummary)(nil), // 226: openshell.v1.NetworkActivitySummary + (*PolicyChunk)(nil), // 227: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 228: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 229: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 230: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 231: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 232: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 233: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 234: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 235: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 236: openshell.v1.RejectDraftChunkResponse + (*DraftChunkApproval)(nil), // 237: openshell.v1.DraftChunkApproval + (*ApproveAllDraftChunksRequest)(nil), // 238: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 239: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 240: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 241: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 242: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 243: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 244: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 245: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 246: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 247: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 248: openshell.v1.GetDraftHistoryResponse + (*CreateWorkspaceRequest)(nil), // 249: openshell.v1.CreateWorkspaceRequest + (*CreateWorkspaceResponse)(nil), // 250: openshell.v1.CreateWorkspaceResponse + (*GetWorkspaceRequest)(nil), // 251: openshell.v1.GetWorkspaceRequest + (*GetWorkspaceResponse)(nil), // 252: openshell.v1.GetWorkspaceResponse + (*ListWorkspacesRequest)(nil), // 253: openshell.v1.ListWorkspacesRequest + (*ListWorkspacesResponse)(nil), // 254: openshell.v1.ListWorkspacesResponse + (*DeleteWorkspaceRequest)(nil), // 255: openshell.v1.DeleteWorkspaceRequest + (*DeleteWorkspaceResponse)(nil), // 256: openshell.v1.DeleteWorkspaceResponse + (*WorkspaceMember)(nil), // 257: openshell.v1.WorkspaceMember + (*AddWorkspaceMemberRequest)(nil), // 258: openshell.v1.AddWorkspaceMemberRequest + (*AddWorkspaceMemberResponse)(nil), // 259: openshell.v1.AddWorkspaceMemberResponse + (*RemoveWorkspaceMemberRequest)(nil), // 260: openshell.v1.RemoveWorkspaceMemberRequest + (*RemoveWorkspaceMemberResponse)(nil), // 261: openshell.v1.RemoveWorkspaceMemberResponse + (*ListWorkspaceMembersRequest)(nil), // 262: openshell.v1.ListWorkspaceMembersRequest + (*ListWorkspaceMembersResponse)(nil), // 263: openshell.v1.ListWorkspaceMembersResponse + (*ExtensionServiceCredential)(nil), // 264: openshell.v1.ExtensionServiceCredential + (*EndpointObservation)(nil), // 265: openshell.v1.EndpointObservation + (*ReportEndpointStatusRequest)(nil), // 266: openshell.v1.ReportEndpointStatusRequest + (*TokenGrantStatus)(nil), // 267: openshell.v1.TokenGrantStatus + (*TokenGrantFailureObservation)(nil), // 268: openshell.v1.TokenGrantFailureObservation + (*ReportEndpointStatusResponse)(nil), // 269: openshell.v1.ReportEndpointStatusResponse + (*EndpointStatus)(nil), // 270: openshell.v1.EndpointStatus + (*SandboxProvisioning)(nil), // 271: openshell.v1.SandboxProvisioning + (*SandboxServiceExposure)(nil), // 272: openshell.v1.SandboxServiceExposure + (*EndpointFailure)(nil), // 273: openshell.v1.EndpointFailure + nil, // 274: openshell.v1.SandboxSpec.EnvironmentEntry + nil, // 275: openshell.v1.SandboxTemplate.LabelsEntry + nil, // 276: openshell.v1.SandboxTemplate.AnnotationsEntry + nil, // 277: openshell.v1.SandboxTemplate.EnvironmentEntry + nil, // 278: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + nil, // 279: openshell.v1.PlatformEvent.MetadataEntry + nil, // 280: openshell.v1.CreateSandboxRequest.LabelsEntry + nil, // 281: openshell.v1.CreateSandboxRequest.AnnotationsEntry + nil, // 282: openshell.v1.SandboxResponse.ServiceUrlsEntry + nil, // 283: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 284: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 285: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry + nil, // 286: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + nil, // 287: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + nil, // 288: openshell.v1.ProviderProfile.AnnotationsEntry + nil, // 289: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + nil, // 290: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + nil, // 291: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + nil, // 292: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + nil, // 293: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + nil, // 294: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + nil, // 295: openshell.v1.ProviderEnvironmentSnapshot.FilesEntry + nil, // 296: openshell.v1.UpdateConfigRequest.AnnotationsEntry + nil, // 297: openshell.v1.UpdateConfigResponse.AnnotationsEntry + nil, // 298: openshell.v1.SandboxPolicyRevision.ProvenanceEntry + nil, // 299: openshell.v1.CreateWorkspaceRequest.LabelsEntry + (*timestamppb.Timestamp)(nil), // 300: google.protobuf.Timestamp + (*datamodelv1.ObjectMeta)(nil), // 301: openshell.datamodel.v1.ObjectMeta + (*sandboxv1.SandboxPolicy)(nil), // 302: openshell.sandbox.v1.SandboxPolicy + (*structpb.Struct)(nil), // 303: google.protobuf.Struct + (*durationpb.Duration)(nil), // 304: google.protobuf.Duration + (*datamodelv1.WorkspaceSelector)(nil), // 305: openshell.datamodel.v1.WorkspaceSelector + (*datamodelv1.Provider)(nil), // 306: openshell.datamodel.v1.Provider + (sandboxv1.PolicySource)(0), // 307: openshell.sandbox.v1.PolicySource + (*sandboxv1.NetworkEndpoint)(nil), // 308: openshell.sandbox.v1.NetworkEndpoint + (*sandboxv1.NetworkBinary)(nil), // 309: openshell.sandbox.v1.NetworkBinary + (*sandboxv1.SettingValue)(nil), // 310: openshell.sandbox.v1.SettingValue + (*sandboxv1.NetworkPolicyRule)(nil), // 311: openshell.sandbox.v1.NetworkPolicyRule + (*sandboxv1.L7DenyRule)(nil), // 312: openshell.sandbox.v1.L7DenyRule + (*sandboxv1.L7Rule)(nil), // 313: openshell.sandbox.v1.L7Rule + (*sandboxv1.SandboxConfigSnapshot)(nil), // 314: openshell.sandbox.v1.SandboxConfigSnapshot + (*datamodelv1.Workspace)(nil), // 315: openshell.datamodel.v1.Workspace + (*sandboxv1.GetSandboxConfigRequest)(nil), // 316: openshell.sandbox.v1.GetSandboxConfigRequest + (*sandboxv1.GetGatewayConfigRequest)(nil), // 317: openshell.sandbox.v1.GetGatewayConfigRequest + (*sandboxv1.GetSandboxConfigResponse)(nil), // 318: openshell.sandbox.v1.GetSandboxConfigResponse + (*sandboxv1.GetGatewayConfigResponse)(nil), // 319: openshell.sandbox.v1.GetGatewayConfigResponse } var file_openshell_proto_depIdxs = []int32{ - 301, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 301, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 265, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential - 301, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp + 300, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 300, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 264, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential + 300, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp 14, // 4: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus 14, // 5: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus 33, // 6: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo @@ -21869,534 +21773,533 @@ var file_openshell_proto_depIdxs = []int32{ 36, // 11: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities 37, // 12: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities 38, // 13: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities - 302, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 301, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 40, // 15: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec 51, // 16: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus 50, // 17: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance - 275, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry + 274, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry 43, // 19: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate - 303, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 302, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy 41, // 21: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements 17, // 22: openshell.v1.SandboxSpec.restart_policy:type_name -> openshell.v1.SandboxRestartPolicy 42, // 23: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements - 276, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry - 277, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry - 278, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry - 304, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct - 304, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct - 302, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 275, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry + 276, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry + 277, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry + 303, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 303, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct + 301, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 45, // 30: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec 46, // 31: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig - 304, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct + 303, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct 48, // 33: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel - 279, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + 278, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry 47, // 35: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources 42, // 36: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements 49, // 37: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup - 305, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration - 53, // 39: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition + 304, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 52, // 39: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition 1, // 40: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 271, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus - 187, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 272, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning - 301, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp - 301, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp - 269, // 46: openshell.v1.SandboxStatus.last_token_grant_failure:type_name -> openshell.v1.TokenGrantFailureObservation - 52, // 47: openshell.v1.SandboxStatus.image_update:type_name -> openshell.v1.SandboxImageUpdate - 301, // 48: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp - 301, // 49: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp - 280, // 50: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 306, // 51: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 40, // 52: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 281, // 53: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 282, // 54: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 273, // 55: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure - 306, // 56: openshell.v1.UpdateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 57: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 44, // 58: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 306, // 59: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 60: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 61: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 44, // 62: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 44, // 63: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate - 18, // 64: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 306, // 65: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 301, // 66: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp - 306, // 67: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 68: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 69: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 70: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 71: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 72: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 73: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 74: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 75: openshell.v1.SuspendSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 76: openshell.v1.ResumeSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 39, // 77: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 283, // 78: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry - 39, // 79: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 307, // 80: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 39, // 81: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 85, // 82: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 39, // 83: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 85, // 84: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 83, // 85: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision - 81, // 86: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity - 308, // 87: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource - 5, // 88: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent - 82, // 89: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision - 7, // 90: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState - 6, // 91: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 301, // 92: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp - 301, // 93: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp - 301, // 94: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp - 2, // 95: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind - 81, // 96: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity - 301, // 97: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp - 4, // 98: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason - 85, // 99: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 3, // 100: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState - 4, // 101: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason - 86, // 102: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation - 301, // 103: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp - 301, // 104: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp - 84, // 105: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation - 306, // 106: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 87, // 107: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus - 86, // 108: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation - 305, // 109: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration - 305, // 110: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration - 18, // 111: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 306, // 112: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 301, // 113: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp - 306, // 114: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 20, // 115: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 306, // 116: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 117: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 102, // 118: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 306, // 119: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 120: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 302, // 121: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 20, // 122: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 101, // 123: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint - 18, // 124: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 306, // 125: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 284, // 126: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 305, // 127: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration - 106, // 128: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout - 107, // 129: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr - 108, // 130: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 212, // 131: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 213, // 132: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget - 110, // 133: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit - 105, // 134: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest - 113, // 135: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 302, // 136: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 301, // 137: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp - 306, // 138: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 301, // 139: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp - 39, // 140: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox - 117, // 141: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine - 54, // 142: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent - 118, // 143: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 229, // 144: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 301, // 145: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp - 285, // 146: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 306, // 147: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 307, // 148: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 306, // 149: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 150: openshell.v1.GetProviderCredentialsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 151: openshell.v1.GetProviderCredentialsRequest.minimum_remaining_lifetime:type_name -> google.protobuf.Duration - 301, // 152: openshell.v1.ProviderCredentialValue.expiration_time:type_name -> google.protobuf.Timestamp - 286, // 153: openshell.v1.GetProviderCredentialsResponse.credentials:type_name -> openshell.v1.GetProviderCredentialsResponse.CredentialsEntry - 306, // 154: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 155: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 307, // 156: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 287, // 157: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - 306, // 158: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 307, // 159: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider - 85, // 160: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt - 307, // 161: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 306, // 162: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 163: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 150, // 164: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 305, // 165: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration - 133, // 166: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride - 8, // 167: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType - 134, // 168: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken - 139, // 169: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh - 135, // 170: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant - 9, // 171: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 305, // 172: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration - 305, // 173: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration - 137, // 174: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial - 138, // 175: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput - 9, // 176: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 301, // 177: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp - 301, // 178: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp - 301, // 179: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp - 16, // 180: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 301, // 181: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp - 306, // 182: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 140, // 183: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 306, // 184: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 9, // 185: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 288, // 186: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 301, // 187: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp - 140, // 188: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 306, // 189: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 140, // 190: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 306, // 191: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 192: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 10, // 193: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory - 136, // 194: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 309, // 195: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 310, // 196: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 141, // 197: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 289, // 198: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 151, // 199: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile - 150, // 200: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 150, // 201: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 306, // 202: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 131, // 203: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 132, // 204: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 150, // 205: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 306, // 206: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 131, // 207: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 132, // 208: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 150, // 209: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 306, // 210: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 131, // 211: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 132, // 212: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 18, // 213: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 306, // 214: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 215: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 164, // 216: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 290, // 217: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 291, // 218: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - 292, // 219: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 293, // 220: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 4, // 221: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 294, // 222: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - 11, // 223: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification - 165, // 224: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding - 301, // 225: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp - 167, // 226: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue - 295, // 227: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry - 4, // 228: openshell.v1.ProviderEnvironmentSnapshot.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 296, // 229: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - 305, // 230: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration - 306, // 231: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 303, // 232: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 311, // 233: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 172, // 234: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 297, // 235: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 173, // 236: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 174, // 237: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 175, // 238: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 177, // 239: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 178, // 240: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 179, // 241: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 312, // 242: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 310, // 243: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 313, // 244: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 176, // 245: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget - 314, // 246: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 176, // 247: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget - 298, // 248: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 306, // 249: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 190, // 250: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 306, // 251: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 190, // 252: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 13, // 253: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 12, // 254: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState - 187, // 255: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 13, // 256: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 301, // 257: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp - 301, // 258: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp - 303, // 259: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 299, // 260: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 306, // 261: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 301, // 262: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp - 117, // 263: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 117, // 264: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 197, // 265: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 205, // 266: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 222, // 267: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 223, // 268: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 201, // 269: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult - 198, // 270: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 203, // 271: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 206, // 272: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 211, // 273: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 223, // 274: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 204, // 275: openshell.v1.GatewayMessage.session_redirect:type_name -> openshell.v1.SessionRedirect - 199, // 276: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate - 199, // 277: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigUpdate - 305, // 278: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration - 315, // 279: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot - 168, // 280: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot - 6, // 281: openshell.v1.ConfigUpdateResult.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 200, // 282: openshell.v1.ConfigUpdateResult.failure:type_name -> openshell.v1.ConfigApplyFailure - 187, // 283: openshell.v1.ConfigUpdateResult.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 202, // 284: openshell.v1.ConfigUpdateResult.policy_load:type_name -> openshell.v1.PolicyLoadResult - 212, // 285: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 213, // 286: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 214, // 287: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 211, // 288: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen - 216, // 289: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit - 218, // 290: openshell.v1.PeerNotifyConfigUpdateRequest.sandbox:type_name -> openshell.v1.PeerConfigSandboxTarget - 219, // 291: openshell.v1.PeerNotifyConfigUpdateRequest.provider:type_name -> openshell.v1.PeerConfigProviderTarget - 301, // 292: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp - 301, // 293: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp - 224, // 294: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 226, // 295: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 312, // 296: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 301, // 297: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp - 301, // 298: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp - 301, // 299: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp - 301, // 300: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp - 303, // 301: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 303, // 302: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 306, // 303: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 225, // 304: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 228, // 305: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 227, // 306: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 306, // 307: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 228, // 308: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 301, // 309: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp - 306, // 310: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 311: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 312: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 238, // 313: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval - 306, // 314: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 312, // 315: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 306, // 316: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 317: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 318: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 301, // 319: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp - 248, // 320: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 300, // 321: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 316, // 322: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 316, // 323: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 316, // 324: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 18, // 325: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 302, // 326: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 15, // 327: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 306, // 328: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 15, // 329: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 258, // 330: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 306, // 331: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 332: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 306, // 333: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 258, // 334: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 301, // 335: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp - 19, // 336: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult - 274, // 337: openshell.v1.EndpointObservation.failure:type_name -> openshell.v1.EndpointFailure - 266, // 338: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation - 268, // 339: openshell.v1.ReportEndpointStatusRequest.token_grant_status:type_name -> openshell.v1.TokenGrantStatus - 269, // 340: openshell.v1.TokenGrantStatus.last_failure:type_name -> openshell.v1.TokenGrantFailureObservation - 274, // 341: openshell.v1.TokenGrantFailureObservation.failure:type_name -> openshell.v1.EndpointFailure - 19, // 342: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult - 301, // 343: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp - 274, // 344: openshell.v1.EndpointStatus.last_failure:type_name -> openshell.v1.EndpointFailure - 301, // 345: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp - 301, // 346: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp - 301, // 347: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp - 301, // 348: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp - 301, // 349: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp - 301, // 350: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp - 301, // 351: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp - 301, // 352: openshell.v1.SandboxProvisioning.preparation_deadline:type_name -> google.protobuf.Timestamp - 301, // 353: openshell.v1.SandboxProvisioning.admission_start_time:type_name -> google.protobuf.Timestamp - 20, // 354: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 21, // 355: openshell.v1.EndpointFailure.domain:type_name -> openshell.v1.EndpointFailureDomain - 16, // 356: openshell.v1.EndpointFailure.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 122, // 357: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry.value:type_name -> openshell.v1.ProviderCredentialValue - 301, // 358: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 301, // 359: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 136, // 360: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 165, // 361: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 136, // 362: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 26, // 363: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 28, // 364: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 30, // 365: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 55, // 366: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 56, // 367: openshell.v1.OpenShell.UpdateSandbox:input_type -> openshell.v1.UpdateSandboxRequest - 64, // 368: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest - 66, // 369: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 67, // 370: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 57, // 371: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 58, // 372: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 59, // 373: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 60, // 374: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 68, // 375: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 69, // 376: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 70, // 377: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 88, // 378: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 71, // 379: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 72, // 380: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 73, // 381: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 74, // 382: openshell.v1.OpenShell.SuspendSandbox:input_type -> openshell.v1.SuspendSandboxRequest - 75, // 383: openshell.v1.OpenShell.ResumeSandbox:input_type -> openshell.v1.ResumeSandboxRequest - 93, // 384: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 95, // 385: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 96, // 386: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 97, // 387: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 99, // 388: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 103, // 389: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 105, // 390: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 111, // 391: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 112, // 392: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 119, // 393: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 120, // 394: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 121, // 395: openshell.v1.OpenShell.GetProviderCredentials:input_type -> openshell.v1.GetProviderCredentialsRequest - 124, // 396: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 129, // 397: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 130, // 398: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 154, // 399: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 156, // 400: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 158, // 401: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 125, // 402: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 142, // 403: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 144, // 404: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 146, // 405: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 148, // 406: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 126, // 407: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 161, // 408: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 317, // 409: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 318, // 410: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 171, // 411: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 181, // 412: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 183, // 413: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 185, // 414: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 267, // 415: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 90, // 416: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 188, // 417: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest - 163, // 418: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 169, // 419: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest - 191, // 420: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 192, // 421: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 195, // 422: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 207, // 423: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest - 209, // 424: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest - 215, // 425: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 217, // 426: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame - 90, // 427: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 267, // 428: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 88, // 429: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 220, // 430: openshell.v1.OpenShell.PeerNotifyConfigUpdate:input_type -> openshell.v1.PeerNotifyConfigUpdateRequest - 115, // 431: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 230, // 432: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 232, // 433: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 234, // 434: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 236, // 435: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 239, // 436: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 241, // 437: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 243, // 438: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 245, // 439: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 247, // 440: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 22, // 441: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 24, // 442: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 250, // 443: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 252, // 444: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 254, // 445: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 256, // 446: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 259, // 447: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 261, // 448: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 263, // 449: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 27, // 450: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 29, // 451: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 31, // 452: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 76, // 453: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 76, // 454: openshell.v1.OpenShell.UpdateSandbox:output_type -> openshell.v1.SandboxResponse - 65, // 455: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse - 76, // 456: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 77, // 457: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 61, // 458: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 61, // 459: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 62, // 460: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 63, // 461: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 78, // 462: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 79, // 463: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 80, // 464: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 89, // 465: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 92, // 466: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 76, // 467: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 76, // 468: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 76, // 469: openshell.v1.OpenShell.SuspendSandbox:output_type -> openshell.v1.SandboxResponse - 76, // 470: openshell.v1.OpenShell.ResumeSandbox:output_type -> openshell.v1.SandboxResponse - 94, // 471: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 102, // 472: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 102, // 473: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 98, // 474: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 100, // 475: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 104, // 476: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 109, // 477: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 111, // 478: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 109, // 479: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 127, // 480: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 127, // 481: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 123, // 482: openshell.v1.OpenShell.GetProviderCredentials:output_type -> openshell.v1.GetProviderCredentialsResponse - 128, // 483: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 153, // 484: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 152, // 485: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 155, // 486: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 157, // 487: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 159, // 488: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 127, // 489: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 143, // 490: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 145, // 491: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 147, // 492: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 149, // 493: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 160, // 494: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 162, // 495: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 319, // 496: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 320, // 497: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 180, // 498: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 182, // 499: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 184, // 500: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 186, // 501: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 270, // 502: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 91, // 503: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 189, // 504: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse - 166, // 505: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 170, // 506: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse - 194, // 507: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 193, // 508: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 196, // 509: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 208, // 510: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse - 210, // 511: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse - 215, // 512: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 217, // 513: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame - 91, // 514: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 270, // 515: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 89, // 516: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 221, // 517: openshell.v1.OpenShell.PeerNotifyConfigUpdate:output_type -> openshell.v1.PeerNotifyConfigUpdateResponse - 116, // 518: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 231, // 519: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 233, // 520: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 235, // 521: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 237, // 522: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 240, // 523: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 242, // 524: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 244, // 525: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 246, // 526: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 249, // 527: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 23, // 528: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 25, // 529: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 251, // 530: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 253, // 531: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 255, // 532: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 257, // 533: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 260, // 534: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 262, // 535: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 264, // 536: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 450, // [450:537] is the sub-list for method output_type - 363, // [363:450] is the sub-list for method input_type - 363, // [363:363] is the sub-list for extension type_name - 363, // [363:363] is the sub-list for extension extendee - 0, // [0:363] is the sub-list for field type_name + 270, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus + 186, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 271, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning + 300, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp + 300, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp + 268, // 46: openshell.v1.SandboxStatus.last_token_grant_failure:type_name -> openshell.v1.TokenGrantFailureObservation + 300, // 47: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp + 300, // 48: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp + 279, // 49: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 305, // 50: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 40, // 51: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec + 280, // 52: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 281, // 53: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 272, // 54: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure + 305, // 55: openshell.v1.UpdateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 56: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 44, // 57: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 305, // 58: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 59: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 60: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 44, // 61: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 44, // 62: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate + 18, // 63: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 305, // 64: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 300, // 65: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp + 305, // 66: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 67: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 68: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 69: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 70: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 71: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 72: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 73: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 74: openshell.v1.SuspendSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 75: openshell.v1.ResumeSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 39, // 76: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox + 282, // 77: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry + 39, // 78: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox + 306, // 79: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 39, // 80: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 84, // 81: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 39, // 82: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 84, // 83: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 82, // 84: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision + 80, // 85: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity + 307, // 86: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 5, // 87: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent + 81, // 88: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision + 7, // 89: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState + 6, // 90: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome + 300, // 91: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp + 300, // 92: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp + 300, // 93: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp + 2, // 94: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind + 80, // 95: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity + 300, // 96: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp + 4, // 97: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason + 84, // 98: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 3, // 99: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState + 4, // 100: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason + 85, // 101: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation + 300, // 102: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp + 300, // 103: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp + 83, // 104: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation + 305, // 105: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 86, // 106: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus + 85, // 107: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation + 304, // 108: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration + 304, // 109: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration + 18, // 110: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 305, // 111: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 300, // 112: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp + 305, // 113: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 20, // 114: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 305, // 115: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 116: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 101, // 117: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse + 305, // 118: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 119: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 301, // 120: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 20, // 121: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 100, // 122: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint + 18, // 123: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 305, // 124: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 283, // 125: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 304, // 126: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration + 105, // 127: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout + 106, // 128: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr + 107, // 129: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit + 211, // 130: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget + 212, // 131: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget + 109, // 132: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit + 104, // 133: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest + 112, // 134: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize + 301, // 135: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 300, // 136: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp + 305, // 137: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 300, // 138: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp + 39, // 139: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox + 116, // 140: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine + 53, // 141: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent + 117, // 142: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning + 228, // 143: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 300, // 144: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp + 284, // 145: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 305, // 146: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 147: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 305, // 148: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 149: openshell.v1.GetProviderCredentialsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 150: openshell.v1.GetProviderCredentialsRequest.minimum_remaining_lifetime:type_name -> google.protobuf.Duration + 300, // 151: openshell.v1.ProviderCredentialValue.expiration_time:type_name -> google.protobuf.Timestamp + 285, // 152: openshell.v1.GetProviderCredentialsResponse.credentials:type_name -> openshell.v1.GetProviderCredentialsResponse.CredentialsEntry + 305, // 153: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 154: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 155: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 286, // 156: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + 305, // 157: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 306, // 158: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 84, // 159: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt + 306, // 160: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 305, // 161: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 162: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 149, // 163: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile + 304, // 164: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration + 132, // 165: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride + 8, // 166: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType + 133, // 167: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken + 138, // 168: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh + 134, // 169: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant + 9, // 170: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 304, // 171: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration + 304, // 172: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration + 136, // 173: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial + 137, // 174: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput + 9, // 175: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 300, // 176: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp + 300, // 177: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp + 300, // 178: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp + 16, // 179: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 300, // 180: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp + 305, // 181: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 139, // 182: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 305, // 183: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 9, // 184: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 287, // 185: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 300, // 186: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp + 139, // 187: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 305, // 188: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 139, // 189: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 305, // 190: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 191: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 10, // 192: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory + 135, // 193: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential + 308, // 194: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 309, // 195: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 140, // 196: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery + 288, // 197: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 150, // 198: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile + 149, // 199: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile + 149, // 200: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 305, // 201: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 130, // 202: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 131, // 203: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 149, // 204: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 305, // 205: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 130, // 206: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem + 131, // 207: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 149, // 208: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile + 305, // 209: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 130, // 210: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 131, // 211: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 18, // 212: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 305, // 213: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 214: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 163, // 215: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding + 289, // 216: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 290, // 217: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + 291, // 218: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 292, // 219: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 4, // 220: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason + 293, // 221: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + 11, // 222: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification + 164, // 223: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding + 300, // 224: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp + 166, // 225: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue + 294, // 226: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + 4, // 227: openshell.v1.ProviderEnvironmentSnapshot.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason + 295, // 228: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry + 304, // 229: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration + 305, // 230: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 302, // 231: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 310, // 232: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 171, // 233: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation + 296, // 234: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 172, // 235: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule + 173, // 236: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint + 174, // 237: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule + 176, // 238: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules + 177, // 239: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules + 178, // 240: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary + 311, // 241: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 309, // 242: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 312, // 243: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 175, // 244: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget + 313, // 245: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 175, // 246: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget + 297, // 247: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 305, // 248: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 189, // 249: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 305, // 250: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 189, // 251: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 13, // 252: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 12, // 253: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState + 186, // 254: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 13, // 255: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 300, // 256: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp + 300, // 257: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp + 302, // 258: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 298, // 259: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 305, // 260: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 300, // 261: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp + 116, // 262: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 116, // 263: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 196, // 264: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello + 204, // 265: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat + 221, // 266: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 222, // 267: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 200, // 268: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult + 197, // 269: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted + 202, // 270: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected + 205, // 271: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat + 210, // 272: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen + 222, // 273: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 203, // 274: openshell.v1.GatewayMessage.session_redirect:type_name -> openshell.v1.SessionRedirect + 198, // 275: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate + 198, // 276: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigUpdate + 304, // 277: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration + 314, // 278: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot + 167, // 279: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot + 6, // 280: openshell.v1.ConfigUpdateResult.outcome:type_name -> openshell.v1.ConfigApplyOutcome + 199, // 281: openshell.v1.ConfigUpdateResult.failure:type_name -> openshell.v1.ConfigApplyFailure + 186, // 282: openshell.v1.ConfigUpdateResult.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 201, // 283: openshell.v1.ConfigUpdateResult.policy_load:type_name -> openshell.v1.PolicyLoadResult + 211, // 284: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget + 212, // 285: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget + 213, // 286: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit + 210, // 287: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen + 215, // 288: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit + 217, // 289: openshell.v1.PeerNotifyConfigUpdateRequest.sandbox:type_name -> openshell.v1.PeerConfigSandboxTarget + 218, // 290: openshell.v1.PeerNotifyConfigUpdateRequest.provider:type_name -> openshell.v1.PeerConfigProviderTarget + 300, // 291: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp + 300, // 292: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp + 223, // 293: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 225, // 294: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 311, // 295: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 300, // 296: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp + 300, // 297: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp + 300, // 298: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp + 300, // 299: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp + 302, // 300: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 302, // 301: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 305, // 302: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 224, // 303: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 227, // 304: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 226, // 305: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 305, // 306: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 227, // 307: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 300, // 308: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp + 305, // 309: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 310: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 311: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 237, // 312: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval + 305, // 313: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 311, // 314: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 305, // 315: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 316: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 317: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 300, // 318: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp + 247, // 319: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 299, // 320: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 315, // 321: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 315, // 322: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 315, // 323: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 18, // 324: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 301, // 325: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 15, // 326: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 305, // 327: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 15, // 328: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 257, // 329: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 305, // 330: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 331: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 305, // 332: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 257, // 333: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 300, // 334: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp + 19, // 335: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult + 273, // 336: openshell.v1.EndpointObservation.failure:type_name -> openshell.v1.EndpointFailure + 265, // 337: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation + 267, // 338: openshell.v1.ReportEndpointStatusRequest.token_grant_status:type_name -> openshell.v1.TokenGrantStatus + 268, // 339: openshell.v1.TokenGrantStatus.last_failure:type_name -> openshell.v1.TokenGrantFailureObservation + 273, // 340: openshell.v1.TokenGrantFailureObservation.failure:type_name -> openshell.v1.EndpointFailure + 19, // 341: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult + 300, // 342: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp + 273, // 343: openshell.v1.EndpointStatus.last_failure:type_name -> openshell.v1.EndpointFailure + 300, // 344: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp + 300, // 345: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp + 300, // 346: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp + 300, // 347: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp + 300, // 348: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp + 300, // 349: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp + 300, // 350: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp + 300, // 351: openshell.v1.SandboxProvisioning.preparation_deadline:type_name -> google.protobuf.Timestamp + 300, // 352: openshell.v1.SandboxProvisioning.admission_start_time:type_name -> google.protobuf.Timestamp + 20, // 353: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 21, // 354: openshell.v1.EndpointFailure.domain:type_name -> openshell.v1.EndpointFailureDomain + 16, // 355: openshell.v1.EndpointFailure.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 121, // 356: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry.value:type_name -> openshell.v1.ProviderCredentialValue + 300, // 357: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 300, // 358: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 135, // 359: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 164, // 360: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 135, // 361: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 26, // 362: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 28, // 363: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 30, // 364: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 54, // 365: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 63, // 366: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest + 65, // 367: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 66, // 368: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 56, // 369: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 57, // 370: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 58, // 371: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 59, // 372: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 67, // 373: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 68, // 374: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 69, // 375: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 87, // 376: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 70, // 377: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 71, // 378: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 72, // 379: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 73, // 380: openshell.v1.OpenShell.SuspendSandbox:input_type -> openshell.v1.SuspendSandboxRequest + 74, // 381: openshell.v1.OpenShell.ResumeSandbox:input_type -> openshell.v1.ResumeSandboxRequest + 92, // 382: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 94, // 383: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 95, // 384: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 96, // 385: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 98, // 386: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 102, // 387: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 104, // 388: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 110, // 389: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 111, // 390: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 118, // 391: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 119, // 392: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 120, // 393: openshell.v1.OpenShell.GetProviderCredentials:input_type -> openshell.v1.GetProviderCredentialsRequest + 123, // 394: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 128, // 395: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 129, // 396: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 153, // 397: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 155, // 398: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 157, // 399: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 124, // 400: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 141, // 401: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 143, // 402: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 145, // 403: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 147, // 404: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 125, // 405: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 160, // 406: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 316, // 407: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 317, // 408: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 170, // 409: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 180, // 410: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 182, // 411: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 184, // 412: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 266, // 413: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 89, // 414: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 187, // 415: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest + 162, // 416: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 168, // 417: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest + 190, // 418: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 191, // 419: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 194, // 420: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 206, // 421: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest + 208, // 422: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest + 214, // 423: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 216, // 424: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame + 89, // 425: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 266, // 426: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 87, // 427: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 219, // 428: openshell.v1.OpenShell.PeerNotifyConfigUpdate:input_type -> openshell.v1.PeerNotifyConfigUpdateRequest + 114, // 429: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 229, // 430: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 231, // 431: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 233, // 432: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 235, // 433: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 238, // 434: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 240, // 435: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 242, // 436: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 244, // 437: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 246, // 438: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 22, // 439: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 24, // 440: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 249, // 441: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 251, // 442: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 253, // 443: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 255, // 444: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 258, // 445: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 260, // 446: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 262, // 447: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 55, // 448: openshell.v1.SandboxUpdates.UpdateSandbox:input_type -> openshell.v1.UpdateSandboxRequest + 27, // 449: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 29, // 450: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 31, // 451: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 75, // 452: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 64, // 453: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse + 75, // 454: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 76, // 455: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 60, // 456: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 60, // 457: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 61, // 458: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 62, // 459: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 77, // 460: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 78, // 461: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 79, // 462: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 88, // 463: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 91, // 464: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 75, // 465: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 75, // 466: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 75, // 467: openshell.v1.OpenShell.SuspendSandbox:output_type -> openshell.v1.SandboxResponse + 75, // 468: openshell.v1.OpenShell.ResumeSandbox:output_type -> openshell.v1.SandboxResponse + 93, // 469: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 101, // 470: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 101, // 471: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 97, // 472: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 99, // 473: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 103, // 474: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 108, // 475: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 110, // 476: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 108, // 477: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 126, // 478: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 126, // 479: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 122, // 480: openshell.v1.OpenShell.GetProviderCredentials:output_type -> openshell.v1.GetProviderCredentialsResponse + 127, // 481: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 152, // 482: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 151, // 483: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 154, // 484: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 156, // 485: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 158, // 486: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 126, // 487: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 142, // 488: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 144, // 489: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 146, // 490: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 148, // 491: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 159, // 492: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 161, // 493: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 318, // 494: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 319, // 495: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 179, // 496: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 181, // 497: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 183, // 498: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 185, // 499: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 269, // 500: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 90, // 501: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 188, // 502: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse + 165, // 503: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 169, // 504: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse + 193, // 505: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 192, // 506: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 195, // 507: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 207, // 508: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse + 209, // 509: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse + 214, // 510: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 216, // 511: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame + 90, // 512: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 269, // 513: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 88, // 514: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 220, // 515: openshell.v1.OpenShell.PeerNotifyConfigUpdate:output_type -> openshell.v1.PeerNotifyConfigUpdateResponse + 115, // 516: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 230, // 517: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 232, // 518: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 234, // 519: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 236, // 520: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 239, // 521: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 241, // 522: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 243, // 523: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 245, // 524: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 248, // 525: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 23, // 526: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 25, // 527: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 250, // 528: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 252, // 529: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 254, // 530: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 256, // 531: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 259, // 532: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 261, // 533: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 263, // 534: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 75, // 535: openshell.v1.SandboxUpdates.UpdateSandbox:output_type -> openshell.v1.SandboxResponse + 449, // [449:536] is the sub-list for method output_type + 362, // [362:449] is the sub-list for method input_type + 362, // [362:362] is the sub-list for extension type_name + 362, // [362:362] is the sub-list for extension extendee + 0, // [0:362] is the sub-list for field type_name } func init() { file_openshell_proto_init() } @@ -22407,37 +22310,37 @@ func file_openshell_proto_init() { file_openshell_proto_msgTypes[20].OneofWrappers = []any{} file_openshell_proto_msgTypes[21].OneofWrappers = []any{} file_openshell_proto_msgTypes[29].OneofWrappers = []any{} - file_openshell_proto_msgTypes[60].OneofWrappers = []any{ + file_openshell_proto_msgTypes[59].OneofWrappers = []any{ (*ConfigSnapshotRevision_SandboxConfig)(nil), (*ConfigSnapshotRevision_ProviderEnvironment)(nil), (*ConfigSnapshotRevision_ProviderTarget)(nil), } - file_openshell_proto_msgTypes[87].OneofWrappers = []any{ + file_openshell_proto_msgTypes[86].OneofWrappers = []any{ (*ExecSandboxEvent_Stdout)(nil), (*ExecSandboxEvent_Stderr)(nil), (*ExecSandboxEvent_Exit)(nil), } - file_openshell_proto_msgTypes[88].OneofWrappers = []any{ + file_openshell_proto_msgTypes[87].OneofWrappers = []any{ (*TcpForwardInit_Ssh)(nil), (*TcpForwardInit_Tcp)(nil), } - file_openshell_proto_msgTypes[89].OneofWrappers = []any{ + file_openshell_proto_msgTypes[88].OneofWrappers = []any{ (*TcpForwardFrame_Init)(nil), (*TcpForwardFrame_Data)(nil), } - file_openshell_proto_msgTypes[90].OneofWrappers = []any{ + file_openshell_proto_msgTypes[89].OneofWrappers = []any{ (*ExecSandboxInput_Start)(nil), (*ExecSandboxInput_Stdin)(nil), (*ExecSandboxInput_Resize)(nil), } - file_openshell_proto_msgTypes[94].OneofWrappers = []any{ + file_openshell_proto_msgTypes[93].OneofWrappers = []any{ (*SandboxStreamEvent_Sandbox)(nil), (*SandboxStreamEvent_Log)(nil), (*SandboxStreamEvent_Event)(nil), (*SandboxStreamEvent_Warning)(nil), (*SandboxStreamEvent_DraftPolicyUpdate)(nil), } - file_openshell_proto_msgTypes[150].OneofWrappers = []any{ + file_openshell_proto_msgTypes[149].OneofWrappers = []any{ (*PolicyMergeOperation_AddRule)(nil), (*PolicyMergeOperation_RemoveEndpoint)(nil), (*PolicyMergeOperation_RemoveRule)(nil), @@ -22445,15 +22348,15 @@ func file_openshell_proto_init() { (*PolicyMergeOperation_AddAllowRules)(nil), (*PolicyMergeOperation_RemoveBinary)(nil), } - file_openshell_proto_msgTypes[154].OneofWrappers = []any{} - file_openshell_proto_msgTypes[173].OneofWrappers = []any{ + file_openshell_proto_msgTypes[153].OneofWrappers = []any{} + file_openshell_proto_msgTypes[172].OneofWrappers = []any{ (*SupervisorMessage_Hello)(nil), (*SupervisorMessage_Heartbeat)(nil), (*SupervisorMessage_RelayOpenResult)(nil), (*SupervisorMessage_RelayClose)(nil), (*SupervisorMessage_ConfigUpdateResult)(nil), } - file_openshell_proto_msgTypes[174].OneofWrappers = []any{ + file_openshell_proto_msgTypes[173].OneofWrappers = []any{ (*GatewayMessage_SessionAccepted)(nil), (*GatewayMessage_SessionRejected)(nil), (*GatewayMessage_Heartbeat)(nil), @@ -22462,34 +22365,34 @@ func file_openshell_proto_init() { (*GatewayMessage_SessionRedirect)(nil), (*GatewayMessage_ConfigUpdate)(nil), } - file_openshell_proto_msgTypes[189].OneofWrappers = []any{ + file_openshell_proto_msgTypes[188].OneofWrappers = []any{ (*RelayOpen_Ssh)(nil), (*RelayOpen_Tcp)(nil), } - file_openshell_proto_msgTypes[193].OneofWrappers = []any{ + file_openshell_proto_msgTypes[192].OneofWrappers = []any{ (*RelayFrame_Init)(nil), (*RelayFrame_Data)(nil), } - file_openshell_proto_msgTypes[195].OneofWrappers = []any{ + file_openshell_proto_msgTypes[194].OneofWrappers = []any{ (*PeerRelayFrame_Init)(nil), (*PeerRelayFrame_Data)(nil), } - file_openshell_proto_msgTypes[198].OneofWrappers = []any{ + file_openshell_proto_msgTypes[197].OneofWrappers = []any{ (*PeerNotifyConfigUpdateRequest_Sandbox)(nil), (*PeerNotifyConfigUpdateRequest_Workspace)(nil), (*PeerNotifyConfigUpdateRequest_AllConnected)(nil), (*PeerNotifyConfigUpdateRequest_Provider)(nil), } - file_openshell_proto_msgTypes[252].OneofWrappers = []any{} + file_openshell_proto_msgTypes[251].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_openshell_proto_rawDesc), len(file_openshell_proto_rawDesc)), NumEnums: 22, - NumMessages: 279, + NumMessages: 278, NumExtensions: 0, - NumServices: 1, + NumServices: 2, }, GoTypes: file_openshell_proto_goTypes, DependencyIndexes: file_openshell_proto_depIdxs, diff --git a/sdk/go/proto/openshellv1/openshell_grpc.pb.go b/sdk/go/proto/openshellv1/openshell_grpc.pb.go index 2c5b89f076..823a41fc36 100644 --- a/sdk/go/proto/openshellv1/openshell_grpc.pb.go +++ b/sdk/go/proto/openshellv1/openshell_grpc.pb.go @@ -27,7 +27,6 @@ const ( OpenShell_GetCurrentUser_FullMethodName = "/openshell.v1.OpenShell/GetCurrentUser" OpenShell_GetGatewayInfo_FullMethodName = "/openshell.v1.OpenShell/GetGatewayInfo" OpenShell_CreateSandbox_FullMethodName = "/openshell.v1.OpenShell/CreateSandbox" - OpenShell_UpdateSandbox_FullMethodName = "/openshell.v1.OpenShell/UpdateSandbox" OpenShell_BeginRootfsTarStaging_FullMethodName = "/openshell.v1.OpenShell/BeginRootfsTarStaging" OpenShell_GetSandbox_FullMethodName = "/openshell.v1.OpenShell/GetSandbox" OpenShell_ListSandboxes_FullMethodName = "/openshell.v1.OpenShell/ListSandboxes" @@ -133,9 +132,6 @@ type OpenShellClient interface { GetGatewayInfo(ctx context.Context, in *GetGatewayInfoRequest, opts ...grpc.CallOption) (*GetGatewayInfoResponse, error) // Create a new sandbox. CreateSandbox(ctx context.Context, in *CreateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) - // Update only the workload image of a stopped sandbox without deleting its - // identity or retained storage. Requires compute-driver image-update support. - UpdateSandbox(ctx context.Context, in *UpdateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) // Allocate a gateway-owned staging slot for a local rootfs tar archive. // // The gateway creates a request-scoped directory inside the compute driver's @@ -411,16 +407,6 @@ func (c *openShellClient) CreateSandbox(ctx context.Context, in *CreateSandboxRe return out, nil } -func (c *openShellClient) UpdateSandbox(ctx context.Context, in *UpdateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(SandboxResponse) - err := c.cc.Invoke(ctx, OpenShell_UpdateSandbox_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *openShellClient) BeginRootfsTarStaging(ctx context.Context, in *BeginRootfsTarStagingRequest, opts ...grpc.CallOption) (*BeginRootfsTarStagingResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(BeginRootfsTarStagingResponse) @@ -1298,9 +1284,6 @@ type OpenShellServer interface { GetGatewayInfo(context.Context, *GetGatewayInfoRequest) (*GetGatewayInfoResponse, error) // Create a new sandbox. CreateSandbox(context.Context, *CreateSandboxRequest) (*SandboxResponse, error) - // Update only the workload image of a stopped sandbox without deleting its - // identity or retained storage. Requires compute-driver image-update support. - UpdateSandbox(context.Context, *UpdateSandboxRequest) (*SandboxResponse, error) // Allocate a gateway-owned staging slot for a local rootfs tar archive. // // The gateway creates a request-scoped directory inside the compute driver's @@ -1548,9 +1531,6 @@ func (UnimplementedOpenShellServer) GetGatewayInfo(context.Context, *GetGatewayI func (UnimplementedOpenShellServer) CreateSandbox(context.Context, *CreateSandboxRequest) (*SandboxResponse, error) { return nil, status.Error(codes.Unimplemented, "method CreateSandbox not implemented") } -func (UnimplementedOpenShellServer) UpdateSandbox(context.Context, *UpdateSandboxRequest) (*SandboxResponse, error) { - return nil, status.Error(codes.Unimplemented, "method UpdateSandbox not implemented") -} func (UnimplementedOpenShellServer) BeginRootfsTarStaging(context.Context, *BeginRootfsTarStagingRequest) (*BeginRootfsTarStagingResponse, error) { return nil, status.Error(codes.Unimplemented, "method BeginRootfsTarStaging not implemented") } @@ -1890,24 +1870,6 @@ func _OpenShell_CreateSandbox_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } -func _OpenShell_UpdateSandbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UpdateSandboxRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(OpenShellServer).UpdateSandbox(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: OpenShell_UpdateSandbox_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(OpenShellServer).UpdateSandbox(ctx, req.(*UpdateSandboxRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _OpenShell_BeginRootfsTarStaging_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(BeginRootfsTarStagingRequest) if err := dec(in); err != nil { @@ -3327,10 +3289,6 @@ var OpenShell_ServiceDesc = grpc.ServiceDesc{ MethodName: "CreateSandbox", Handler: _OpenShell_CreateSandbox_Handler, }, - { - MethodName: "UpdateSandbox", - Handler: _OpenShell_UpdateSandbox_Handler, - }, { MethodName: "BeginRootfsTarStaging", Handler: _OpenShell_BeginRootfsTarStaging_Handler, @@ -3677,3 +3635,117 @@ var OpenShell_ServiceDesc = grpc.ServiceDesc{ }, Metadata: "openshell.proto", } + +const ( + SandboxUpdates_UpdateSandbox_FullMethodName = "/openshell.v1.SandboxUpdates/UpdateSandbox" +) + +// SandboxUpdatesClient is the client API for SandboxUpdates service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Optional sandbox mutations are separate from OpenShell so existing generated +// OpenShell server implementations remain source-compatible. +type SandboxUpdatesClient interface { + // Update only the workload image of a stopped sandbox without deleting its + // identity or retained storage. Requires compute-driver image-update support + // and explicit gateway activation of sandbox image updates. + UpdateSandbox(ctx context.Context, in *UpdateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) +} + +type sandboxUpdatesClient struct { + cc grpc.ClientConnInterface +} + +func NewSandboxUpdatesClient(cc grpc.ClientConnInterface) SandboxUpdatesClient { + return &sandboxUpdatesClient{cc} +} + +func (c *sandboxUpdatesClient) UpdateSandbox(ctx context.Context, in *UpdateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SandboxResponse) + err := c.cc.Invoke(ctx, SandboxUpdates_UpdateSandbox_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SandboxUpdatesServer is the server API for SandboxUpdates service. +// All implementations must embed UnimplementedSandboxUpdatesServer +// for forward compatibility. +// +// Optional sandbox mutations are separate from OpenShell so existing generated +// OpenShell server implementations remain source-compatible. +type SandboxUpdatesServer interface { + // Update only the workload image of a stopped sandbox without deleting its + // identity or retained storage. Requires compute-driver image-update support + // and explicit gateway activation of sandbox image updates. + UpdateSandbox(context.Context, *UpdateSandboxRequest) (*SandboxResponse, error) + mustEmbedUnimplementedSandboxUpdatesServer() +} + +// UnimplementedSandboxUpdatesServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedSandboxUpdatesServer struct{} + +func (UnimplementedSandboxUpdatesServer) UpdateSandbox(context.Context, *UpdateSandboxRequest) (*SandboxResponse, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateSandbox not implemented") +} +func (UnimplementedSandboxUpdatesServer) mustEmbedUnimplementedSandboxUpdatesServer() {} +func (UnimplementedSandboxUpdatesServer) testEmbeddedByValue() {} + +// UnsafeSandboxUpdatesServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to SandboxUpdatesServer will +// result in compilation errors. +type UnsafeSandboxUpdatesServer interface { + mustEmbedUnimplementedSandboxUpdatesServer() +} + +func RegisterSandboxUpdatesServer(s grpc.ServiceRegistrar, srv SandboxUpdatesServer) { + // If the following call panics, it indicates UnimplementedSandboxUpdatesServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&SandboxUpdates_ServiceDesc, srv) +} + +func _SandboxUpdates_UpdateSandbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSandboxRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SandboxUpdatesServer).UpdateSandbox(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SandboxUpdates_UpdateSandbox_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SandboxUpdatesServer).UpdateSandbox(ctx, req.(*UpdateSandboxRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// SandboxUpdates_ServiceDesc is the grpc.ServiceDesc for SandboxUpdates service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var SandboxUpdates_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "openshell.v1.SandboxUpdates", + HandlerType: (*SandboxUpdatesServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "UpdateSandbox", + Handler: _SandboxUpdates_UpdateSandbox_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "openshell.proto", +} diff --git a/sdk/go/tests/compatibility/sandbox_updates_test.go b/sdk/go/tests/compatibility/sandbox_updates_test.go new file mode 100644 index 0000000000..2181a87b88 --- /dev/null +++ b/sdk/go/tests/compatibility/sandbox_updates_test.go @@ -0,0 +1,121 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package compatibility_test + +import ( + "context" + "net" + "testing" + + dm "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1" + pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/grpc/test/bufconn" + "google.golang.org/protobuf/proto" + "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", + } + 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) + } + 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")) + updates := pb.File_openshell_proto.Services().ByName("SandboxUpdates") + require.NotNil(t, updates) + require.Equal(t, 1, updates.Methods().Len()) + method := updates.Methods().Get(0) + require.Equal(t, protoreflect.FullName("openshell.v1.UpdateSandboxRequest"), method.Input().FullName()) + require.Equal(t, protoreflect.FullName("openshell.v1.SandboxResponse"), method.Output().FullName()) + require.Equal(t, "/openshell.v1.SandboxUpdates/UpdateSandbox", pb.SandboxUpdates_UpdateSandbox_FullMethodName) +} + +type legacyHealthServer struct { + pb.UnimplementedOpenShellServer +} + +func (legacyHealthServer) Health(context.Context, *pb.HealthRequest) (*pb.HealthResponse, error) { + return &pb.HealthResponse{Version: "legacy-compatible"}, nil +} + +type imageUpdateServer struct { + pb.UnimplementedSandboxUpdatesServer + request *pb.UpdateSandboxRequest +} + +func (s *imageUpdateServer) UpdateSandbox(_ context.Context, request *pb.UpdateSandboxRequest) (*pb.SandboxResponse, error) { + s.request = proto.Clone(request).(*pb.UpdateSandboxRequest) + return &pb.SandboxResponse{Sandbox: &pb.Sandbox{ + Metadata: &dm.ObjectMeta{Id: "stable-id", Name: request.Name, Workspace: request.WorkspaceScope.GetWorkspace()}, + Spec: &pb.SandboxSpec{Template: &pb.SandboxTemplate{Image: request.Image}}, + }}, nil +} + +func TestSeparateSandboxUpdatesTransportCoexistsWithLegacyOpenShell(t *testing.T) { + listener := bufconn.Listen(1024 * 1024) + server := grpc.NewServer(grpc.UnaryInterceptor(func(ctx context.Context, request any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { + if info.FullMethod == pb.SandboxUpdates_UpdateSandbox_FullMethodName { + md, _ := metadata.FromIncomingContext(ctx) + if len(md.Get("authorization")) == 0 { + return nil, status.Error(codes.Unauthenticated, "bearer required") + } + } + return handler(ctx, request) + })) + updatesServer := &imageUpdateServer{} + pb.RegisterOpenShellServer(server, legacyHealthServer{}) + pb.RegisterSandboxUpdatesServer(server, updatesServer) + go func() { _ = server.Serve(listener) }() + t.Cleanup(server.Stop) + t.Cleanup(func() { _ = listener.Close() }) + conn, err := grpc.NewClient("passthrough:///sandbox-updates", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { + return listener.Dial() + })) + require.NoError(t, err) + t.Cleanup(func() { _ = conn.Close() }) + legacy := pb.NewOpenShellClient(conn) + health, err := legacy.Health(context.Background(), &pb.HealthRequest{}) + require.NoError(t, err) + require.Equal(t, "legacy-compatible", health.Version) + updates := pb.NewSandboxUpdatesClient(conn) + request := &pb.UpdateSandboxRequest{ + WorkspaceScope: &dm.WorkspaceSelector{Selection: &dm.WorkspaceSelector_Workspace{Workspace: "team"}}, + Name: "sandbox", + Image: "example/workload:new", + ExpectedResourceVersion: 42, + RequestId: "550e8400-e29b-41d4-a716-446655440000", + } + _, err = updates.UpdateSandbox(context.Background(), request) + require.Equal(t, codes.Unauthenticated, status.Code(err)) + require.Nil(t, updatesServer.request) + ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs("authorization", "Bearer test-token")) + response, err := updates.UpdateSandbox(ctx, request) + require.NoError(t, err) + require.True(t, proto.Equal(request, updatesServer.request)) + require.Equal(t, "stable-id", response.Sandbox.Metadata.Id) + require.Equal(t, "team", response.Sandbox.Metadata.Workspace) + require.Equal(t, request.Image, response.Sandbox.Spec.Template.Image) + // The old service has no accidental update endpoint. + err = conn.Invoke(ctx, "/openshell.v1.OpenShell/UpdateSandbox", request, &pb.SandboxResponse{}) + require.Equal(t, codes.Unimplemented, status.Code(err)) +} diff --git a/sdk/typescript/src/raw.test.ts b/sdk/typescript/src/raw.test.ts index 9d2e02ac6e..798d23b536 100644 --- a/sdk/typescript/src/raw.test.ts +++ b/sdk/typescript/src/raw.test.ts @@ -3,10 +3,55 @@ import type { MessageInitShape } from '@bufbuild/protobuf'; import { timestampFromDate } from '@bufbuild/protobuf/wkt'; -import { createRouterTransport } from '@connectrpc/connect'; +import { createClient, createRouterTransport } from '@connectrpc/connect'; import { describe, expect, it } from 'vitest'; import { SandboxClient } from './index.js'; -import { EndpointResult, type EndpointStatusSchema, OpenShell, SandboxPhase } from './raw.js'; +import { EndpointResult, type EndpointStatusSchema, OpenShell, SandboxPhase, SandboxUpdates } from './raw.js'; + +describe('raw sandbox image updates', () => { + it.each([true, false])('uses a separate service on the existing transport (binary: %s)', async (useBinaryFormat) => { + const transport = createRouterTransport( + (router) => { + router.service(OpenShell, { + getSandbox: () => ({ sandbox: { metadata: { id: 'stable-id' } } }), + }); + router.service(SandboxUpdates, { + updateSandbox: (request) => { + expect(request.workspaceScope?.selection).toEqual({ case: 'workspace', value: 'team' }); + expect(request.name).toBe('sandbox'); + expect(request.expectedResourceVersion).toBe(42n); + expect(request.requestId).toBe('550e8400-e29b-41d4-a716-446655440000'); + return { + sandbox: { + metadata: { id: 'stable-id', name: request.name, workspace: 'team' }, + spec: { template: { image: request.image } }, + status: { phase: SandboxPhase.STOPPED }, + }, + }; + }, + }); + }, + { transport: { useBinaryFormat } }, + ); + const legacy = new SandboxClient(transport); + const updates = createClient(SandboxUpdates, legacy.transport); + expect(Object.hasOwn(OpenShell.method, 'updateSandbox')).toBe(false); + expect(SandboxUpdates.typeName).toBe('openshell.v1.SandboxUpdates'); + const before = await legacy.raw.getSandbox({ name: 'sandbox' }); + const response = await updates.updateSandbox({ + workspaceScope: { selection: { case: 'workspace', value: 'team' } }, + name: 'sandbox', + image: 'example/workload:new', + expectedResourceVersion: 42n, + requestId: '550e8400-e29b-41d4-a716-446655440000', + }); + expect(response.sandbox?.metadata?.id).toBe(before.sandbox?.metadata?.id); + expect(response.sandbox?.spec?.template?.image).toBe('example/workload:new'); + expect(response.sandbox?.status?.phase).toBe(SandboxPhase.STOPPED); + expect(response.sandbox?.status).not.toHaveProperty('imageUpdate'); + expect(response.sandbox?.status).not.toHaveProperty('imageRevision'); + }); +}); describe('raw sandbox endpoint status', () => { it.each([true, false])( diff --git a/sdk/typescript/src/raw.ts b/sdk/typescript/src/raw.ts index 1571e8e23e..067a6558b9 100644 --- a/sdk/typescript/src/raw.ts +++ b/sdk/typescript/src/raw.ts @@ -4,7 +4,7 @@ export * from './gen/datamodel_pb.js'; export * from './gen/google/rpc/error_details_pb.js'; // Advanced surface: the full generated protobuf types (messages, enums, and the -// OpenShell service descriptor) for callers using the raw escape hatch on +// OpenShell and SandboxUpdates service descriptors) for callers using the raw escape hatch on // OpenShellClient / SandboxClient (`.raw` and `.transport`). These are the // uncurated wire types; import them from '@nvidia/openshell-sdk/raw'. The // curated entry point stays free of generated types so its surface does not diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index 29b4407563..b73e8efe1a 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -1435,6 +1435,46 @@ network supervisor logs for CONNECT and upstream-proxy decisions: kubectl -n logs pod/ --tail=200 | grep -Ei 'upstream|connect|proxy' ``` +#### Sandbox image-update activation and recovery + +`openshell.v1.SandboxUpdates/UpdateSandbox` uses the existing authenticated +gateway listener and defaults to disabled. Check the effective +`[openshell.gateway] enable_sandbox_image_updates` value and its overrides, +`--enable-sandbox-image-updates true` or +`OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES=true`. Canonical Helm values use: + +```yaml +gatewayConfig: + "openshell.gateway": + enable_sandbox_image_updates: true +``` + +Do not enable the flag to work around an error. It attests that all incompatible +gateways, including unregistered processes and Jobs, have been drained and +retired, their outstanding driver operations have settled, and old binaries +cannot return through rollout or rollback configurations. Keep it false during +a rolling upgrade. SQLite supports one gateway process, not shared-file HA. + +On PostgreSQL, an unmarked client backend in the same database blocks updates, +including an administrative session. The new binary sets every pool +connection's `application_name` to `openshell-image-update-v1`; close unmarked +sessions or use a dedicated database, rather than relabeling old clients. Live +gateway membership must advertise image-update protocol 1; malformed or +truncated membership reads fail closed. Neither these observations nor an +expired membership TTL proves old gateways and their work have stopped. Follow +the published +[activation checklist](https://docs.nvidia.com/openshell/latest/kubernetes/high-availability#activate-sandbox-image-updates), +and do not downgrade while updates are pending or retained sandboxes require +the private revision protocol. + +For an operation-pending error, use the original requested image and a fresh +sandbox resource version to reconcile through `SandboxUpdates`. Intent and +revision are private, not new public status fields. Start, stop, provisioning +retry, and delete do not bypass the barrier. Preserve request-admission semantics: +never change the payload under an existing ID or blindly switch IDs after a +timeout. See the published +[recovery contract](https://docs.nvidia.com/openshell/latest/sdk/api-errors#sandbox-image-update-recovery). + ### Step 7: Check VM-Backed Gateways Use the VM driver logs and host diagnostics available in the user's environment. Verify: diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index d10370b329..075cfbec7e 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -557,12 +557,21 @@ retained memory state. ### Change a stopped sandbox's workload image Do not invent a `sandbox update` command or use delete/create to change an -existing sandbox's image. The raw `UpdateSandbox` RPC initially supports only -stopped Kubernetes sandboxes; other drivers return `UNIMPLEMENTED`. Stop and +existing sandbox's image. The separate +`openshell.v1.SandboxUpdates/UpdateSandbox` RPC uses the same gateway listener +and authentication as `OpenShell`. It defaults to disabled; the operator must +complete the published +[activation checklist](https://docs.nvidia.com/openshell/latest/kubernetes/high-availability#activate-sandbox-image-updates) +before enabling `enable_sandbox_image_updates`. Keep it false during a rolling +upgrade and never enable it merely to bypass a failed compatibility check. +After activation, the RPC initially supports only stopped Kubernetes sandboxes; +other drivers return `UNIMPLEMENTED`. Stop and wait for `Stopped`, read the sandbox's current resource version through `GetSandbox`, call raw `UpdateSandbox` with the named workspace, sandbox name, OCI image, and required nonzero `expected_resource_version`, then start after -success. There is no curated SDK update method. The sandbox identity, Kubernetes +success. Rust SDK callers use `client.raw_sandbox_updates_fresh()`; generated +clients use `SandboxUpdates`, not the unchanged `OpenShell` service. There is no +curated SDK update method. The sandbox identity, Kubernetes custom resource, and persistent volume claim remain; the existing workspace is not reseeded and trusted runtime images do not change. @@ -571,8 +580,10 @@ cleanup completion and settlement of the original driver operation, then run `sandbox stop` to obtain `Stopped` before correcting the image. This retains the timeout diagnostic and storage and does not bypass pending cleanup. -If raw `sandbox.status.image_update` is present after a failure, start is -blocked. Read a fresh version and retry that same pending image. An optional +An operation-pending error after a failure blocks start, stop, provisioning +retry, and delete. Image intent and revision are private; the public `SandboxStatus` +shape is unchanged. Read a fresh version and retry the same image originally +requested, even if the spec already names it. An optional `request_id` with an unresolved admission does not execute again; inspect and reconcile state before submitting a new conditional request with a fresh version and new ID, or no ID. Never change the payload under the original ID or From 6408554443283c56bdf78df6b4edae01417a2f18 Mon Sep 17 00:00:00 2001 From: sjenning <493891+sjenning@users.noreply.github.com> Date: Thu, 15 Oct 2026 21:33:07 -0500 Subject: [PATCH 04/23] fix(gateway): preserve optional driver compatibility and repair CI Move image updates to a separate optional compute-driver service, preserving the baseline generated trait and streaming associated type. Add source and TCP/UDS transport regressions, capability negotiation coverage, and a default-unsupported in-process extension. Keep Go compatibility tests outside generated output and update production reflection expectations for the separate sandbox update service. Signed-off-by: sjenning <493891+sjenning@users.noreply.github.com> --- crates/openshell-core/README.md | 13 + crates/openshell-core/src/compute.rs | 26 ++ crates/openshell-core/src/lib.rs | 1 + .../tests/compute_driver_compat.rs | 292 ++++++++++++++++++ crates/openshell-driver-docker/src/lib.rs | 26 +- crates/openshell-driver-kubernetes/README.md | 4 +- .../openshell-driver-kubernetes/src/grpc.rs | 55 ++-- .../src/image_update_tests.rs | 2 +- .../openshell-driver-kubernetes/src/main.rs | 7 +- crates/openshell-driver-mxc/src/grpc.rs | 13 +- crates/openshell-driver-podman/src/grpc.rs | 13 +- crates/openshell-driver-vm/src/driver.rs | 13 +- crates/openshell-otel/src/grpc.rs | 11 +- crates/openshell-server/src/compute/mod.rs | 227 ++++++++++---- crates/openshell-server/src/test_support.rs | 36 ++- examples/isolation-backend-v8/src/driver.rs | 9 - proto/compute_driver.proto | 20 +- 17 files changed, 618 insertions(+), 150 deletions(-) create mode 100644 crates/openshell-core/src/compute.rs create mode 100644 crates/openshell-core/tests/compute_driver_compat.rs diff --git a/crates/openshell-core/README.md b/crates/openshell-core/README.md index 1cf1b7e70e..707e3ec77b 100644 --- a/crates/openshell-core/README.md +++ b/crates/openshell-core/README.md @@ -65,6 +65,19 @@ configuration validation live in `openshell_core::middleware`. Policy admission and the supervisor runtime consume the same contract without introducing a dependency from the policy crate to the supervisor implementation. +## Optional Compute Image Updates + +The generated `proto::compute::v1::compute_driver_server::ComputeDriver` trait +retains its baseline methods and streaming associated type. External drivers +that support image updates additionally serve `ComputeDriverImageUpdates` on +the same endpoint and advertise `openshell.compute.update-sandbox-image`. +Drivers without that capability need no new generated-trait method. + +Linked in-process drivers implement `openshell_core::compute::ComputeDriver` +in addition to the generated baseline trait. An empty implementation inherits +`UNIMPLEMENTED` for image updates; supporting drivers override the optional +method. The gateway negotiates the capability before invoking either path. + ## Protobuf Struct Conversion Use `openshell_core::proto_struct` when crossing between `serde_json` values and diff --git a/crates/openshell-core/src/compute.rs b/crates/openshell-core/src/compute.rs new file mode 100644 index 0000000000..57722752e3 --- /dev/null +++ b/crates/openshell-core/src/compute.rs @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! In-process compute contract, separate from the baseline generated gRPC trait. + +use crate::proto::compute::v1::{ + UpdateSandboxImageRequest, UpdateSandboxImageResponse, compute_driver_server, +}; + +/// Gateway-facing in-process compute driver with optional image updates. +/// +/// External servers implement the unchanged generated +/// [`compute_driver_server::ComputeDriver`] trait and, when supported, the +/// separate generated `ComputeDriverImageUpdates` service on the same endpoint. +/// In-process drivers use this default unless they advertise image updates. +#[tonic::async_trait] +pub trait ComputeDriver: compute_driver_server::ComputeDriver { + async fn update_sandbox_image( + &self, + _request: tonic::Request, + ) -> Result, tonic::Status> { + Err(tonic::Status::unimplemented( + "storage-preserving image updates are not supported by this driver", + )) + } +} diff --git a/crates/openshell-core/src/lib.rs b/crates/openshell-core/src/lib.rs index 0588a9974d..8baca88966 100644 --- a/crates/openshell-core/src/lib.rs +++ b/crates/openshell-core/src/lib.rs @@ -11,6 +11,7 @@ pub mod activity; pub mod auth; +pub mod compute; pub mod config; pub mod container_paths; pub mod denial; diff --git a/crates/openshell-core/tests/compute_driver_compat.rs b/crates/openshell-core/tests/compute_driver_compat.rs new file mode 100644 index 0000000000..40f0124af5 --- /dev/null +++ b/crates/openshell-core/tests/compute_driver_compat.rs @@ -0,0 +1,292 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Fixed baseline server source fixture from 6546691d5e493343c7877573252e835d28bf9e23. +//! It deliberately implements only the original generated `ComputeDriver` methods, +//! including its concrete streaming associated type, with no image-update method +//! or in-process extension trait. New optional RPCs must not break this source. + +use openshell_core::proto::compute::v1::{ + AuthenticateSandboxRequest, AuthenticateSandboxResponse, CreateSandboxRequest, + CreateSandboxResponse, DeleteSandboxRequest, DeleteSandboxResponse, DeleteWorkspaceRequest, + DeleteWorkspaceResponse, EnsureWorkspaceRequest, EnsureWorkspaceResponse, + GetCapabilitiesRequest, GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse, + ListSandboxesRequest, ListSandboxesResponse, StartSandboxRequest, StartSandboxResponse, + StopSandboxRequest, StopSandboxResponse, UpdateSandboxImageRequest, UpdateSandboxImageResponse, + ValidateSandboxCreateRequest, ValidateSandboxCreateResponse, WatchSandboxesEvent, + WatchSandboxesRequest, + compute_driver_client::ComputeDriverClient, + compute_driver_image_updates_client::ComputeDriverImageUpdatesClient, + compute_driver_image_updates_server::{ + ComputeDriverImageUpdates, ComputeDriverImageUpdatesServer, + }, + compute_driver_server::{ComputeDriver, ComputeDriverServer}, +}; +use prost::Message; +use std::pin::Pin; +use std::sync::{Arc, Mutex}; +use std::task::{Context, Poll}; +use tokio::net::{TcpListener, TcpStream}; +use tokio_stream::Stream; +use tonic::{Request, Response, Status}; + +#[derive(Debug)] +struct BaselineDriver; + +#[tonic::async_trait] +impl ComputeDriver for BaselineDriver { + async fn get_capabilities( + &self, + _request: Request, + ) -> Result, Status> { + Ok(Response::new(GetCapabilitiesResponse { + driver_name: "baseline-source-fixture".into(), + ..Default::default() + })) + } + + async fn authenticate_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("fixture")) + } + + async fn validate_sandbox_create( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("fixture")) + } + + async fn get_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("fixture")) + } + + async fn list_sandboxes( + &self, + _request: Request, + ) -> Result, Status> { + Ok(Response::new(ListSandboxesResponse { sandboxes: vec![] })) + } + + async fn create_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("fixture")) + } + + async fn stop_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("fixture")) + } + + async fn start_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("fixture")) + } + + async fn delete_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("fixture")) + } + + type WatchSandboxesStream = tokio_stream::Empty>; + + async fn watch_sandboxes( + &self, + _request: Request, + ) -> Result, Status> { + Ok(Response::new(tokio_stream::empty())) + } + + async fn ensure_workspace( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("fixture")) + } + + async fn delete_workspace( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("fixture")) + } +} + +#[derive(Debug, Clone, Default)] +struct ImageUpdates { + calls: Arc>>, +} + +#[tonic::async_trait] +impl ComputeDriverImageUpdates for ImageUpdates { + async fn update_sandbox_image( + &self, + request: Request, + ) -> Result, Status> { + self.calls.lock().unwrap().push(request.into_inner()); + Ok(Response::new(UpdateSandboxImageResponse {})) + } +} + +struct TcpIncoming(TcpListener); + +impl Stream for TcpIncoming { + type Item = std::io::Result; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.0.poll_accept(cx).map(|result| { + Some(result.map(|(stream, _)| { + openshell_core::net::set_tcp_nodelay_best_effort(&stream); + stream + })) + }) + } +} + +async fn roundtrip(serve_image_updates: bool) { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let address = listener.local_addr().unwrap(); + let extension = ImageUpdates::default(); + let optional_service = + serve_image_updates.then(|| ComputeDriverImageUpdatesServer::new(extension.clone())); + let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel(); + let server = tokio::spawn(async move { + tonic::transport::Server::builder() + .add_service(ComputeDriverServer::new(BaselineDriver)) + .add_optional_service(optional_service) + .serve_with_incoming_shutdown(TcpIncoming(listener), async { + let _ = shutdown_rx.await; + }) + .await + .unwrap(); + }); + let channel = tonic::transport::Endpoint::from_shared(format!("http://{address}")) + .unwrap() + .connect() + .await + .unwrap(); + let mut baseline = ComputeDriverClient::new(channel.clone()); + assert_eq!( + baseline + .get_capabilities(GetCapabilitiesRequest::default()) + .await + .unwrap() + .into_inner() + .driver_name, + "baseline-source-fixture" + ); + assert!( + baseline + .list_sandboxes(ListSandboxesRequest {}) + .await + .unwrap() + .into_inner() + .sandboxes + .is_empty() + ); + assert!( + baseline + .watch_sandboxes(WatchSandboxesRequest {}) + .await + .unwrap() + .into_inner() + .message() + .await + .unwrap() + .is_none() + ); + + let request = UpdateSandboxImageRequest { + sandbox_id: "sandbox-id".into(), + image: "example/workload:v2".into(), + ..Default::default() + }; + let result = ComputeDriverImageUpdatesClient::new(channel) + .update_sandbox_image(request.clone()) + .await; + if serve_image_updates { + result.unwrap(); + assert_eq!(*extension.calls.lock().unwrap(), vec![request]); + } else { + assert_eq!(result.unwrap_err().code(), tonic::Code::Unimplemented); + assert!(extension.calls.lock().unwrap().is_empty()); + } + // Absence of the optional service must not impair the original service. + baseline + .list_sandboxes(ListSandboxesRequest {}) + .await + .unwrap(); + drop(baseline); + shutdown_tx.send(()).unwrap(); + server.await.unwrap(); +} + +#[tokio::test] +async fn baseline_generated_server_source_and_transport_remain_compatible() { + roundtrip(false).await; +} + +#[tokio::test] +async fn optional_image_service_shares_the_baseline_channel() { + roundtrip(true).await; +} + +#[test] +fn baseline_compute_service_methods_are_frozen() { + let descriptor = + prost_types::FileDescriptorSet::decode(openshell_core::FILE_DESCRIPTOR_SET).unwrap(); + let compute = descriptor + .file + .iter() + .find(|file| file.package.as_deref() == Some("openshell.compute.v1")) + .unwrap(); + let baseline = compute + .service + .iter() + .find(|service| service.name.as_deref() == Some("ComputeDriver")) + .unwrap(); + assert_eq!( + baseline + .method + .iter() + .map(|method| method.name.as_deref().unwrap()) + .collect::>(), + vec![ + "GetCapabilities", + "AuthenticateSandbox", + "ValidateSandboxCreate", + "GetSandbox", + "ListSandboxes", + "CreateSandbox", + "StopSandbox", + "StartSandbox", + "DeleteSandbox", + "WatchSandboxes", + "EnsureWorkspace", + "DeleteWorkspace", + ] + ); + let image_updates = compute + .service + .iter() + .find(|service| service.name.as_deref() == Some("ComputeDriverImageUpdates")) + .unwrap(); + assert_eq!(image_updates.method.len(), 1); + assert_eq!( + image_updates.method[0].name.as_deref(), + Some("UpdateSandboxImage") + ); +} diff --git a/crates/openshell-driver-docker/src/lib.rs b/crates/openshell-driver-docker/src/lib.rs index 803f7e537f..8bf5df4e22 100644 --- a/crates/openshell-driver-docker/src/lib.rs +++ b/crates/openshell-driver-docker/src/lib.rs @@ -3157,17 +3157,10 @@ fn validate_docker_outer_fence( Ok(()) } #[tonic::async_trait] -impl ComputeDriver for ComputeDriverService { - async fn update_sandbox_image( - &self, - _request: Request, - ) -> Result, Status> - { - Err(Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } +impl openshell_core::compute::ComputeDriver for ComputeDriverService {} +#[tonic::async_trait] +impl ComputeDriver for ComputeDriverService { type WatchSandboxesStream = WatchStream; async fn authenticate_sandbox( @@ -3329,17 +3322,10 @@ impl ComputeDriver for ComputeDriverService { } #[tonic::async_trait] -impl ComputeDriver for DockerComputeDriver { - async fn update_sandbox_image( - &self, - _request: Request, - ) -> Result, Status> - { - Err(Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } +impl openshell_core::compute::ComputeDriver for DockerComputeDriver {} +#[tonic::async_trait] +impl ComputeDriver for DockerComputeDriver { async fn authenticate_sandbox( &self, _request: Request, diff --git a/crates/openshell-driver-kubernetes/README.md b/crates/openshell-driver-kubernetes/README.md index 59d3f709ca..9237f76d00 100644 --- a/crates/openshell-driver-kubernetes/README.md +++ b/crates/openshell-driver-kubernetes/README.md @@ -303,7 +303,9 @@ condition and deletion of the backing pod. Legacy `v1alpha1` controllers omit a usable stopped condition, so pod deletion alone confirms their stop. The optional `openshell.compute.update-sandbox-image` capability supports -image-only updates while the sandbox is stopped. `UpdateSandboxImage` requires +image-only updates while the sandbox is stopped. External drivers serve it as +the separate `ComputeDriverImageUpdates` service on the baseline `ComputeDriver` +endpoint, preserving the baseline generated server trait. `UpdateSandboxImage` requires the persisted Kubernetes runtime identity, current image, sandbox name, and a stable operation ID with a monotonic image revision. The driver verifies that the same Sandbox resource is suspended, runtime bootstrap has completed, and diff --git a/crates/openshell-driver-kubernetes/src/grpc.rs b/crates/openshell-driver-kubernetes/src/grpc.rs index 108c9ffbd5..06c2f0110a 100644 --- a/crates/openshell-driver-kubernetes/src/grpc.rs +++ b/crates/openshell-driver-kubernetes/src/grpc.rs @@ -224,26 +224,6 @@ impl ComputeDriver for ComputeDriverService { .await } - async fn update_sandbox_image( - &self, - request: Request, - ) -> Result, Status> - { - self.rpc_tracer - .trace(openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, async { - self.driver - .update_sandbox_image(&request.into_inner()) - .await - .map_err(|error| { - Status::from(openshell_core::ComputeDriverError::from(error)) - })?; - Ok(Response::new( - openshell_core::proto::compute::v1::UpdateSandboxImageResponse {}, - )) - }) - .await - } - async fn delete_sandbox( &self, request: Request, @@ -357,6 +337,41 @@ impl ComputeDriver for ComputeDriverService { } } +#[tonic::async_trait] +impl openshell_core::compute::ComputeDriver for ComputeDriverService { + async fn update_sandbox_image( + &self, + request: Request, + ) -> Result, Status> + { + self.rpc_tracer + .trace(openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, async { + self.driver + .update_sandbox_image(&request.into_inner()) + .await + .map_err(|error| { + Status::from(openshell_core::ComputeDriverError::from(error)) + })?; + Ok(Response::new( + openshell_core::proto::compute::v1::UpdateSandboxImageResponse {}, + )) + }) + .await + } +} + +#[tonic::async_trait] +impl openshell_core::proto::compute::v1::compute_driver_image_updates_server::ComputeDriverImageUpdates + for ComputeDriverService +{ + async fn update_sandbox_image( + &self, + request: Request, + ) -> Result, Status> { + openshell_core::compute::ComputeDriver::update_sandbox_image(self, request).await + } +} + fn workspace_delete_requires_namespace_access(mode: WorkspaceMode) -> bool { matches!(mode, WorkspaceMode::Managed) } diff --git a/crates/openshell-driver-kubernetes/src/image_update_tests.rs b/crates/openshell-driver-kubernetes/src/image_update_tests.rs index 25ca24364f..f8d37c73f4 100644 --- a/crates/openshell-driver-kubernetes/src/image_update_tests.rs +++ b/crates/openshell-driver-kubernetes/src/image_update_tests.rs @@ -562,7 +562,7 @@ async fn image_update_conflict_does_not_blindly_retry_or_recreate() { #[tokio::test] async fn image_update_grpc_maps_validation_and_precondition_errors() { - use openshell_core::proto::compute::v1::compute_driver_server::ComputeDriver; + use openshell_core::proto::compute::v1::compute_driver_image_updates_server::ComputeDriverImageUpdates; let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); let service = crate::ComputeDriverService::new(driver); let mut invalid = request(); diff --git a/crates/openshell-driver-kubernetes/src/main.rs b/crates/openshell-driver-kubernetes/src/main.rs index 7803d1561a..de7facfa8e 100644 --- a/crates/openshell-driver-kubernetes/src/main.rs +++ b/crates/openshell-driver-kubernetes/src/main.rs @@ -9,6 +9,7 @@ use std::path::PathBuf; use tracing::info; use openshell_core::VERSION; +use openshell_core::proto::compute::v1::compute_driver_image_updates_server::ComputeDriverImageUpdatesServer; use openshell_core::proto::compute::v1::compute_driver_server::ComputeDriverServer; use openshell_driver_kubernetes::{ ComputeDriverService, DEFAULT_GATEWAY_ID, DEFAULT_SANDBOX_SERVICE_ACCOUNT_NAME, @@ -340,7 +341,9 @@ async fn main() -> Result<()> { .await .into_diagnostic()?; - let service = ComputeDriverServer::new(ComputeDriverService::new(driver)); + let driver_service = ComputeDriverService::new(driver); + let image_updates_service = ComputeDriverImageUpdatesServer::new(driver_service.clone()); + let service = ComputeDriverServer::new(driver_service); let shutdown = async move { shutdown_signal().await; let _ = shutdown_tx.send(true); @@ -354,6 +357,7 @@ async fn main() -> Result<()> { tonic::transport::Server::builder() .layer(openshell_otel::compute_driver_rpc_layer()) .add_service(service) + .add_service(image_updates_service) .serve_with_incoming_shutdown( openshell_core::external_driver_socket::SameUidUnixIncoming::new(listener), shutdown, @@ -365,6 +369,7 @@ async fn main() -> Result<()> { tonic::transport::Server::builder() .layer(openshell_otel::compute_driver_rpc_layer()) .add_service(service) + .add_service(image_updates_service) .serve_with_shutdown(args.bind_address, shutdown) .await .into_diagnostic() diff --git a/crates/openshell-driver-mxc/src/grpc.rs b/crates/openshell-driver-mxc/src/grpc.rs index ac4206276c..ca834987cb 100644 --- a/crates/openshell-driver-mxc/src/grpc.rs +++ b/crates/openshell-driver-mxc/src/grpc.rs @@ -33,17 +33,10 @@ impl ComputeDriverService { } #[tonic::async_trait] -impl ComputeDriver for ComputeDriverService { - async fn update_sandbox_image( - &self, - _request: Request, - ) -> Result, Status> - { - Err(Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } +impl openshell_core::compute::ComputeDriver for ComputeDriverService {} +#[tonic::async_trait] +impl ComputeDriver for ComputeDriverService { async fn get_capabilities( &self, request: Request, diff --git a/crates/openshell-driver-podman/src/grpc.rs b/crates/openshell-driver-podman/src/grpc.rs index c9be5b4409..dff752db24 100644 --- a/crates/openshell-driver-podman/src/grpc.rs +++ b/crates/openshell-driver-podman/src/grpc.rs @@ -49,17 +49,10 @@ impl ComputeDriverService { } #[tonic::async_trait] -impl ComputeDriver for ComputeDriverService { - async fn update_sandbox_image( - &self, - _request: Request, - ) -> Result, Status> - { - Err(Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } +impl openshell_core::compute::ComputeDriver for ComputeDriverService {} +#[tonic::async_trait] +impl ComputeDriver for ComputeDriverService { async fn authenticate_sandbox( &self, _request: Request, diff --git a/crates/openshell-driver-vm/src/driver.rs b/crates/openshell-driver-vm/src/driver.rs index f60d7f8bb1..6260a52842 100644 --- a/crates/openshell-driver-vm/src/driver.rs +++ b/crates/openshell-driver-vm/src/driver.rs @@ -5324,17 +5324,10 @@ fn configure_main_exit_marker(command: &mut Command, state_dir: &Path) { } #[tonic::async_trait] -impl ComputeDriver for VmDriver { - async fn update_sandbox_image( - &self, - _request: Request, - ) -> Result, Status> - { - Err(Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } +impl openshell_core::compute::ComputeDriver for VmDriver {} +#[tonic::async_trait] +impl ComputeDriver for VmDriver { async fn authenticate_sandbox( &self, _request: Request, diff --git a/crates/openshell-otel/src/grpc.rs b/crates/openshell-otel/src/grpc.rs index 9dbb83c85b..877b13efce 100644 --- a/crates/openshell-otel/src/grpc.rs +++ b/crates/openshell-otel/src/grpc.rs @@ -63,6 +63,8 @@ where } pub const COMPUTE_DRIVER_RPC_SERVICE: &str = "openshell.compute.v1.ComputeDriver"; +pub const COMPUTE_DRIVER_IMAGE_UPDATES_RPC_SERVICE: &str = + "openshell.compute.v1.ComputeDriverImageUpdates"; /// Low-cardinality semantic-convention identity for a compute-driver RPC. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -102,10 +104,11 @@ pub mod rpc { "CreateSandbox", "openshell.compute.v1.ComputeDriver/CreateSandbox", ); - pub const UPDATE_SANDBOX_IMAGE: ComputeDriverRpc = ComputeDriverRpc::new( - "UpdateSandboxImage", - "openshell.compute.v1.ComputeDriver/UpdateSandboxImage", - ); + pub const UPDATE_SANDBOX_IMAGE: ComputeDriverRpc = ComputeDriverRpc { + service: super::COMPUTE_DRIVER_IMAGE_UPDATES_RPC_SERVICE, + method: "UpdateSandboxImage", + operation: "openshell.compute.v1.ComputeDriverImageUpdates/UpdateSandboxImage", + }; pub const GET_SANDBOX: ComputeDriverRpc = ComputeDriverRpc::new( "GetSandbox", "openshell.compute.v1.ComputeDriver/GetSandbox", diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index e41c9a04ff..aab7e81b4b 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -43,6 +43,7 @@ use openshell_core::proto::compute::v1::{ ResourceRequirements as DriverSandboxResourceRequirements, StartSandboxRequest, StopSandboxRequest, SuspendSandboxRequest, ValidateSandboxCreateRequest, WatchSandboxesEvent, WatchSandboxesRequest, WorkloadIdentityRequest, compute_driver_client::ComputeDriverClient, + compute_driver_image_updates_client::ComputeDriverImageUpdatesClient, compute_driver_server::ComputeDriver, watch_sandboxes_event, }; use openshell_core::proto::{ @@ -84,8 +85,11 @@ use tracing::{Instrument as _, debug, info, warn}; pub type DriverWatchStream = Pin> + Send>>; -pub type SharedComputeDriver = - Arc + Send + Sync>; +pub type SharedComputeDriver = Arc< + dyn openshell_core::compute::ComputeDriver + + Send + + Sync, +>; fn supports_isolation_registration(capabilities: &[String]) -> bool { capabilities.iter().any(|capability| { @@ -677,6 +681,9 @@ impl AcquiredRemoteDriverEndpoint { #[derive(Debug, Clone)] struct RemoteComputeDriver { client: RemoteComputeDriverClient, + image_updates_client: ComputeDriverImageUpdatesClient< + tonic::service::interceptor::InterceptedService, + >, admission_acknowledgement: Arc>>, } @@ -687,7 +694,11 @@ type RemoteComputeDriverClient = ComputeDriverClient< impl RemoteComputeDriver { fn new(channel: Channel) -> Self { Self { - client: ComputeDriverClient::with_interceptor(channel, TraceContextInterceptor), + client: ComputeDriverClient::with_interceptor(channel.clone(), TraceContextInterceptor), + image_updates_client: ComputeDriverImageUpdatesClient::with_interceptor( + channel, + TraceContextInterceptor, + ), admission_acknowledgement: Arc::new(StdMutex::new(None)), } } @@ -729,7 +740,7 @@ impl RemoteComputeDriver { } #[tonic::async_trait] -impl ComputeDriver for RemoteComputeDriver { +impl openshell_core::compute::ComputeDriver for RemoteComputeDriver { async fn update_sandbox_image( &self, request: Request, @@ -738,9 +749,15 @@ impl ComputeDriver for RemoteComputeDriver { Status, > { self.verify_admission_policy(false).await?; - self.client().update_sandbox_image(request).await + self.image_updates_client + .clone() + .update_sandbox_image(request) + .await } +} +#[tonic::async_trait] +impl ComputeDriver for RemoteComputeDriver { type WatchSandboxesStream = DriverWatchStream; async fn get_capabilities( @@ -8202,19 +8219,11 @@ impl Default for NoopTestDriver { #[cfg(any(test, feature = "test-support"))] #[tonic::async_trait] -impl ComputeDriver for NoopTestDriver { - async fn update_sandbox_image( - &self, - _request: Request, - ) -> Result< - tonic::Response, - Status, - > { - Err(Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } +impl openshell_core::compute::ComputeDriver for NoopTestDriver {} +#[cfg(any(test, feature = "test-support"))] +#[tonic::async_trait] +impl ComputeDriver for NoopTestDriver { async fn authenticate_sandbox( &self, _request: Request, @@ -8854,19 +8863,10 @@ mod tests { } #[tonic::async_trait] - impl ComputeDriver for TestDriver { - async fn update_sandbox_image( - &self, - _request: Request, - ) -> Result< - tonic::Response, - Status, - > { - Err(Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } + impl openshell_core::compute::ComputeDriver for TestDriver {} + #[tonic::async_trait] + impl ComputeDriver for TestDriver { async fn authenticate_sandbox( &self, _request: Request, @@ -9329,19 +9329,10 @@ mod tests { } #[tonic::async_trait] - impl ComputeDriver for ControlledDriver { - async fn update_sandbox_image( - &self, - _request: Request, - ) -> Result< - tonic::Response, - Status, - > { - Err(Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } + impl openshell_core::compute::ComputeDriver for ControlledDriver {} + #[tonic::async_trait] + impl ComputeDriver for ControlledDriver { async fn authenticate_sandbox( &self, _request: Request, @@ -12635,19 +12626,10 @@ mod tests { struct FailingDriver(TestDriver); #[tonic::async_trait] - impl ComputeDriver for FailingDriver { - async fn update_sandbox_image( - &self, - _request: Request, - ) -> Result< - tonic::Response, - Status, - > { - Err(Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } + impl openshell_core::compute::ComputeDriver for FailingDriver {} + #[tonic::async_trait] + impl ComputeDriver for FailingDriver { async fn authenticate_sandbox( &self, _request: Request, @@ -17629,10 +17611,11 @@ mod tests { async fn remote_compute_driver_interceptor_propagates_every_rpc() { use crate::otel_tracing::test_exporter; use crate::test_support::FakeComputeDriver; + use openshell_core::compute::ComputeDriver as _; let dir = tempfile::tempdir().unwrap(); let socket_path = dir.path().join("compute-driver.sock"); - let driver = FakeComputeDriver::new(); + let driver = FakeComputeDriver::new().with_sandbox_image_updates(); let _server = driver.serve_uds(&socket_path).unwrap(); let endpoint = connect_remote_compute_driver("external-test", &socket_path) .await @@ -17686,6 +17669,16 @@ mod tests { .watch_sandboxes(Request::new(WatchSandboxesRequest {})) .await .unwrap(); + remote + .update_sandbox_image(Request::new( + openshell_core::proto::compute::v1::UpdateSandboxImageRequest { + sandbox_id: sandbox.id.clone(), + image: "example/workload:v2".into(), + ..Default::default() + }, + )) + .await + .unwrap(); remote .delete_sandbox(Request::new(DeleteSandboxRequest { sandbox_id: sandbox.id, @@ -17703,7 +17696,7 @@ mod tests { let traceparents = driver.traceparents(); assert_eq!( traceparents.len(), - 10, + 12, "the client interceptor should cover every RPC" ); assert!( @@ -18320,6 +18313,130 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" ); } + #[tokio::test] + #[cfg(unix)] + async fn remote_compute_driver_negotiates_optional_image_service() { + use crate::test_support::{FakeComputeDriver, FakeComputeDriverCall}; + use openshell_core::GetResourceVersion as _; + use openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE; + + for supported in [false, true] { + let dir = tempfile::tempdir().unwrap(); + let socket_path = dir.path().join("image-updates.sock"); + let driver = FakeComputeDriver::new(); + let driver = if supported { + driver.with_sandbox_image_updates() + } else { + driver + }; + let _server = driver.serve_uds(&socket_path).unwrap(); + let endpoint = connect_remote_compute_driver("external-test", &socket_path) + .await + .unwrap(); + let store = Arc::new(crate::persistence::test_store().await); + crate::ensure_default_workspace(&store).await.unwrap(); + let mut runtime = ComputeRuntime::new_remote_driver( + endpoint, + store.clone(), + SandboxIndex::new(), + SandboxWatchBus::new(), + TracingLogBus::new(), + Arc::new(SupervisorSessionRegistry::new()), + ) + .await + .unwrap(); + runtime.image_updates_enabled = true; + assert_eq!( + runtime + .driver_info + .negotiated_extension + .supported_capabilities + .iter() + .any(|capability| capability == COMPUTE_UPDATE_SANDBOX_IMAGE), + supported, + ); + let mut sandbox = sandbox_record("sb-image", "image-sandbox", SandboxPhase::Stopped); + sandbox.metadata.as_mut().unwrap().annotations.insert( + COMPUTE_RUNTIME_IDENTITY_ANNOTATION.into(), + "stable-runtime".into(), + ); + sandbox.spec = Some(SandboxSpec { + template: Some(SandboxTemplate { + image: "example/workload:v1".into(), + ..Default::default() + }), + ..Default::default() + }); + store.put_message(&sandbox).await.unwrap(); + let sandbox = store + .get_message::("sb-image") + .await + .unwrap() + .unwrap(); + driver.clear_calls(); + let result = runtime + .update_sandbox_image( + "sb-image", + "example/workload:v2".into(), + sandbox.get_resource_version(), + ) + .await; + let requests = driver + .calls() + .into_iter() + .filter_map(|call| match call { + FakeComputeDriverCall::UpdateSandboxImage { request } => Some(request), + _ => None, + }) + .collect::>(); + if supported { + let updated = result.unwrap(); + assert_eq!( + updated.spec.unwrap().template.unwrap().image, + "example/workload:v2" + ); + assert_eq!( + requests.len(), + 2, + "preflight and mutation use the optional service" + ); + assert!(requests[0].validate_only); + assert!(!requests[1].validate_only); + for request in &requests { + assert_eq!(request.sandbox_id, "sb-image"); + assert_eq!(request.expected_runtime_identity, "stable-runtime"); + assert_eq!(request.expected_image, "example/workload:v1"); + assert_eq!(request.image, "example/workload:v2"); + } + assert_eq!(requests[0].operation_id, requests[1].operation_id); + } else { + assert_eq!(result.unwrap_err().code(), Code::Unimplemented); + assert!( + requests.is_empty(), + "capability admission must precede extension calls" + ); + let unchanged = store + .get_message::("sb-image") + .await + .unwrap() + .unwrap(); + assert_eq!(unchanged, sandbox); + } + } + } + + #[tokio::test] + async fn in_process_driver_defaults_image_updates_to_unimplemented() { + let driver = NoopTestDriver::default(); + let error = openshell_core::compute::ComputeDriver::update_sandbox_image( + &driver, + Request::new(openshell_core::proto::compute::v1::UpdateSandboxImageRequest::default()), + ) + .await + .unwrap_err(); + assert_eq!(error.code(), Code::Unimplemented); + } + #[tokio::test] async fn negotiated_launch_requirement_rejects_create_before_driver_or_store() { let driver = Arc::new(TestDriver { diff --git a/crates/openshell-server/src/test_support.rs b/crates/openshell-server/src/test_support.rs index 43d39be7ee..b0c8fd8a94 100644 --- a/crates/openshell-server/src/test_support.rs +++ b/crates/openshell-server/src/test_support.rs @@ -15,6 +15,8 @@ use crate::tracing_bus::TracingLogBus; use futures::{Stream, stream}; use openshell_core::Config; #[cfg(unix)] +use openshell_core::proto::compute::v1::compute_driver_image_updates_server::ComputeDriverImageUpdatesServer; +#[cfg(unix)] use openshell_core::proto::compute::v1::compute_driver_server::ComputeDriverServer; use openshell_core::proto::compute::v1::{ CreateSandboxRequest, CreateSandboxResponse, DeleteSandboxRequest, DeleteSandboxResponse, @@ -232,6 +234,20 @@ impl FakeComputeDriver { self } + #[must_use] + pub fn with_sandbox_image_updates(self) -> Self { + self.with_state(|state| { + state + .capabilities + .extension + .as_mut() + .unwrap() + .supported_capabilities + .push(openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.into()); + }); + self + } + #[must_use] pub fn calls(&self) -> Vec { self.with_state(|state| state.calls.clone()) @@ -260,7 +276,8 @@ impl FakeComputeDriver { let driver = self.clone(); let task = tokio::spawn(async move { tonic::transport::Server::builder() - .add_service(ComputeDriverServer::new(driver)) + .add_service(ComputeDriverServer::new(driver.clone())) + .add_service(ComputeDriverImageUpdatesServer::new(driver)) .serve_with_incoming(UnixIncoming { listener }) .await }); @@ -326,7 +343,7 @@ impl Stream for UnixIncoming { } #[tonic::async_trait] -impl ComputeDriver for FakeComputeDriver { +impl openshell_core::compute::ComputeDriver for FakeComputeDriver { async fn update_sandbox_image( &self, request: Request, @@ -350,7 +367,22 @@ impl ComputeDriver for FakeComputeDriver { )) }) } +} + +#[tonic::async_trait] +impl openshell_core::proto::compute::v1::compute_driver_image_updates_server::ComputeDriverImageUpdates + for FakeComputeDriver +{ + async fn update_sandbox_image( + &self, + request: Request, + ) -> Result, Status> { + openshell_core::compute::ComputeDriver::update_sandbox_image(self, request).await + } +} +#[tonic::async_trait] +impl ComputeDriver for FakeComputeDriver { async fn authenticate_sandbox( &self, _request: Request, diff --git a/examples/isolation-backend-v8/src/driver.rs b/examples/isolation-backend-v8/src/driver.rs index 6f70347cff..adce131a8f 100644 --- a/examples/isolation-backend-v8/src/driver.rs +++ b/examples/isolation-backend-v8/src/driver.rs @@ -337,15 +337,6 @@ impl std::ops::Deref for DriverService { } #[tonic::async_trait] impl compute_driver_server::ComputeDriver for DriverService { - async fn update_sandbox_image( - &self, - _: Request, - ) -> Result, Status> { - Err(Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } - async fn get_capabilities( &self, _: Request, diff --git a/proto/compute_driver.proto b/proto/compute_driver.proto index a83ca1b019..3734db611d 100644 --- a/proto/compute_driver.proto +++ b/proto/compute_driver.proto @@ -45,13 +45,6 @@ service ComputeDriver { // Provision platform resources for a sandbox. rpc CreateSandbox(CreateSandboxRequest) returns (CreateSandboxResponse); - // Idempotently replace only the workload image of a stopped sandbox, retaining - // its stable resource and storage. Requires the optional capability - // openshell.compute.update-sandbox-image. Unsupported drivers return - // UNIMPLEMENTED without changing any resource. - rpc UpdateSandboxImage(UpdateSandboxImageRequest) - returns (UpdateSandboxImageResponse); - // Idempotently stop platform resources without deleting persistent state. rpc StopSandbox(StopSandboxRequest) returns (StopSandboxResponse); @@ -81,6 +74,19 @@ service ComputeDriver { rpc DeleteWorkspace(DeleteWorkspaceRequest) returns (DeleteWorkspaceResponse); } +// Optional image-update extension, served on the same endpoint as ComputeDriver. +// Keeping this separate preserves the baseline generated server trait for +// independently versioned external drivers. Drivers advertise +// openshell.compute.update-sandbox-image only when they serve this service; +// gateways must negotiate that capability before calling it. +service ComputeDriverImageUpdates { + // Idempotently replace only the workload image of a stopped sandbox, retaining + // its stable resource and storage. Unsupported drivers omit this service and + // return UNIMPLEMENTED without changing any resource. + rpc UpdateSandboxImage(UpdateSandboxImageRequest) + returns (UpdateSandboxImageResponse); +} + message GetCapabilitiesRequest { // Gateway protocol metadata. Drivers must reject unmet requirements. openshell.extension.v1.PeerMetadata gateway = 1; From fc8b1f62ab4e715fc056a350c8c832853513c72f Mon Sep 17 00:00:00 2001 From: sjenning <493891+sjenning@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:37:48 -0500 Subject: [PATCH 05/23] fix(gateway): preserve baseline factory and descriptor APIs Restore the original in-process driver trait object and existing instance enum. Register optional image updates through a default factory hook without requiring changes to existing drivers or factories, and require registration plus capability before mutation. Accept OpenShell-only descriptors while retaining strict validation of present update services. Cover baseline registration, missing-updater no-write behavior, descriptor validation, and both live Kubernetes retention lanes. Signed-off-by: sjenning <493891+sjenning@users.noreply.github.com> --- crates/openshell-core/README.md | 10 +- crates/openshell-core/src/compute.rs | 12 +- .../tests/compute_driver_compat.rs | 18 +- crates/openshell-driver-kubernetes/README.md | 4 +- .../src/routes.rs | 202 ++++++++++++++++-- crates/openshell-gateway/src/lib.rs | 21 +- crates/openshell-server/README.md | 13 ++ .../src/compute/image_update.rs | 74 ++++++- crates/openshell-server/src/compute/mod.rs | 51 +++-- .../src/compute_factory_compatibility.rs | 172 +++++++++++++++ .../src/grpc/sandbox/image_update_tests.rs | 1 + crates/openshell-server/src/lib.rs | 29 ++- 12 files changed, 536 insertions(+), 71 deletions(-) create mode 100644 crates/openshell-server/src/compute_factory_compatibility.rs diff --git a/crates/openshell-core/README.md b/crates/openshell-core/README.md index 707e3ec77b..0b694f1b1e 100644 --- a/crates/openshell-core/README.md +++ b/crates/openshell-core/README.md @@ -73,10 +73,12 @@ that support image updates additionally serve `ComputeDriverImageUpdates` on the same endpoint and advertise `openshell.compute.update-sandbox-image`. Drivers without that capability need no new generated-trait method. -Linked in-process drivers implement `openshell_core::compute::ComputeDriver` -in addition to the generated baseline trait. An empty implementation inherits -`UNIMPLEMENTED` for image updates; supporting drivers override the optional -method. The gateway negotiates the capability before invoking either path. +Existing linked in-process drivers and factories need no new trait or hook. +Only drivers opting into image updates implement +`openshell_core::compute::ComputeDriver` and register that implementation through +`ComputeDriverFactory::build_with_image_updates`. The default factory hook calls +the existing `build` method without an updater. The gateway requires both this +separate registration and the negotiated capability before invoking updates. ## Protobuf Struct Conversion diff --git a/crates/openshell-core/src/compute.rs b/crates/openshell-core/src/compute.rs index 57722752e3..ba9e6f546a 100644 --- a/crates/openshell-core/src/compute.rs +++ b/crates/openshell-core/src/compute.rs @@ -1,18 +1,18 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! In-process compute contract, separate from the baseline generated gRPC trait. +//! Opt-in in-process image updates, separate from the baseline driver contract. use crate::proto::compute::v1::{ UpdateSandboxImageRequest, UpdateSandboxImageResponse, compute_driver_server, }; -/// Gateway-facing in-process compute driver with optional image updates. +/// Optional in-process image updater, registered separately by a driver factory. /// -/// External servers implement the unchanged generated -/// [`compute_driver_server::ComputeDriver`] trait and, when supported, the -/// separate generated `ComputeDriverImageUpdates` service on the same endpoint. -/// In-process drivers use this default unless they advertise image updates. +/// Existing drivers need only the generated baseline trait, not this extension. +/// Supporting factories opt in through `ComputeDriverFactory::build_with_image_updates` +/// and advertise the image-update capability. External servers use the separate +/// generated `ComputeDriverImageUpdates` service on the same endpoint instead. #[tonic::async_trait] pub trait ComputeDriver: compute_driver_server::ComputeDriver { async fn update_sandbox_image( diff --git a/crates/openshell-core/tests/compute_driver_compat.rs b/crates/openshell-core/tests/compute_driver_compat.rs index 40f0124af5..81643cd4b1 100644 --- a/crates/openshell-core/tests/compute_driver_compat.rs +++ b/crates/openshell-core/tests/compute_driver_compat.rs @@ -1,8 +1,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Fixed baseline server source fixture from 6546691d5e493343c7877573252e835d28bf9e23. -//! It deliberately implements only the original generated `ComputeDriver` methods, +//! Baseline server source fixture adapted for the upstream suspend RPC. +//! It deliberately implements only the baseline generated `ComputeDriver` methods, //! including its concrete streaming associated type, with no image-update method //! or in-process extension trait. New optional RPCs must not break this source. @@ -12,9 +12,9 @@ use openshell_core::proto::compute::v1::{ DeleteWorkspaceResponse, EnsureWorkspaceRequest, EnsureWorkspaceResponse, GetCapabilitiesRequest, GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse, ListSandboxesRequest, ListSandboxesResponse, StartSandboxRequest, StartSandboxResponse, - StopSandboxRequest, StopSandboxResponse, UpdateSandboxImageRequest, UpdateSandboxImageResponse, - ValidateSandboxCreateRequest, ValidateSandboxCreateResponse, WatchSandboxesEvent, - WatchSandboxesRequest, + StopSandboxRequest, StopSandboxResponse, SuspendSandboxRequest, SuspendSandboxResponse, + UpdateSandboxImageRequest, UpdateSandboxImageResponse, ValidateSandboxCreateRequest, + ValidateSandboxCreateResponse, WatchSandboxesEvent, WatchSandboxesRequest, compute_driver_client::ComputeDriverClient, compute_driver_image_updates_client::ComputeDriverImageUpdatesClient, compute_driver_image_updates_server::{ @@ -87,6 +87,13 @@ impl ComputeDriver for BaselineDriver { Err(Status::unimplemented("fixture")) } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("fixture")) + } + async fn start_sandbox( &self, _request: Request, @@ -273,6 +280,7 @@ fn baseline_compute_service_methods_are_frozen() { "CreateSandbox", "StopSandbox", "StartSandbox", + "SuspendSandbox", "DeleteSandbox", "WatchSandboxes", "EnsureWorkspace", diff --git a/crates/openshell-driver-kubernetes/README.md b/crates/openshell-driver-kubernetes/README.md index 9237f76d00..2958409344 100644 --- a/crates/openshell-driver-kubernetes/README.md +++ b/crates/openshell-driver-kubernetes/README.md @@ -305,7 +305,9 @@ a usable stopped condition, so pod deletion alone confirms their stop. The optional `openshell.compute.update-sandbox-image` capability supports image-only updates while the sandbox is stopped. External drivers serve it as the separate `ComputeDriverImageUpdates` service on the baseline `ComputeDriver` -endpoint, preserving the baseline generated server trait. `UpdateSandboxImage` requires +endpoint, preserving the baseline generated server trait. The linked gateway +factory opts in through `ComputeDriverFactory::build_with_image_updates` without +changing the baseline driver object. `UpdateSandboxImage` requires the persisted Kubernetes runtime identity, current image, sandbox name, and a stable operation ID with a monotonic image revision. The driver verifies that the same Sandbox resource is suspended, runtime bootstrap has completed, and diff --git a/crates/openshell-gateway-interceptors/src/routes.rs b/crates/openshell-gateway-interceptors/src/routes.rs index dcb98ec5bc..30e053e323 100644 --- a/crates/openshell-gateway-interceptors/src/routes.rs +++ b/crates/openshell-gateway-interceptors/src/routes.rs @@ -62,17 +62,23 @@ impl OpenShellRouteIndex { } pub(crate) fn from_descriptor_pool(pool: &DescriptorPool) -> Result { + let open_shell = pool + .get_service_by_name(SERVICE_OPEN_SHELL) + .ok_or_else(|| { + InterceptorError::Config(format!( + "descriptor set does not contain service '{SERVICE_OPEN_SHELL}'" + )) + })?; + // SandboxUpdates is an optional extension: baseline descriptor sets + // still need only OpenShell, but a present extension must be valid. + let sandbox_updates = pool.get_service_by_name(SERVICE_SANDBOX_UPDATES); let mut all_methods = BTreeSet::new(); let mut unary_methods = BTreeSet::new(); let mut input_types = BTreeMap::new(); let mut output_types = BTreeMap::new(); - for service_name in [SERVICE_OPEN_SHELL, SERVICE_SANDBOX_UPDATES] { - let service = pool.get_service_by_name(service_name).ok_or_else(|| { - InterceptorError::Config(format!( - "descriptor set does not contain service '{service_name}'" - )) - })?; + for service in std::iter::once(&open_shell).chain(sandbox_updates.as_ref()) { + let service_name = service.full_name(); for method in service.methods() { let route = format!("{service_name}/{}", method.name()); all_methods.insert(route.clone()); @@ -90,7 +96,13 @@ impl OpenShellRouteIndex { input_types, output_types, }; - index.validate_interceptable_list()?; + index.validate_interceptable_list(SERVICE_OPEN_SHELL, INTERCEPTABLE_METHODS)?; + if sandbox_updates.is_some() { + index.validate_interceptable_list( + SERVICE_SANDBOX_UPDATES, + INTERCEPTABLE_SANDBOX_UPDATE_METHODS, + )?; + } Ok(index) } @@ -118,23 +130,15 @@ impl OpenShellRouteIndex { .map(String::as_str) } - fn validate_interceptable_list(&self) -> Result<()> { + fn validate_interceptable_list(&self, service: &str, methods: &[&str]) -> Result<()> { let mut stale = Vec::new(); let mut streaming = Vec::new(); - for (service, methods) in [ - (SERVICE_OPEN_SHELL, INTERCEPTABLE_METHODS), - ( - SERVICE_SANDBOX_UPDATES, - INTERCEPTABLE_SANDBOX_UPDATE_METHODS, - ), - ] { - for method in methods { - let route = format!("{service}/{method}"); - if !self.all_methods.contains(&route) { - stale.push(route); - } else if !self.unary_methods.contains(&route) { - streaming.push(route); - } + for method in methods { + let route = format!("{service}/{method}"); + if !self.all_methods.contains(&route) { + stale.push(route); + } else if !self.unary_methods.contains(&route) { + streaming.push(route); } } if !stale.is_empty() { @@ -153,8 +157,158 @@ impl OpenShellRouteIndex { #[cfg(test)] mod tests { + use prost::Message; + use prost_types::{FileDescriptorSet, ServiceDescriptorProto}; + use super::*; + fn descriptor_set() -> FileDescriptorSet { + FileDescriptorSet::decode(openshell_core::FILE_DESCRIPTOR_SET).unwrap() + } + + fn service_mut<'a>( + descriptors: &'a mut FileDescriptorSet, + name: &str, + ) -> &'a mut ServiceDescriptorProto { + descriptors + .file + .iter_mut() + .filter(|file| file.package.as_deref() == Some("openshell.v1")) + .flat_map(|file| &mut file.service) + .find(|service| service.name.as_deref() == Some(name)) + .unwrap() + } + + #[test] + fn open_shell_only_descriptor_set_is_accepted() { + let mut descriptors = descriptor_set(); + for file in &mut descriptors.file { + file.service.retain(|service| { + file.package.as_deref() == Some("openshell.v1") + && service.name.as_deref() == Some("OpenShell") + }); + } + + let index = OpenShellRouteIndex::from_descriptor_set(&descriptors.encode_to_vec()).unwrap(); + for method in INTERCEPTABLE_METHODS { + assert!(index.is_interceptable(SERVICE_OPEN_SHELL, method)); + assert!(index.input_type(SERVICE_OPEN_SHELL, method).is_some()); + assert!(index.output_type(SERVICE_OPEN_SHELL, method).is_some()); + } + assert!(!index.is_interceptable(SERVICE_SANDBOX_UPDATES, "UpdateSandbox")); + assert!( + index + .input_type(SERVICE_SANDBOX_UPDATES, "UpdateSandbox") + .is_none() + ); + assert!( + index + .output_type(SERVICE_SANDBOX_UPDATES, "UpdateSandbox") + .is_none() + ); + } + + #[test] + fn missing_open_shell_service_is_rejected() { + let mut descriptors = descriptor_set(); + for file in &mut descriptors.file { + file.service + .retain(|service| service.name.as_deref() != Some("OpenShell")); + } + + let error = + OpenShellRouteIndex::from_descriptor_set(&descriptors.encode_to_vec()).unwrap_err(); + assert!(error.to_string().contains(&format!( + "descriptor set does not contain service '{SERVICE_OPEN_SHELL}'" + ))); + } + + #[test] + fn present_sandbox_updates_service_requires_update_sandbox() { + let mut descriptors = descriptor_set(); + service_mut(&mut descriptors, "SandboxUpdates") + .method + .clear(); + + let error = + OpenShellRouteIndex::from_descriptor_set(&descriptors.encode_to_vec()).unwrap_err(); + assert!(error.to_string().contains("stale methods")); + assert!( + error + .to_string() + .contains("openshell.v1.SandboxUpdates/UpdateSandbox") + ); + } + + #[test] + fn streaming_update_sandbox_is_rejected() { + for (client_streaming, server_streaming) in [(true, false), (false, true), (true, true)] { + let mut descriptors = descriptor_set(); + let method = &mut service_mut(&mut descriptors, "SandboxUpdates").method[0]; + assert_eq!(method.name.as_deref(), Some("UpdateSandbox")); + method.client_streaming = Some(client_streaming); + method.server_streaming = Some(server_streaming); + + let error = + OpenShellRouteIndex::from_descriptor_set(&descriptors.encode_to_vec()).unwrap_err(); + assert!(error.to_string().contains("streaming methods")); + assert!( + error + .to_string() + .contains("openshell.v1.SandboxUpdates/UpdateSandbox") + ); + } + } + + #[test] + fn unlisted_sandbox_update_methods_are_not_interceptable() { + let mut descriptors = descriptor_set(); + let service = service_mut(&mut descriptors, "SandboxUpdates"); + let mut future_method = service.method[0].clone(); + future_method.name = Some("FutureUnaryMethod".to_string()); + service.method.push(future_method); + + let index = OpenShellRouteIndex::from_descriptor_set(&descriptors.encode_to_vec()).unwrap(); + assert!(index.is_interceptable(SERVICE_SANDBOX_UPDATES, "UpdateSandbox")); + assert!(!index.is_interceptable(SERVICE_SANDBOX_UPDATES, "FutureUnaryMethod")); + assert_eq!( + index.input_type(SERVICE_SANDBOX_UPDATES, "FutureUnaryMethod"), + Some("openshell.v1.UpdateSandboxRequest") + ); + } + + #[test] + fn open_shell_allowlist_validation_remains_required() { + let mut missing_method = descriptor_set(); + service_mut(&mut missing_method, "OpenShell") + .method + .retain(|method| method.name.as_deref() != Some("CreateSandbox")); + let error = + OpenShellRouteIndex::from_descriptor_set(&missing_method.encode_to_vec()).unwrap_err(); + assert!(error.to_string().contains("stale methods")); + assert!( + error + .to_string() + .contains("openshell.v1.OpenShell/CreateSandbox") + ); + + let mut streaming_method = descriptor_set(); + let method = service_mut(&mut streaming_method, "OpenShell") + .method + .iter_mut() + .find(|method| method.name.as_deref() == Some("CreateSandbox")) + .unwrap(); + method.server_streaming = Some(true); + let error = OpenShellRouteIndex::from_descriptor_set(&streaming_method.encode_to_vec()) + .unwrap_err(); + assert!(error.to_string().contains("streaming methods")); + assert!( + error + .to_string() + .contains("openshell.v1.OpenShell/CreateSandbox") + ); + } + #[test] fn interceptable_entries_match_real_unary_methods() { OpenShellRouteIndex::from_descriptor_set(openshell_core::FILE_DESCRIPTOR_SET).unwrap(); @@ -168,6 +322,10 @@ mod tests { assert!(index.is_interceptable(SERVICE_SANDBOX_UPDATES, "UpdateSandbox")); assert!(!index.is_interceptable(SERVICE_OPEN_SHELL, "UpdateSandbox")); assert!(!index.is_interceptable(SERVICE_SANDBOX_UPDATES, "CreateSandbox")); + assert_eq!( + index.input_type(SERVICE_OPEN_SHELL, "CreateSandbox"), + Some("openshell.v1.CreateSandboxRequest") + ); assert_eq!( index.input_type(SERVICE_SANDBOX_UPDATES, "UpdateSandbox"), Some("openshell.v1.UpdateSandboxRequest") diff --git a/crates/openshell-gateway/src/lib.rs b/crates/openshell-gateway/src/lib.rs index a6a50774b6..280a3d16e0 100644 --- a/crates/openshell-gateway/src/lib.rs +++ b/crates/openshell-gateway/src/lib.rs @@ -289,6 +289,18 @@ impl openshell_server::ComputeDriverFactory for KubernetesFactory { &self, context: openshell_server::ComputeDriverBuildContext<'_>, ) -> openshell_core::Result { + self.build_with_image_updates(context) + .await + .map(|(instance, _)| instance) + } + + async fn build_with_image_updates( + &self, + context: openshell_server::ComputeDriverBuildContext<'_>, + ) -> openshell_core::Result<( + openshell_server::ComputeDriverInstance, + Option, + )> { let mut config = kubernetes_config(context.config_context())?; config.supervisor_otlp_endpoint = context .otlp_config() @@ -330,9 +342,12 @@ impl openshell_server::ComputeDriverFactory for KubernetesFactory { .await } .map_err(|error| openshell_core::Error::execution(error.to_string()))?; - let driver = openshell_driver_kubernetes::ComputeDriverService::new_in_process(driver); - Ok(openshell_server::ComputeDriverInstance::InProcess( - std::sync::Arc::new(driver), + let driver = std::sync::Arc::new( + openshell_driver_kubernetes::ComputeDriverService::new_in_process(driver), + ); + Ok(( + openshell_server::ComputeDriverInstance::InProcess(driver.clone()), + Some(driver), )) } } diff --git a/crates/openshell-server/README.md b/crates/openshell-server/README.md index 3af2d80f6a..1f98ebeb91 100644 --- a/crates/openshell-server/README.md +++ b/crates/openshell-server/README.md @@ -123,6 +123,19 @@ or two minutes after the withdrawal, after their owner was told to stop them. Pool members still authenticate with the one shared supervisor token, so a member identity is asserted by its hello rather than bound to its Pod. +## Optional in-process image updates + +`SharedComputeDriver` retains the generated baseline compute-driver trait, and +`ComputeDriverInstance` retains its existing variants. Existing compiled drivers +and factories need no new trait implementation or registration method. + +A supporting factory overrides `ComputeDriverFactory::build_with_image_updates` +to return its ordinary instance plus a separately registered image updater. The +default calls the existing `build` method and returns no updater. The gateway +requires both this opt-in and the negotiated capability before recording image +intent. Remote drivers register the separate `ComputeDriverImageUpdates` service +on their existing endpoint instead. + ## Operator credential export `GetProviderCredentials` exports selected profile-declared runtime environment diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs index 3eb11f65f3..407a795a5a 100644 --- a/crates/openshell-server/src/compute/image_update.rs +++ b/crates/openshell-server/src/compute/image_update.rs @@ -53,6 +53,11 @@ impl ComputeRuntime { "compute driver does not support storage-preserving sandbox image updates", )); } + if self.image_update_driver.is_none() { + return Err(Status::unimplemented( + "compute driver has no registered image updater", + )); + } let lifecycle_guard = self.lifecycle_gates.lock_for(sandbox_id).await; let sandbox_guard = self.lock_sandbox_for_lifecycle(&lifecycle_guard).await; let current = self @@ -112,15 +117,7 @@ impl ComputeRuntime { current } else { let request = image_update_driver_request(¤t, &intent, true); - self.driver - .call_owned( - openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, - Some(sandbox_id), - move |driver| async move { - driver.update_sandbox_image(Request::new(request)).await - }, - ) - .await?; + self.call_image_update_driver(request).await?; // The private intent, desired image, and OLD-understood pending // operation flag commit in one version-fenced transaction. self.store @@ -156,8 +153,7 @@ impl ComputeRuntime { ) -> Result { ensure_image_update_interlock(&pending, &intent)?; let request = image_update_driver_request(&pending, &intent, false); - self.driver.call_owned(openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, Some(pending.object_id()), - move |driver| async move { driver.update_sandbox_image(Request::new(request)).await }).await?; + self.call_image_update_driver(request).await?; let _guard = self.lock_sandbox_local(pending.object_id()).await; // An ambiguous error NEVER clears either the private intent or the // public operation interlock. Only exact successful reconciliation can. @@ -175,6 +171,28 @@ impl ComputeRuntime { Ok(updated) } + async fn call_image_update_driver( + &self, + request: UpdateSandboxImageRequest, + ) -> Result< + tonic::Response, + Status, + > { + let driver = self.image_update_driver.clone().ok_or_else(|| { + Status::unimplemented("compute driver has no registered image updater") + })?; + let sandbox_id = request.sandbox_id.clone(); + self.driver + .call_owned( + openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, + Some(&sandbox_id), + move |_baseline| async move { + driver.update_sandbox_image(Request::new(request)).await + }, + ) + .await + } + pub(super) async fn ensure_no_pending_image_update( &self, sandbox: &Sandbox, @@ -279,6 +297,7 @@ mod tests { .unwrap(); runtime.image_updates_enabled = true; if supported { + runtime.image_update_driver = Some(driver.clone()); runtime .driver_info .negotiated_extension @@ -414,6 +433,39 @@ mod tests { assert_eq!(image_calls(&driver)[1].revision, 2); } + #[tokio::test] + async fn image_update_rejects_unregistered_updater_without_writes() { + let (mut runtime, driver, original) = fixture(true).await; + runtime.image_update_driver = None; + driver.clear_calls(); + let error = runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + assert_eq!(error.code(), Code::Unimplemented); + assert!(driver.calls().is_empty()); + assert_eq!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap(), + Some(original.clone()) + ); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_none() + ); + } + #[tokio::test] async fn image_update_rejects_unsupported_driver_and_stale_version_without_writes() { let (runtime, driver, original) = fixture(false).await; diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index aab7e81b4b..9662051f93 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -85,7 +85,11 @@ use tracing::{Instrument as _, debug, info, warn}; pub type DriverWatchStream = Pin> + Send>>; -pub type SharedComputeDriver = Arc< +pub type SharedComputeDriver = + Arc + Send + Sync>; + +/// Optional image-update registration, independent of the baseline driver object. +pub type SharedComputeDriverImageUpdates = Arc< dyn openshell_core::compute::ComputeDriver + Send + Sync, @@ -912,6 +916,7 @@ pub struct ComputeRuntime { admission: openshell_core::resource_admission::DriverAdmissionConfig, admission_acknowledgement: String, driver: TracedDriver, + image_update_driver: Option, driver_info: ComputeDriverInfoSnapshot, telemetry_compute_driver: TelemetryComputeDriver, driver_process: Option>, @@ -1027,6 +1032,7 @@ impl ComputeRuntime { Ok(Self { isolation_backend: None, driver: TracedDriver::new(driver, driver_name), + image_update_driver: None, admission: openshell_core::resource_admission::DriverAdmissionConfig::default(), admission_acknowledgement: capabilities.resource_admission_policy, driver_info, @@ -1166,10 +1172,10 @@ impl ComputeRuntime { tracing_log_bus: TracingLogBus, supervisor_sessions: Arc, ) -> Result { - let driver: SharedComputeDriver = Arc::new(RemoteComputeDriver::new(endpoint.channel)); + let driver = Arc::new(RemoteComputeDriver::new(endpoint.channel)); Self::from_driver( endpoint.name, - driver, + driver.clone(), endpoint.driver_process, store, sandbox_index, @@ -1178,6 +1184,15 @@ impl ComputeRuntime { supervisor_sessions, ) .await + .map(|runtime| runtime.with_image_update_driver(Some(driver))) + } + + pub(crate) fn with_image_update_driver( + mut self, + driver: Option, + ) -> Self { + self.image_update_driver = driver; + self } #[must_use] @@ -8217,10 +8232,6 @@ impl Default for NoopTestDriver { } } -#[cfg(any(test, feature = "test-support"))] -#[tonic::async_trait] -impl openshell_core::compute::ComputeDriver for NoopTestDriver {} - #[cfg(any(test, feature = "test-support"))] #[tonic::async_trait] impl ComputeDriver for NoopTestDriver { @@ -8444,6 +8455,7 @@ pub fn new_test_runtime_with_driver( ComputeRuntime { isolation_backend: None, driver: TracedDriver::new(driver, "test".to_string()), + image_update_driver: None, admission: openshell_core::resource_admission::DriverAdmissionConfig { allow_driver_config: true, ..Default::default() @@ -8862,9 +8874,6 @@ mod tests { created_sandboxes: TestMutex>, } - #[tonic::async_trait] - impl openshell_core::compute::ComputeDriver for TestDriver {} - #[tonic::async_trait] impl ComputeDriver for TestDriver { async fn authenticate_sandbox( @@ -9647,6 +9656,7 @@ mod tests { ComputeRuntime { isolation_backend: None, driver: TracedDriver::new(driver, "test-driver".to_string()), + image_update_driver: None, admission: openshell_core::resource_admission::DriverAdmissionConfig { allow_driver_config: true, ..Default::default() @@ -18427,14 +18437,21 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" #[tokio::test] async fn in_process_driver_defaults_image_updates_to_unimplemented() { - let driver = NoopTestDriver::default(); - let error = openshell_core::compute::ComputeDriver::update_sandbox_image( - &driver, - Request::new(openshell_core::proto::compute::v1::UpdateSandboxImageRequest::default()), - ) - .await - .unwrap_err(); + // NoopTestDriver implements only the baseline generated trait. + let mut runtime = test_runtime(Arc::new(NoopTestDriver::default())) + .await + .with_sandbox_image_updates(true); + runtime + .driver_info + .negotiated_extension + .supported_capabilities + .push(openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.into()); + let error = runtime + .update_sandbox_image("not-created", "example/workload:v2".into(), 1) + .await + .unwrap_err(); assert_eq!(error.code(), Code::Unimplemented); + assert!(runtime.image_update_driver.is_none()); } #[tokio::test] diff --git a/crates/openshell-server/src/compute_factory_compatibility.rs b/crates/openshell-server/src/compute_factory_compatibility.rs new file mode 100644 index 0000000000..c009597076 --- /dev/null +++ b/crates/openshell-server/src/compute_factory_compatibility.rs @@ -0,0 +1,172 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Baseline factory source fixture: no image-update trait or new hook required. + +use std::collections::BTreeMap; +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use openshell_core::proto::compute::v1::compute_driver_server::ComputeDriver; + +use crate::test_support::FakeComputeDriver; +use crate::{ + ComputeDriverBuildContext, ComputeDriverFactory, ComputeDriverInstance, + ComputeDriverRegistration, ComputeDriverRegistry, DriverWatchStream, SharedComputeDriver, + SharedComputeDriverImageUpdates, +}; + +// Written using only the baseline generated trait, not the new optional trait. +type BaselineDriver = + Arc + Send + Sync>; + +struct BaselineFactory { + driver: BaselineDriver, + calls: Arc, +} + +#[async_trait::async_trait] +impl ComputeDriverFactory for BaselineFactory { + async fn build( + &self, + _context: ComputeDriverBuildContext<'_>, + ) -> openshell_core::Result { + self.calls.fetch_add(1, Ordering::SeqCst); + // This unchanged baseline expression must compile without a new trait. + Ok(ComputeDriverInstance::InProcess(self.driver.clone())) + } +} + +struct OptInFactory { + driver: Arc, + legacy_build_calls: Arc, + opt_in_calls: Arc, +} + +#[async_trait::async_trait] +impl ComputeDriverFactory for OptInFactory { + async fn build( + &self, + _context: ComputeDriverBuildContext<'_>, + ) -> openshell_core::Result { + self.legacy_build_calls.fetch_add(1, Ordering::SeqCst); + Ok(ComputeDriverInstance::InProcess(self.driver.clone())) + } + + async fn build_with_image_updates( + &self, + _context: ComputeDriverBuildContext<'_>, + ) -> openshell_core::Result<( + ComputeDriverInstance, + Option, + )> { + self.opt_in_calls.fetch_add(1, Ordering::SeqCst); + Ok(( + ComputeDriverInstance::InProcess(self.driver.clone()), + Some(self.driver.clone()), + )) + } +} + +async fn registered_runtime(factory: impl ComputeDriverFactory + 'static) -> crate::ComputeRuntime { + let mut registry = ComputeDriverRegistry::new(); + registry + .install(ComputeDriverRegistration::new("fixture", 0, None, factory).unwrap()) + .unwrap(); + let selection = registry.select(Some("fixture")).unwrap(); + let config = openshell_core::Config::new(None); + let overrides = BTreeMap::new(); + let startup = crate::compute::driver_config::DriverStartupContext { + file: None, + guest_tls: None, + gateway_port: 8080, + gateway_tls_enabled: false, + endpoint_overrides: &overrides, + }; + let store = Arc::new(crate::persistence::test_store().await); + crate::build_compute_runtime( + ®istry, + &selection, + &config, + startup, + store, + crate::sandbox_index::SandboxIndex::new(), + crate::sandbox_watch::SandboxWatchBus::new(), + crate::tracing_bus::TracingLogBus::new(), + Arc::new(crate::supervisor_session::SupervisorSessionRegistry::new()), + tokio::sync::watch::channel(false).1, + ) + .await + .unwrap() + .with_sandbox_image_updates(true) +} + +#[tokio::test] +async fn baseline_factory_and_trait_object_still_build_without_opt_in() { + // This concrete fixture implements only the baseline generated trait. + let driver: BaselineDriver = Arc::new(crate::compute::NoopTestDriver::default()); + let shared: SharedComputeDriver = driver.clone(); + // Exhaustive baseline enum match also prevents adding a required new variant. + match ComputeDriverInstance::InProcess(shared) { + ComputeDriverInstance::InProcess(actual) => assert!(Arc::ptr_eq(&actual, &driver)), + ComputeDriverInstance::ManagedRemote(_) => panic!("expected in-process driver"), + } + let calls = Arc::new(AtomicUsize::new(0)); + let runtime = registered_runtime(BaselineFactory { + driver, + calls: calls.clone(), + }) + .await; + assert_eq!(calls.load(Ordering::SeqCst), 1); + assert_eq!( + runtime + .update_sandbox_image("not-created", "example/workload:v2".into(), 1) + .await + .unwrap_err() + .code(), + tonic::Code::Unimplemented + ); +} + +#[tokio::test] +async fn capability_alone_does_not_register_an_in_process_image_updater() { + let driver = Arc::new(FakeComputeDriver::new().with_sandbox_image_updates()); + let runtime = registered_runtime(BaselineFactory { + driver: driver.clone(), + calls: Arc::new(AtomicUsize::new(0)), + }) + .await; + driver.clear_calls(); + assert_eq!( + runtime + .update_sandbox_image("not-created", "example/workload:v2".into(), 1) + .await + .unwrap_err() + .code(), + tonic::Code::Unimplemented + ); + assert!(driver.calls().is_empty()); +} + +#[tokio::test] +async fn registered_opt_in_hook_supplies_the_optional_updater() { + let legacy_calls = Arc::new(AtomicUsize::new(0)); + let opt_in_calls = Arc::new(AtomicUsize::new(0)); + let runtime = registered_runtime(OptInFactory { + driver: Arc::new(FakeComputeDriver::new().with_sandbox_image_updates()), + legacy_build_calls: legacy_calls.clone(), + opt_in_calls: opt_in_calls.clone(), + }) + .await; + assert_eq!(legacy_calls.load(Ordering::SeqCst), 0); + assert_eq!(opt_in_calls.load(Ordering::SeqCst), 1); + // Passing capability/registration admission reaches the sandbox lookup. + assert_eq!( + runtime + .update_sandbox_image("not-created", "example/workload:v2".into(), 1) + .await + .unwrap_err() + .code(), + tonic::Code::NotFound + ); +} 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 dbcf4c57cb..988b2aa267 100644 --- a/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs +++ b/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs @@ -151,6 +151,7 @@ async fn state() -> (Arc, Arc, Sandbox) { ) .await .unwrap() + .with_image_update_driver(Some(driver.clone())) .with_sandbox_image_updates(true); Arc::get_mut(&mut state).unwrap().compute = compute; let mut sandbox = Sandbox { diff --git a/crates/openshell-server/src/lib.rs b/crates/openshell-server/src/lib.rs index ab4af5b2d9..7e1961e546 100644 --- a/crates/openshell-server/src/lib.rs +++ b/crates/openshell-server/src/lib.rs @@ -1389,6 +1389,7 @@ async fn terminate_signal() { pub use compute::{ AcquiredRemoteDriverEndpoint, DriverWatchStream, ManagedDriverProcess, SharedComputeDriver, + SharedComputeDriverImageUpdates, }; /// Driver instance returned by a compiled compute-driver factory. @@ -1464,6 +1465,23 @@ pub trait ComputeDriverFactory: Send + Sync { } async fn build(&self, context: ComputeDriverBuildContext<'_>) -> Result; + + /// Build with a separately registered, optional in-process image updater. + /// + /// Existing factories only implement `build`; their baseline driver object + /// remains sufficient and this hook defaults to no image-update support. + /// Supporting factories return the same driver instance in both slots and + /// advertise the negotiated image-update capability. Remote drivers expose + /// their extension over the existing endpoint instead of using this hook. + async fn build_with_image_updates( + &self, + context: ComputeDriverBuildContext<'_>, + ) -> Result<( + ComputeDriverInstance, + Option, + )> { + self.build(context).await.map(|instance| (instance, None)) + } } /// One named compiled-driver registration. @@ -1914,7 +1932,10 @@ async fn build_compute_runtime( supervisor_recovery_timeout_secs: supervisor_pool .and_then(|pool| pool.recovery_timeout_secs), }; - let instance = registration.factory.build(build_context).await?; + let (instance, image_updates) = registration + .factory + .build_with_image_updates(build_context) + .await?; let supervisor_host = shared_supervision .into_inner() .map(|supervision| supervision.controller().clone()); @@ -1936,7 +1957,8 @@ async fn build_compute_runtime( .map_err(|error| { Error::execution(format!("failed to create compute runtime: {error}")) })? - .with_supervisor_host(supervisor_host), + .with_supervisor_host(supervisor_host) + .with_image_update_driver(image_updates), ComputeDriverInstance::ManagedRemote(_) if supervisor_host.is_some() => { return Err(Error::config( "only an in-process compute driver can use the gateway's shared supervision", @@ -2211,6 +2233,9 @@ pub(crate) async fn ensure_default_workspace(store: &Store) -> Result<()> { } } +#[cfg(test)] +mod compute_factory_compatibility; + #[cfg(test)] mod tests { use super::{ From 81c2da35f23f8fce63e9f1a439bfd9c7f275fda2 Mon Sep 17 00:00:00 2001 From: sjenning <493891+sjenning@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:50:30 -0500 Subject: [PATCH 06/23] chore(ci): use upstream Kubernetes E2E defaults Drop the task-level fallback superseded by main's runner defaults and explicit e2e-conformance-only selector. Preserve current upstream task definitions and recovery waiver unchanged. Signed-off-by: sjenning <493891+sjenning@users.noreply.github.com> --- tasks/test.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tasks/test.toml b/tasks/test.toml index d4b16d5026..7714d14dd4 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -240,10 +240,7 @@ run = "e2e/rust/e2e-podman.sh" ["e2e:kubernetes"] description = "Run Rust CLI e2e tests against an OpenShell gateway deployed on Kubernetes via Helm (set OPENSHELL_E2E_KUBE_CONTEXT to reuse a cluster; otherwise creates a local k3d cluster when k3d is installed; set OPENSHELL_E2E_KUBE_TEST= to scope to one test)" -# The reusable CI workflow exports an empty feature input by default. Restore -# the normal Rust suite here, not in the runner: the external-driver task -# intentionally passes an empty feature set for conformance-only coverage. -run = 'OPENSHELL_E2E_KUBERNETES_FEATURES="${OPENSHELL_E2E_KUBERNETES_FEATURES:-e2e,e2e-host-gateway,e2e-kubernetes}" e2e/rust/e2e-kubernetes.sh' +run = "e2e/rust/e2e-kubernetes.sh" ["e2e:kubernetes:v1alpha1"] description = "Run Kubernetes e2e against Agent Sandbox v1alpha1" From 5c2e96b0e0d11e48b79c4402142fae2ec534fdda Mon Sep 17 00:00:00 2001 From: sjenning <493891+sjenning@users.noreply.github.com> Date: Fri, 16 Oct 2026 15:10:32 -0500 Subject: [PATCH 07/23] fix(gateway): integrate image updates with backend protocol Adapt non-launch image updates to the upstream remote admission API while retaining resource-policy verification before forwarding. Cover both negotiated extensions and preservation of backend pins and persisted launch identity. Signed-off-by: sjenning <493891+sjenning@users.noreply.github.com> --- .../openshell-core/src/extension_protocol.rs | 18 ++++++++++++ .../src/compute/image_update.rs | 28 +++++++++++++++---- crates/openshell-server/src/compute/mod.rs | 20 ++++++++++++- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/crates/openshell-core/src/extension_protocol.rs b/crates/openshell-core/src/extension_protocol.rs index 370c642bce..92aecc7b46 100644 --- a/crates/openshell-core/src/extension_protocol.rs +++ b/crates/openshell-core/src/extension_protocol.rs @@ -131,6 +131,7 @@ pub fn gateway_metadata(family: ExtensionFamily) -> PeerMetadata { if family == ExtensionFamily::Compute { supported_capabilities.push(COMPUTE_LAUNCH_AUTHENTICATION.to_string()); supported_capabilities.push(COMPUTE_ISOLATION_BACKEND.to_string()); + supported_capabilities.push(COMPUTE_UPDATE_SANDBOX_IMAGE.to_string()); } PeerMetadata { protocol_version: Some(ProtocolVersion { @@ -402,6 +403,23 @@ fn valid_capability(value: &str) -> bool { mod tests { use super::*; + #[test] + fn compute_gateway_advertises_both_optional_extensions() { + let gateway = gateway_metadata(ExtensionFamily::Compute); + assert!( + gateway + .supported_capabilities + .iter() + .any(|c| c == COMPUTE_ISOLATION_BACKEND) + ); + assert!( + gateway + .supported_capabilities + .iter() + .any(|c| c == COMPUTE_UPDATE_SANDBOX_IMAGE) + ); + } + fn compatible() -> (PeerMetadata, PeerMetadata) { let gateway = gateway_metadata(ExtensionFamily::Compute); let extension = extension_metadata( diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs index 407a795a5a..76c14f3375 100644 --- a/crates/openshell-server/src/compute/image_update.rs +++ b/crates/openshell-server/src/compute/image_update.rs @@ -310,10 +310,16 @@ mod tests { name: "image-sandbox".into(), workspace: "default".into(), labels: HashMap::from([("app".into(), "retained".into())]), - annotations: HashMap::from([( - COMPUTE_RUNTIME_IDENTITY_ANNOTATION.into(), - "stable-runtime".into(), - )]), + annotations: HashMap::from([ + ( + COMPUTE_RUNTIME_IDENTITY_ANNOTATION.into(), + "stable-runtime".into(), + ), + ( + crate::compute::ISOLATION_BACKEND_ANNOTATION.into(), + openshell_core::isolation_registration::BUILTIN_BACKEND_NAME.into(), + ), + ]), ..Default::default() }), spec: Some(SandboxSpec { @@ -353,7 +359,19 @@ mod tests { #[tokio::test] async fn image_update_preserves_identity_and_every_other_spec_field() { - let (runtime, driver, original) = fixture(true).await; + let (runtime, driver, mut original) = fixture(true).await; + // Image edits must preserve the upstream backend pin and launch identity, + // including generation/session and authorization epoch annotations. + crate::auth::sandbox_session::PersistedSandboxIdentity::new() + .unwrap() + .write(&mut original.metadata.as_mut().unwrap().annotations); + runtime.store.put_message(&original).await.unwrap(); + let original = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); let updated = runtime .update_sandbox_image( original.object_id(), diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index 9662051f93..ce55c5b5cd 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -752,6 +752,7 @@ impl openshell_core::compute::ComputeDriver for RemoteComputeDriver { tonic::Response, Status, > { + // An image-only update does not install an external isolation route. self.verify_admission_policy(false).await?; self.image_updates_client .clone() @@ -18317,9 +18318,16 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" .await .is_err() ); + let status = openshell_core::compute::ComputeDriver::update_sandbox_image( + &remote, + Request::new(openshell_core::proto::compute::v1::UpdateSandboxImageRequest::default()), + ) + .await + .unwrap_err(); + assert_eq!(status.code(), Code::FailedPrecondition); assert_eq!( driver.calls(), - vec![FakeComputeDriverCall::GetCapabilities; 3] + vec![FakeComputeDriverCall::GetCapabilities; 4] ); } @@ -18356,6 +18364,16 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" .await .unwrap(); runtime.image_updates_enabled = true; + assert!( + !runtime + .driver_info + .negotiated_extension + .supported_capabilities + .iter() + .any(|capability| capability + == openshell_core::extension_protocol::COMPUTE_ISOLATION_BACKEND), + "image-only updates do not require external isolation registration" + ); assert_eq!( runtime .driver_info From 3ce3612c83b4efd1028f508bfb54f8425892adb3 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Thu, 22 Oct 2026 10:59:29 +0100 Subject: [PATCH 08/23] fix(gateway): remove sandbox image state on deletion Signed-off-by: Gordon Sim --- .../src/compute/image_update.rs | 78 +++++++++++++++++++ crates/openshell-server/src/compute/mod.rs | 4 + .../src/persistence/sandbox_image.rs | 9 +++ 3 files changed, 91 insertions(+) diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs index 76c14f3375..b08f3d2f4d 100644 --- a/crates/openshell-server/src/compute/image_update.rs +++ b/crates/openshell-server/src/compute/image_update.rs @@ -451,6 +451,84 @@ mod tests { assert_eq!(image_calls(&driver)[1].revision, 2); } + #[tokio::test] + async fn image_update_state_is_removed_on_sandbox_deletion() { + for out_of_band in [false, true] { + let (runtime, _, original) = fixture(true).await; + let mut unrelated = original.clone(); + let metadata = unrelated.metadata.as_mut().unwrap(); + metadata.id = "unrelated-sandbox-id".into(); + metadata.name = "unrelated-sandbox".into(); + runtime.store.put_message(&unrelated).await.unwrap(); + let unrelated = runtime + .store + .get_message::(unrelated.object_id()) + .await + .unwrap() + .unwrap(); + for sandbox in [&original, &unrelated] { + runtime + .update_sandbox_image( + sandbox.object_id(), + "example/workload:new".into(), + sandbox.get_resource_version(), + ) + .await + .unwrap(); + } + let unrelated_state = runtime + .store + .get_sandbox_image_state(unrelated.object_id()) + .await + .unwrap() + .unwrap(); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_some() + ); + + // Exercise explicit deletion and watch-driven removal, including + // a delayed or repeated watch deletion event. + if out_of_band { + runtime.apply_deleted(original.object_id()).await.unwrap(); + } else { + runtime + .delete_sandbox("default", original.object_name()) + .await + .unwrap(); + } + runtime.apply_deleted(original.object_id()).await.unwrap(); + assert!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .is_none() + ); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_none() + ); + assert_eq!( + runtime + .store + .get_sandbox_image_state(unrelated.object_id()) + .await + .unwrap(), + Some(unrelated_state) + ); + } + } + #[tokio::test] async fn image_update_rejects_unregistered_updater_without_writes() { let (mut runtime, driver, original) = fixture(true).await; diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index ce55c5b5cd..f7e331fada 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -6205,6 +6205,10 @@ impl ComputeRuntime { } async fn cleanup_sandbox_owned_records(&self, sandbox: &Sandbox) -> Result<(), String> { + self.store + .delete_sandbox_image_state(sandbox.object_id()) + .await + .map_err(|error| format!("delete sandbox image state: {error}"))?; self.cleanup_ssh_identity(sandbox) .await .map_err(|error| error.to_string())?; diff --git a/crates/openshell-server/src/persistence/sandbox_image.rs b/crates/openshell-server/src/persistence/sandbox_image.rs index 88a2bc7d32..a427062ffb 100644 --- a/crates/openshell-server/src/persistence/sandbox_image.rs +++ b/crates/openshell-server/src/persistence/sandbox_image.rs @@ -257,6 +257,15 @@ fn project_complete( } impl Store { + /// Remove private image state when its owning sandbox is reclaimed. + pub(crate) async fn delete_sandbox_image_state( + &self, + sandbox_id: &str, + ) -> PersistenceResult { + self.delete(IMAGE_STATE_OBJECT_TYPE, &state_id(sandbox_id)) + .await + } + /// Read gateway-private image state by immutable sandbox identity. pub async fn get_sandbox_image_state( &self, From e7d4c5aade1d31195773ae7af3c8dd601a9e4041 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Fri, 23 Oct 2026 12:12:24 +0100 Subject: [PATCH 09/23] feat(gateway): expand UpdateSandbox configuration updates Signed-off-by: Gordon Sim --- .agents/skills/helm-dev-environment/SKILL.md | 9 +- Cargo.lock | 1 - crates/openshell-core/README.md | 8 +- crates/openshell-core/src/compute.rs | 17 +- crates/openshell-core/src/config.rs | 6 +- .../openshell-core/src/extension_protocol.rs | 3 + crates/openshell-core/src/lib.rs | 1 + crates/openshell-core/src/sandbox_update.rs | 48 + crates/openshell-driver-kubernetes/Cargo.toml | 1 - crates/openshell-driver-kubernetes/README.md | 10 + .../openshell-driver-kubernetes/src/driver.rs | 6 +- .../openshell-driver-kubernetes/src/grpc.rs | 23 + .../src/image_update.rs | 179 +- .../src/image_update_tests.rs | 145 + .../openshell-driver-kubernetes/src/main.rs | 3 + crates/openshell-otel/src/grpc.rs | 6 + crates/openshell-sdk/src/raw.rs | 12 +- crates/openshell-sdk/tests/client_mock.rs | 3 +- crates/openshell-server/README.md | 12 +- .../proto/sandbox_image.proto | 5 + crates/openshell-server/src/cli.rs | 43 +- .../src/compute/image_update.rs | 328 +- crates/openshell-server/src/compute/mod.rs | 36 +- .../src/compute/tests/error_recovery.rs | 6 + .../src/compute_factory_compatibility.rs | 2 +- crates/openshell-server/src/config_file.rs | 2 +- .../openshell-server/src/gateway_members.rs | 2 +- crates/openshell-server/src/grpc/sandbox.rs | 81 +- .../src/grpc/sandbox/image_update_tests.rs | 163 +- crates/openshell-server/src/lib.rs | 2 +- .../src/persistence/image_activation.rs | 16 +- .../src/persistence/postgres.rs | 2 +- .../src/persistence/sandbox_image.rs | 142 +- crates/openshell-server/src/storage_proto.rs | 19 +- crates/openshell-server/src/test_support.rs | 37 + docs/how-it-works/gateways/configuration.mdx | 21 +- docs/how-it-works/sandboxes/overview.mdx | 48 +- docs/kubernetes/high-availability.mdx | 12 +- docs/sdk/api-errors.mdx | 12 +- e2e/rust/tests/kubernetes_image_update.rs | 42 +- e2e/with-kube-gateway.sh | 2 +- proto/compute_driver.proto | 27 + proto/openshell.proto | 30 +- sdk/go/proto/openshellv1/openshell.pb.go | 3064 +++++++++-------- sdk/go/proto/openshellv1/openshell_grpc.pb.go | 14 +- .../compatibility/sandbox_updates_test.go | 6 +- skills/debug-openshell-cluster/SKILL.md | 16 +- skills/openshell-cli/SKILL.md | 17 +- 48 files changed, 3027 insertions(+), 1663 deletions(-) create mode 100644 crates/openshell-core/src/sandbox_update.rs diff --git a/.agents/skills/helm-dev-environment/SKILL.md b/.agents/skills/helm-dev-environment/SKILL.md index a6e7c3a0d5..1fb2ea6e3b 100644 --- a/.agents/skills/helm-dev-environment/SKILL.md +++ b/.agents/skills/helm-dev-environment/SKILL.md @@ -422,7 +422,8 @@ above) instead of relying only on `OPENSHELL_GATEWAY_ENDPOINT`; some tests call Use `mise run e2e:kubernetes` for the standard Helm-backed Kubernetes suite. Set `OPENSHELL_E2E_KUBE_TEST=kubernetes_image_update` to scope the Rust suite to -image replacement with retained sandbox, SSH, and PVC identities. This target is +combined image, command, environment, and metadata updates with retained sandbox, +SSH, and PVC identities. The next start verifies the new argv and environment. This target is included in both existing Agent Sandbox API-version lanes; unlike the Python Docker suite, it exercises the driver that supports image updates. @@ -432,9 +433,9 @@ in only for a fresh gateway fixture that it owns; set activation to an existing shared gateway or enable it during a mixed-version rollout. For manual testing, follow the retirement and activation checklist in `docs/kubernetes/high-availability.mdx` before setting -`gatewayConfig: {"openshell.gateway": {enable_sandbox_image_updates: true}}`. -The gateway process equivalents are `--enable-sandbox-image-updates true` and -`OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES=true`. Retire every old process and Job, +`gatewayConfig: {"openshell.gateway": {enable_sandbox_updates: true}}`. +The gateway process equivalents are `--enable-sandbox-updates true` and +`OPENSHELL_ENABLE_SANDBOX_UPDATES=true`. Retire every old process and Job, settle outstanding driver work, prevent old binaries returning, and do not treat PostgreSQL connection markers or membership TTL expiry as retirement proof. SQLite testing supports one gateway process only. Image-update clients diff --git a/Cargo.lock b/Cargo.lock index 97aa0f6cf5..073efa4e1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4546,7 +4546,6 @@ dependencies = [ "opentelemetry_sdk", "prost", "prost-types", - "rand 0.9.4", "rcgen", "regex", "rustls", diff --git a/crates/openshell-core/README.md b/crates/openshell-core/README.md index 0b694f1b1e..a7bd283572 100644 --- a/crates/openshell-core/README.md +++ b/crates/openshell-core/README.md @@ -65,7 +65,7 @@ configuration validation live in `openshell_core::middleware`. Policy admission and the supervisor runtime consume the same contract without introducing a dependency from the policy crate to the supervisor implementation. -## Optional Compute Image Updates +## Optional Compute Updates The generated `proto::compute::v1::compute_driver_server::ComputeDriver` trait retains its baseline methods and streaming associated type. External drivers @@ -73,6 +73,12 @@ that support image updates additionally serve `ComputeDriverImageUpdates` on the same endpoint and advertise `openshell.compute.update-sandbox-image`. Drivers without that capability need no new generated-trait method. +Drivers supporting command and environment replacement additionally serve +`ComputeDriverConfigurationUpdates` and advertise +`openshell.compute.update-sandbox-configuration`. Its separate typed request +retains image-update lifecycle preconditions. Both optional in-process methods +have `UNIMPLEMENTED` defaults, so image-only implementations remain valid. + Existing linked in-process drivers and factories need no new trait or hook. Only drivers opting into image updates implement `openshell_core::compute::ComputeDriver` and register that implementation through diff --git a/crates/openshell-core/src/compute.rs b/crates/openshell-core/src/compute.rs index ba9e6f546a..7e3f7046b0 100644 --- a/crates/openshell-core/src/compute.rs +++ b/crates/openshell-core/src/compute.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Opt-in in-process image updates, separate from the baseline driver contract. +//! Opt-in in-process sandbox updates, separate from the baseline driver contract. use crate::proto::compute::v1::{ UpdateSandboxImageRequest, UpdateSandboxImageResponse, compute_driver_server, @@ -12,9 +12,22 @@ use crate::proto::compute::v1::{ /// Existing drivers need only the generated baseline trait, not this extension. /// Supporting factories opt in through `ComputeDriverFactory::build_with_image_updates` /// and advertise the image-update capability. External servers use the separate -/// generated `ComputeDriverImageUpdates` service on the same endpoint instead. +/// generated `ComputeDriverImageUpdates` or `ComputeDriverConfigurationUpdates` +/// service on the same endpoint instead. Each operation requires its own capability. #[tonic::async_trait] pub trait ComputeDriver: compute_driver_server::ComputeDriver { + async fn update_sandbox_configuration( + &self, + _request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + > { + Err(tonic::Status::unimplemented( + "sandbox configuration updates are not supported by this driver", + )) + } + async fn update_sandbox_image( &self, _request: tonic::Request, diff --git a/crates/openshell-core/src/config.rs b/crates/openshell-core/src/config.rs index add555778e..308b9edb61 100644 --- a/crates/openshell-core/src/config.rs +++ b/crates/openshell-core/src/config.rs @@ -253,9 +253,9 @@ pub struct Config { pub enable_websocket_tunnel: bool, /// Operator activation after all gateways and outstanding legacy driver - /// operations have been drained onto the image-update-compatible protocol. + /// operations have been drained onto the configuration-update-compatible protocol. /// Disabled by default; not a license to run mixed-version writers. - pub enable_sandbox_image_updates: bool, + pub enable_sandbox_updates: bool, /// Disabled-by-default gateway interceptor service configs. pub gateway_interceptors: Vec, @@ -1004,7 +1004,7 @@ impl Config { oidc: None, auth: GatewayAuthConfig::default(), enable_websocket_tunnel: false, - enable_sandbox_image_updates: false, + enable_sandbox_updates: false, gateway_interceptors: Vec::new(), provider_profile_sources: vec![GatewayProviderProfileSourceConfig::User], mtls_auth: MtlsAuthConfig::default(), diff --git a/crates/openshell-core/src/extension_protocol.rs b/crates/openshell-core/src/extension_protocol.rs index 92aecc7b46..fca1da3b46 100644 --- a/crates/openshell-core/src/extension_protocol.rs +++ b/crates/openshell-core/src/extension_protocol.rs @@ -26,6 +26,8 @@ pub const COMPUTE_ISOLATION_BACKEND: &str = "openshell.compute.isolation-backend pub const COMPUTE_SUSPEND_RESUME: &str = "openshell.compute.suspend-resume"; /// Optional stopped-state image updates retaining the resource and its storage. +pub const COMPUTE_UPDATE_SANDBOX_CONFIGURATION: &str = + "openshell.compute.update-sandbox-configuration"; pub const COMPUTE_UPDATE_SANDBOX_IMAGE: &str = "openshell.compute.update-sandbox-image"; const MAX_IMPLEMENTATION_NAME_BYTES: usize = 128; @@ -132,6 +134,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_IMAGE.to_string()); + supported_capabilities.push(COMPUTE_UPDATE_SANDBOX_CONFIGURATION.to_string()); } PeerMetadata { protocol_version: Some(ProtocolVersion { diff --git a/crates/openshell-core/src/lib.rs b/crates/openshell-core/src/lib.rs index 8baca88966..f16eb7c130 100644 --- a/crates/openshell-core/src/lib.rs +++ b/crates/openshell-core/src/lib.rs @@ -59,6 +59,7 @@ pub mod rpc_error; pub mod sandbox_env; pub mod sandbox_generation; pub mod sandbox_session; +pub mod sandbox_update; pub mod secrets; pub mod settings; pub mod shell; diff --git a/crates/openshell-core/src/sandbox_update.rs b/crates/openshell-core/src/sandbox_update.rs new file mode 100644 index 0000000000..8654c391e8 --- /dev/null +++ b/crates/openshell-core/src/sandbox_update.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Shared projections for selected stopped-sandbox configuration changes. +use crate::proto::{Sandbox, SandboxCommandUpdate, SandboxMapUpdate}; +use std::collections::HashMap; + +/// System metadata is never caller-replaceable, including subdomains. +#[must_use] +pub fn is_system_metadata_key(key: &str) -> bool { + key.split_once('/').is_some_and(|(domain, _)| { + domain == "openshell.ai" + || domain.ends_with(".openshell.ai") + || domain == "agents.x-k8s.io" + || domain.ends_with(".agents.x-k8s.io") + }) +} + +fn replace_user_metadata(current: &mut HashMap, update: &SandboxMapUpdate) { + current.retain(|key, _| is_system_metadata_key(key)); + current.extend(update.values.clone()); +} + +/// Caller must validate syntax and forbid system keys before projecting. +pub fn apply_configuration( + sandbox: &mut Sandbox, + command: Option<&SandboxCommandUpdate>, + environment: Option<&SandboxMapUpdate>, + labels: Option<&SandboxMapUpdate>, + annotations: Option<&SandboxMapUpdate>, +) { + if let Some(spec) = sandbox.spec.as_mut() { + if let Some(command) = command { + spec.command.clone_from(&command.argv); + } + if let Some(environment) = environment { + spec.environment.clone_from(&environment.values); + } + } + if let Some(metadata) = sandbox.metadata.as_mut() { + if let Some(labels) = labels { + replace_user_metadata(&mut metadata.labels, labels); + } + if let Some(annotations) = annotations { + replace_user_metadata(&mut metadata.annotations, annotations); + } + } +} diff --git a/crates/openshell-driver-kubernetes/Cargo.toml b/crates/openshell-driver-kubernetes/Cargo.toml index 37df72f614..c84713f2bf 100644 --- a/crates/openshell-driver-kubernetes/Cargo.toml +++ b/crates/openshell-driver-kubernetes/Cargo.toml @@ -43,7 +43,6 @@ tracing-subscriber = { workspace = true } thiserror = { workspace = true } miette = { workspace = true } notify = "8" -rand = { workspace = true } regex = { workspace = true } rcgen = { workspace = true } bytes = { workspace = true } diff --git a/crates/openshell-driver-kubernetes/README.md b/crates/openshell-driver-kubernetes/README.md index 2958409344..47fca1aca6 100644 --- a/crates/openshell-driver-kubernetes/README.md +++ b/crates/openshell-driver-kubernetes/README.md @@ -323,6 +323,16 @@ trusted runtime images, or bootstrap annotations. They leave the sandbox stopped. Existing workspace contents and the seed sentinel remain unchanged, so an image update does not replace files already stored under `/sandbox`. +The additional `openshell.compute.update-sandbox-configuration` capability and +`ComputeDriverConfigurationUpdates` service reconcile workload argv and effective +user environment with the image in one UID/resource-version-fenced patch. The +main-process annotation and agent environment supply the next runtime generation; +the trusted container launcher and runtime environment remain intact. Retry +records identify selected fields and verify their live target values without +copying environment values into operation evidence. Top-level public sandbox +labels and annotations remain gateway metadata; this operation does not change +Kubernetes pod metadata. + The workspace PVC size defaults to `workspace_default_storage_size`. Set `workspace_storage_class` to pin the PVC to a specific `StorageClass`; an empty value omits `storageClassName` so the cluster's default `StorageClass` applies. diff --git a/crates/openshell-driver-kubernetes/src/driver.rs b/crates/openshell-driver-kubernetes/src/driver.rs index f5a717abfc..6ebae66273 100644 --- a/crates/openshell-driver-kubernetes/src/driver.rs +++ b/crates/openshell-driver-kubernetes/src/driver.rs @@ -1344,7 +1344,11 @@ impl KubernetesComputeDriver { openshell_core::extension_protocol::ExtensionFamily::Compute, "openshell/kubernetes", openshell_core::VERSION, - [openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.to_string()], + [ + openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.to_string(), + openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION + .to_string(), + ], )), }) } diff --git a/crates/openshell-driver-kubernetes/src/grpc.rs b/crates/openshell-driver-kubernetes/src/grpc.rs index 06c2f0110a..ac972db536 100644 --- a/crates/openshell-driver-kubernetes/src/grpc.rs +++ b/crates/openshell-driver-kubernetes/src/grpc.rs @@ -339,6 +339,22 @@ impl ComputeDriver for ComputeDriverService { #[tonic::async_trait] impl openshell_core::compute::ComputeDriver for ComputeDriverService { + async fn update_sandbox_configuration( + &self, + request: Request, + ) -> Result< + Response, + Status, + > { + self.driver + .update_sandbox_configuration(&request.into_inner()) + .await + .map_err(|error| Status::from(openshell_core::ComputeDriverError::from(error)))?; + Ok(Response::new( + openshell_core::proto::compute::v1::UpdateSandboxConfigurationResponse {}, + )) + } + async fn update_sandbox_image( &self, request: Request, @@ -372,6 +388,13 @@ impl openshell_core::proto::compute::v1::compute_driver_image_updates_server::Co } } +#[tonic::async_trait] +impl openshell_core::proto::compute::v1::compute_driver_configuration_updates_server::ComputeDriverConfigurationUpdates for ComputeDriverService { + async fn update_sandbox_configuration(&self, request: Request) -> Result, Status> { + openshell_core::compute::ComputeDriver::update_sandbox_configuration(self, request).await + } +} + fn workspace_delete_requires_namespace_access(mode: WorkspaceMode) -> bool { matches!(mode, WorkspaceMode::Managed) } diff --git a/crates/openshell-driver-kubernetes/src/image_update.rs b/crates/openshell-driver-kubernetes/src/image_update.rs index fe7f805fc6..293bc45a39 100644 --- a/crates/openshell-driver-kubernetes/src/image_update.rs +++ b/crates/openshell-driver-kubernetes/src/image_update.rs @@ -28,6 +28,12 @@ struct ImageUpdateRecord { expected_image: String, image: String, revision: u64, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + configuration: bool, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + command_updated: bool, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + environment_updated: bool, } impl KubernetesComputeDriver { @@ -47,6 +53,27 @@ impl KubernetesComputeDriver { pub async fn update_sandbox_image( &self, request: &UpdateSandboxImageRequest, + ) -> Result<(), KubernetesDriverError> { + self.update_workload(request, None).await + } + + pub async fn update_sandbox_configuration( + &self, + request: &openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest, + ) -> Result<(), KubernetesDriverError> { + let image = request.image_update.as_ref().ok_or_else(|| { + KubernetesDriverError::InvalidArgument("image_update is required".into()) + })?; + validate_configuration(request)?; + self.update_workload(image, Some(request)).await + } + + async fn update_workload( + &self, + request: &UpdateSandboxImageRequest, + configuration: Option< + &openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest, + >, ) -> Result<(), KubernetesDriverError> { let span_status = openshell_otel::ErrorStatusGuard::current(); validate_image_update_request(request)?; @@ -56,21 +83,25 @@ impl KubernetesComputeDriver { .lock_owned() .await; // Include discovery, admission and Pod pagination in a single bound. - let result = - tokio::time::timeout(KUBE_API_TIMEOUT, self.update_sandbox_image_inner(request)) - .await - .unwrap_or_else(|_| { - Err(KubernetesDriverError::Message( - "timed out updating Kubernetes sandbox image; retry the same operation" - .into(), - )) - }); + let result = tokio::time::timeout( + KUBE_API_TIMEOUT, + self.update_sandbox_image_inner(request, configuration), + ) + .await + .unwrap_or_else(|_| { + Err(KubernetesDriverError::Message( + "timed out updating Kubernetes sandbox image; retry the same operation".into(), + )) + }); span_status.finish(result) } async fn update_sandbox_image_inner( &self, request: &UpdateSandboxImageRequest, + configuration: Option< + &openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest, + >, ) -> Result<(), KubernetesDriverError> { let expected = parse_kubernetes_runtime_identity(&request.expected_runtime_identity)?; self.wait_for_operator_allowlist() @@ -123,7 +154,10 @@ impl KubernetesComputeDriver { } require_stopped_for_image_update(&object, &lookup.resource.version)?; let mut candidate = object.clone(); - let repeat = prepare_image_update(&mut candidate, request)?; + let repeat = prepare_update(&mut candidate, request, configuration)?; + if let Some(configuration) = configuration { + prepare_configuration(&mut candidate, configuration, repeat)?; + } // Revalidate the saved provenance and attachment UIDs against current // operator policy, even for retries. Do not manufacture new provenance // or re-render driver_config from a caller's request. @@ -161,6 +195,16 @@ impl KubernetesComputeDriver { "containers": candidate.data["spec"]["podTemplate"]["spec"]["containers"] }}} }); + if configuration.is_some_and(|configuration| configuration.main_process.is_some()) { + let key = super::ANNOTATION_SANDBOX_RUNTIME_MAIN_PROCESS_SPEC; + patch["metadata"]["annotations"][key] = serde_json::json!( + candidate + .metadata + .annotations + .as_ref() + .and_then(|annotations| annotations.get(key)) + ); + } if let Some(init) = candidate .data .pointer("/spec/podTemplate/spec/initContainers") @@ -324,9 +368,10 @@ fn require_stopped_for_image_update( } /// Apply the image-only mutation in memory; return true for an exact retry. -fn prepare_image_update( +fn prepare_update( object: &mut DynamicObject, request: &UpdateSandboxImageRequest, + configuration: Option<&openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest>, ) -> Result { let evidence = object .metadata @@ -343,6 +388,9 @@ fn prepare_image_update( expected_image: request.expected_image.clone(), image: request.image.clone(), revision: request.revision, + configuration: configuration.is_some(), + command_updated: configuration.is_some_and(|value| value.main_process.is_some()), + environment_updated: configuration.is_some_and(|value| value.environment.is_some()), }; if let Some(saved) = &evidence { if request.revision < saved.revision { @@ -420,6 +468,115 @@ fn prepare_image_update( Ok(repeat) } +fn validate_configuration( + request: &openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest, +) -> Result<(), KubernetesDriverError> { + let invalid = |message: &str| KubernetesDriverError::InvalidArgument(message.into()); + if let Some(spec) = &request.main_process + && (spec.command.len() > 256 + || spec.command.iter().map(String::len).sum::() > 256 * 1024 + || spec.command.first().is_some_and(String::is_empty) + || spec.command.iter().any(|arg| arg.contains('\0'))) + { + return Err(invalid("invalid workload argv")); + } + if let Some(environment) = &request.environment { + if environment.values.len() > 256 + || environment + .values + .iter() + .map(|(key, value)| key.len() + value.len()) + .sum::() + > 256 * 1024 + { + return Err(invalid("environment exceeds size limits")); + } + for (key, value) in &environment.values { + if key.is_empty() + || key.starts_with("OPENSHELL_") + || key.as_bytes()[0].is_ascii_digit() + || !key.bytes().all(|c| c.is_ascii_alphanumeric() || c == b'_') + || value.contains(['\0', '\n', '\r']) + { + return Err(invalid("invalid or reserved workload environment entry")); + } + } + } + Ok(()) +} + +fn prepare_configuration( + object: &mut DynamicObject, + request: &openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest, + repeat: bool, +) -> Result<(), KubernetesDriverError> { + if let Some(spec) = &request.main_process { + let key = super::ANNOTATION_SANDBOX_RUNTIME_MAIN_PROCESS_SPEC; + let encoded = super::required_sandbox_annotation(object, key)?; + let mut main = openshell_core::sandbox_env::MainProcessConfig::decode(&encoded) + .map_err(KubernetesDriverError::Precondition)?; + let original = main.clone(); + main.command.clone_from(&spec.command); + main.tty = spec.command.is_empty() || spec.tty; + if repeat && main != original { + return Err(KubernetesDriverError::Precondition( + "recorded update command does not match target".into(), + )); + } + object + .metadata + .annotations + .get_or_insert_with(BTreeMap::new) + .insert( + key.into(), + serde_json::to_string(&main).map_err(|_| { + KubernetesDriverError::InvalidArgument("cannot encode main process".into()) + })?, + ); + } + if let Some(environment) = &request.environment { + let containers = object + .data + .pointer_mut("/spec/podTemplate/spec/containers") + .and_then(serde_json::Value::as_array_mut) + .ok_or_else(|| { + KubernetesDriverError::Precondition("missing workload containers".into()) + })?; + let agent = containers + .iter_mut() + .find(|container| container["name"] == "agent") + .ok_or_else(|| KubernetesDriverError::Precondition("missing agent container".into()))?; + let mut current = std::collections::HashMap::new(); + let mut retained = Vec::new(); + for entry in agent["env"].as_array().into_iter().flatten() { + let name = entry["name"].as_str().ok_or_else(|| { + KubernetesDriverError::Precondition("invalid workload environment".into()) + })?; + if name.starts_with("OPENSHELL_") { + retained.push(entry.clone()); + } else if let Some(value) = entry["value"].as_str() { + current.insert(name.to_owned(), value.to_owned()); + } else { + return Err(KubernetesDriverError::Precondition( + "cannot replace workload environment with external value sources".into(), + )); + } + } + if repeat && current != environment.values { + return Err(KubernetesDriverError::Precondition( + "recorded update environment does not match target".into(), + )); + } + let mut entries: Vec<_> = environment.values.iter().collect(); + entries.sort_unstable_by_key(|(name, _)| *name); + for (name, value) in entries { + retained.push(serde_json::json!({"name": name, "value": value})); + } + agent["env"] = serde_json::json!(retained); + } + Ok(()) +} + fn image_update_pod_matches(pod: &Pod, object: &DynamicObject, sandbox_id: &str) -> bool { let metadata = &pod.metadata; metadata.owner_references.as_ref().is_some_and(|owners| { diff --git a/crates/openshell-driver-kubernetes/src/image_update_tests.rs b/crates/openshell-driver-kubernetes/src/image_update_tests.rs index f8d37c73f4..3ef3884e73 100644 --- a/crates/openshell-driver-kubernetes/src/image_update_tests.rs +++ b/crates/openshell-driver-kubernetes/src/image_update_tests.rs @@ -310,6 +310,9 @@ async fn image_update_preserves_resource_storage_and_operator_bootstrap_annotati expected["metadata"]["generation"] = serde_json::json!(8); expected["metadata"]["annotations"][IMAGE_UPDATE_ANNOTATION] = serde_json::json!( serde_json::to_string(&ImageUpdateRecord { + configuration: false, + command_updated: false, + environment_updated: false, operation_id: request().operation_id, expected_image: request().expected_image, image: request().image, @@ -657,3 +660,145 @@ async fn image_update_serializes_with_other_lifecycle_operations() { drop(guard); pending.await.unwrap(); } + +#[tokio::test] +async fn configuration_update_atomically_changes_restart_inputs_and_retries_without_writes() { + use openshell_core::proto::compute::v1::{ + SandboxEnvironmentUpdate, SandboxMainProcessUpdate, UpdateSandboxConfigurationRequest, + }; + for version in [SANDBOX_VERSION_V1ALPHA1, SANDBOX_VERSION_V1BETA1] { + let (driver, state) = fixture(version, false); + { + let mut state = state.lock().unwrap(); + state.sandbox["metadata"]["annotations"] + [ANNOTATION_SANDBOX_RUNTIME_MAIN_PROCESS_SPEC] = serde_json::json!( + openshell_core::sandbox_env::MainProcessConfig::encode_driver_spec(None).unwrap() + ); + state.sandbox["spec"]["podTemplate"]["spec"]["containers"][0]["env"] + .as_array_mut() + .unwrap() + .push(serde_json::json!({"name":"OPENSHELL_TEST_RUNTIME", "value":"protected"})); + } + let before = state.lock().unwrap().sandbox.clone(); + let mut update = UpdateSandboxConfigurationRequest { + image_update: Some(request()), + main_process: Some(SandboxMainProcessUpdate { + command: vec!["/usr/local/bin/start-agent".into(), "--new".into()], + ..Default::default() + }), + environment: Some(SandboxEnvironmentUpdate { + values: std::collections::HashMap::from([( + "AGENT_MODE".into(), + "sensitive-environment-value".into(), + )]), + }), + }; + update.image_update.as_mut().unwrap().validate_only = true; + driver.update_sandbox_configuration(&update).await.unwrap(); + assert_eq!(state.lock().unwrap().sandbox, before); + update.image_update.as_mut().unwrap().validate_only = false; + driver.update_sandbox_configuration(&update).await.unwrap(); + { + let state = state.lock().unwrap(); + assert_eq!(state.patches.len(), 1); + assert_eq!( + state.sandbox["spec"]["volumeClaimTemplates"], + before["spec"]["volumeClaimTemplates"] + ); + let agent = &state.sandbox["spec"]["podTemplate"]["spec"]["containers"][0]; + assert_eq!( + agent["command"], + before["spec"]["podTemplate"]["spec"]["containers"][0]["command"] + ); + assert_eq!(agent["image"], update.image_update.as_ref().unwrap().image); + let env = agent["env"].as_array().unwrap(); + assert!(env.iter().any(|entry| entry["name"] == "AGENT_MODE" + && entry["value"] == "sensitive-environment-value")); + assert!( + env.iter() + .any(|entry| entry["name"] == "OPENSHELL_TEST_RUNTIME" + && entry["value"] == "protected") + ); + assert!(!env.iter().any(|entry| entry["name"] == "UNCHANGED")); + let encoded = state.sandbox["metadata"]["annotations"] + [ANNOTATION_SANDBOX_RUNTIME_MAIN_PROCESS_SPEC] + .as_str() + .unwrap(); + assert_eq!( + openshell_core::sandbox_env::MainProcessConfig::decode(encoded) + .unwrap() + .command, + update.main_process.as_ref().unwrap().command + ); + let evidence = state.sandbox["metadata"]["annotations"][IMAGE_UPDATE_ANNOTATION] + .as_str() + .unwrap(); + assert!( + !evidence.contains("sensitive-environment-value"), + "operation evidence must not contain environment values" + ); + } + driver.update_sandbox_configuration(&update).await.unwrap(); + assert_eq!(state.lock().unwrap().patches.len(), 1); + let mut changed = update.clone(); + changed + .environment + .as_mut() + .unwrap() + .values + .insert("AGENT_MODE".into(), "different".into()); + assert!(driver.update_sandbox_configuration(&changed).await.is_err()); + changed = update.clone(); + changed + .main_process + .as_mut() + .unwrap() + .command + .push("--different".into()); + assert!(driver.update_sandbox_configuration(&changed).await.is_err()); + update.image_update.as_mut().unwrap().expected_image = + update.image_update.as_ref().unwrap().image.clone(); + update.image_update.as_mut().unwrap().revision += 1; + update.image_update.as_mut().unwrap().operation_id = "clear-configuration".into(); + update.main_process.as_mut().unwrap().command.clear(); + update.environment.as_mut().unwrap().values.clear(); + driver.update_sandbox_configuration(&update).await.unwrap(); + let state = state.lock().unwrap(); + let encoded = state.sandbox["metadata"]["annotations"] + [ANNOTATION_SANDBOX_RUNTIME_MAIN_PROCESS_SPEC] + .as_str() + .unwrap(); + let main = openshell_core::sandbox_env::MainProcessConfig::decode(encoded).unwrap(); + assert!(main.command.is_empty() && main.tty); + assert_eq!( + state.sandbox["spec"]["podTemplate"]["spec"]["containers"][0]["env"] + .as_array() + .unwrap() + .len(), + 1 + ); + } +} + +#[tokio::test] +async fn configuration_update_rejects_reserved_environment_without_writes() { + use openshell_core::proto::compute::v1::{ + SandboxEnvironmentUpdate, UpdateSandboxConfigurationRequest, + }; + let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); + let update = UpdateSandboxConfigurationRequest { + image_update: Some(request()), + main_process: None, + environment: Some(SandboxEnvironmentUpdate { + values: std::collections::HashMap::from([( + "OPENSHELL_SESSION".into(), + "forged".into(), + )]), + }), + }; + assert!(matches!( + driver.update_sandbox_configuration(&update).await, + Err(KubernetesDriverError::InvalidArgument(_)) + )); + assert!(state.lock().unwrap().calls.is_empty()); +} diff --git a/crates/openshell-driver-kubernetes/src/main.rs b/crates/openshell-driver-kubernetes/src/main.rs index de7facfa8e..84ad0884ea 100644 --- a/crates/openshell-driver-kubernetes/src/main.rs +++ b/crates/openshell-driver-kubernetes/src/main.rs @@ -342,6 +342,7 @@ async fn main() -> Result<()> { .into_diagnostic()?; let driver_service = ComputeDriverService::new(driver); + let configuration_updates_service = openshell_core::proto::compute::v1::compute_driver_configuration_updates_server::ComputeDriverConfigurationUpdatesServer::new(driver_service.clone()); let image_updates_service = ComputeDriverImageUpdatesServer::new(driver_service.clone()); let service = ComputeDriverServer::new(driver_service); let shutdown = async move { @@ -358,6 +359,7 @@ async fn main() -> Result<()> { .layer(openshell_otel::compute_driver_rpc_layer()) .add_service(service) .add_service(image_updates_service) + .add_service(configuration_updates_service) .serve_with_incoming_shutdown( openshell_core::external_driver_socket::SameUidUnixIncoming::new(listener), shutdown, @@ -370,6 +372,7 @@ async fn main() -> Result<()> { .layer(openshell_otel::compute_driver_rpc_layer()) .add_service(service) .add_service(image_updates_service) + .add_service(configuration_updates_service) .serve_with_shutdown(args.bind_address, shutdown) .await .into_diagnostic() diff --git a/crates/openshell-otel/src/grpc.rs b/crates/openshell-otel/src/grpc.rs index 877b13efce..0492b3c0a2 100644 --- a/crates/openshell-otel/src/grpc.rs +++ b/crates/openshell-otel/src/grpc.rs @@ -104,6 +104,11 @@ pub mod rpc { "CreateSandbox", "openshell.compute.v1.ComputeDriver/CreateSandbox", ); + pub const UPDATE_SANDBOX_CONFIGURATION: ComputeDriverRpc = ComputeDriverRpc { + service: "openshell.compute.v1.ComputeDriverConfigurationUpdates", + method: "UpdateSandboxConfiguration", + operation: "openshell.compute.v1.ComputeDriverConfigurationUpdates/UpdateSandboxConfiguration", + }; pub const UPDATE_SANDBOX_IMAGE: ComputeDriverRpc = ComputeDriverRpc { service: super::COMPUTE_DRIVER_IMAGE_UPDATES_RPC_SERVICE, method: "UpdateSandboxImage", @@ -201,6 +206,7 @@ pub fn compute_driver_rpc_operation(path: &str) -> Option { Some("GetCapabilities") => Some(rpc::GET_CAPABILITIES), Some("ValidateSandboxCreate") => Some(rpc::VALIDATE_SANDBOX_CREATE), Some("CreateSandbox") => Some(rpc::CREATE_SANDBOX), + Some("UpdateSandboxConfiguration") => Some(rpc::UPDATE_SANDBOX_CONFIGURATION), Some("UpdateSandboxImage") => Some(rpc::UPDATE_SANDBOX_IMAGE), Some("GetSandbox") => Some(rpc::GET_SANDBOX), Some("ListSandboxes") => Some(rpc::LIST_SANDBOXES), diff --git a/crates/openshell-sdk/src/raw.rs b/crates/openshell-sdk/src/raw.rs index a22e98cadb..15e26d52cc 100644 --- a/crates/openshell-sdk/src/raw.rs +++ b/crates/openshell-sdk/src/raw.rs @@ -29,12 +29,12 @@ pub use openshell_core::proto::{ ListSandboxTemplatesRequest, ListSandboxesRequest, ListWorkspacesRequest, ProviderDesiredIdentity, ProviderMutationKind, ProviderMutationReceipt, ProviderReadinessObservation, ProviderReadinessReason, ProviderReadinessState, - ProviderReadinessStatus, ResumeSandboxRequest, Sandbox, SandboxPhase as ProtoSandboxPhase, - SandboxResources, SandboxServiceLevel, SandboxSpec as ProtoSandboxSpec, SandboxStartup, - SandboxTemplate, SandboxTemplateResponse, SandboxWorkloadConfig, SandboxWorkloadTemplate, - SandboxWorkloadTemplateProvenance, SandboxWorkloadTemplateSpec, - ServiceStatus as ProtoServiceStatus, StartSandboxRequest, StopSandboxRequest, - SuspendSandboxRequest, UpdateSandboxRequest, Workspace, + ProviderReadinessStatus, ResumeSandboxRequest, Sandbox, SandboxCommandUpdate, SandboxMapUpdate, + SandboxPhase as ProtoSandboxPhase, SandboxResources, SandboxServiceLevel, + SandboxSpec as ProtoSandboxSpec, SandboxStartup, SandboxTemplate, SandboxTemplateResponse, + SandboxWorkloadConfig, SandboxWorkloadTemplate, SandboxWorkloadTemplateProvenance, + SandboxWorkloadTemplateSpec, ServiceStatus as ProtoServiceStatus, StartSandboxRequest, + StopSandboxRequest, SuspendSandboxRequest, UpdateSandboxRequest, Workspace, }; /// Type alias for the gRPC client wrapped in the SDK's auth interceptor. diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index 4e50b95bb8..1f3f791a08 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -2425,9 +2425,10 @@ async fn raw_sandbox_updates_shares_transport_and_live_auth_slot() { let request = proto::UpdateSandboxRequest { workspace_scope: Some(proto::workspace_selector("team")), name: "sandbox".into(), - image: "example/workload:new".into(), + image: Some("example/workload:new".into()), expected_resource_version: 42, request_id: "550e8400-e29b-41d4-a716-446655440000".into(), + ..Default::default() }; assert_eq!( updates diff --git a/crates/openshell-server/README.md b/crates/openshell-server/README.md index 1f98ebeb91..05dd0efc5d 100644 --- a/crates/openshell-server/README.md +++ b/crates/openshell-server/README.md @@ -123,7 +123,7 @@ or two minutes after the withdrawal, after their owner was told to stop them. Pool members still authenticate with the one shared supervisor token, so a member identity is asserted by its hello rather than bound to its Pod. -## Optional in-process image updates +## Optional in-process sandbox updates `SharedComputeDriver` retains the generated baseline compute-driver trait, and `ComputeDriverInstance` retains its existing variants. Existing compiled drivers @@ -136,6 +136,16 @@ requires both this opt-in and the negotiated capability before recording image intent. Remote drivers register the separate `ComputeDriverImageUpdates` service on their existing endpoint instead. +Command, environment, label, and annotation selections use the same stopped-only +transaction and durable interlock. Extended requests require the separate +configuration-update driver capability and RPC; unsupported combinations fail +before admission. User metadata replacement preserves system domains, and labels +are indexed in the same SQL transaction as the payload. The existing activation +flag now requires deployment protocol 2. Old private image-only intents remain +readable, and completion verifies the selected workload targets and labels before +clearing the fence. Annotation replacement commits at acceptance; completion +preserves later annotation writes accepted through `UpdateConfig`. + ## Operator credential export `GetProviderCredentials` exports selected profile-declared runtime environment diff --git a/crates/openshell-server/proto/sandbox_image.proto b/crates/openshell-server/proto/sandbox_image.proto index 8d3e3f030d..1ed4a2167f 100644 --- a/crates/openshell-server/proto/sandbox_image.proto +++ b/crates/openshell-server/proto/sandbox_image.proto @@ -13,6 +13,11 @@ message StoredSandboxImageUpdate { string previous_image = 2; string image = 3; uint64 revision = 4; + // Absent for legacy image-only operations. Presence retains selection semantics. + openshell.v1.SandboxCommandUpdate command = 5; + openshell.v1.SandboxMapUpdate environment = 6; + openshell.v1.SandboxMapUpdate labels = 7; + openshell.v1.SandboxMapUpdate annotations = 8; } message StoredSandboxImageState { diff --git a/crates/openshell-server/src/cli.rs b/crates/openshell-server/src/cli.rs index ae7fdfe560..dfbbf4e7bb 100644 --- a/crates/openshell-server/src/cli.rs +++ b/crates/openshell-server/src/cli.rs @@ -314,10 +314,10 @@ struct RunArgs { )] enable_websocket_tunnel: bool, - /// Activate image updates only after retiring every incompatible gateway + /// Activate stopped-sandbox configuration updates only after retiring every incompatible gateway /// and settling its outstanding driver operations. See HA upgrade guidance. - #[arg(long, env = "OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES", default_value_t = false, action = ArgAction::Set)] - enable_sandbox_image_updates: bool, + #[arg(long, env = "OPENSHELL_ENABLE_SANDBOX_UPDATES", default_value_t = false, action = ArgAction::Set)] + enable_sandbox_updates: bool, } pub fn command() -> Command { @@ -600,7 +600,7 @@ fn prepare_server_config_with_drivers( .validate(&config.name) .map_err(|error| miette::miette!("invalid service routing configuration: {error}"))?; - config.enable_sandbox_image_updates = args.enable_sandbox_image_updates; + config.enable_sandbox_updates = args.enable_sandbox_updates; if let Some(sources) = file .as_ref() .and_then(|file| file.openshell.gateway.provider_profile_sources.clone()) @@ -1386,10 +1386,10 @@ fn merge_file_into_args(args: &mut RunArgs, file: &GatewayFileSection, matches: { args.enable_websocket_tunnel = enabled; } - if let Some(enabled) = file.enable_sandbox_image_updates - && arg_defaulted(matches, "enable_sandbox_image_updates") + if let Some(enabled) = file.enable_sandbox_updates + && arg_defaulted(matches, "enable_sandbox_updates") { - args.enable_sandbox_image_updates = enabled; + args.enable_sandbox_updates = enabled; } if let Some(mtls_auth) = &file.mtls_auth && arg_defaulted(matches, "enable_mtls_auth") @@ -3108,39 +3108,36 @@ mod tests { } #[test] - fn image_update_activation_defaults_off_and_file_requires_explicit_opt_in() { - Environment::new().remove("OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES").run(|| { + fn sandbox_update_activation_defaults_off_and_file_requires_explicit_opt_in() { + Environment::new().remove("OPENSHELL_ENABLE_SANDBOX_UPDATES").run(|| { let (mut args, matches) = parse_with_args(&["openshell-gateway"]); - assert!(!args.enable_sandbox_image_updates); - assert!(!openshell_core::Config::new(None).enable_sandbox_image_updates); - let file = config_file_from_toml("[openshell]\nversion = 2\n[openshell.gateway]\nenable_sandbox_image_updates = true\n"); + assert!(!args.enable_sandbox_updates); + assert!(!openshell_core::Config::new(None).enable_sandbox_updates); + let file = config_file_from_toml("[openshell]\nversion = 2\n[openshell.gateway]\nenable_sandbox_updates = true\n"); merge_file_into_args(&mut args, &file.openshell.gateway, &matches); - assert!(args.enable_sandbox_image_updates); + assert!(args.enable_sandbox_updates); }); } #[test] fn explicit_cli_or_environment_disable_overrides_file_activation() { let file = config_file_from_toml( - "[openshell]\nversion = 2\n[openshell.gateway]\nenable_sandbox_image_updates = true\n", + "[openshell]\nversion = 2\n[openshell.gateway]\nenable_sandbox_updates = true\n", ); Environment::new() - .remove("OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES") + .remove("OPENSHELL_ENABLE_SANDBOX_UPDATES") .run(|| { - let (mut args, matches) = parse_with_args(&[ - "openshell-gateway", - "--enable-sandbox-image-updates", - "false", - ]); + let (mut args, matches) = + parse_with_args(&["openshell-gateway", "--enable-sandbox-updates", "false"]); merge_file_into_args(&mut args, &file.openshell.gateway, &matches); - assert!(!args.enable_sandbox_image_updates); + assert!(!args.enable_sandbox_updates); }); Environment::new() - .set("OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES", "false") + .set("OPENSHELL_ENABLE_SANDBOX_UPDATES", "false") .run(|| { let (mut args, matches) = parse_with_args(&["openshell-gateway"]); merge_file_into_args(&mut args, &file.openshell.gateway, &matches); - assert!(!args.enable_sandbox_image_updates); + assert!(!args.enable_sandbox_updates); }); } diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs index b08f3d2f4d..54e2166a08 100644 --- a/crates/openshell-server/src/compute/image_update.rs +++ b/crates/openshell-server/src/compute/image_update.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Stopped-only image changes with private durable intent and an operation +//! Stopped-only configuration changes with private durable intent and an operation //! interlock understood by supported older gateways. use super::{ComputeRuntime, provisioning_operation, sandbox_compute_runtime_identity}; @@ -14,23 +14,50 @@ use tonic::{Request, Status}; use tracing::info; impl ComputeRuntime { - pub(crate) fn with_sandbox_image_updates(mut self, enabled: bool) -> Self { - self.image_updates_enabled = enabled; + pub(crate) fn with_sandbox_updates(mut self, enabled: bool) -> Self { + self.sandbox_updates_enabled = enabled; self } + #[cfg(test)] pub(crate) async fn update_sandbox_image( &self, sandbox_id: &str, image: String, expected_resource_version: u64, ) -> Result { + self.update_sandbox_configuration( + sandbox_id, + &openshell_core::proto::UpdateSandboxRequest { + image: Some(image), + expected_resource_version, + ..Default::default() + }, + ) + .await + } + + pub(crate) async fn update_sandbox_configuration( + &self, + sandbox_id: &str, + update: &openshell_core::proto::UpdateSandboxRequest, + ) -> Result { + let expected_resource_version = update.expected_resource_version; + let extended = update.command.is_some() + || update.environment.is_some() + || update.labels.is_some() + || update.annotations.is_some(); + let capability_required = if extended { + openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION + } else { + COMPUTE_UPDATE_SANDBOX_IMAGE + }; // Explicit operator activation follows retirement of incompatible // gateways and their outstanding driver work. Refuse before preflight // or durable effects; a cached placement ring is not a version proof. - if !self.image_updates_enabled { + if !self.sandbox_updates_enabled { return Err(Status::failed_precondition( - "sandbox image updates are disabled; complete the compatible deployment rollout before activating them", + "sandbox updates are disabled; complete the compatible deployment rollout before activating them", )); } self.store @@ -47,7 +74,7 @@ impl ComputeRuntime { .negotiated_extension .supported_capabilities .iter() - .any(|capability| capability == COMPUTE_UPDATE_SANDBOX_IMAGE) + .any(|capability| capability == capability_required) { return Err(Status::unimplemented( "compute driver does not support storage-preserving sandbox image updates", @@ -81,11 +108,27 @@ impl ComputeRuntime { .await .map_err(|_| Status::internal("fetch private sandbox image state failed"))?; let pending = state.as_ref().and_then(|state| state.pending.clone()); + let image = update + .image + .clone() + .or_else(|| { + current + .spec + .as_ref() + .and_then(|spec| spec.template.as_ref()) + .map(|template| template.image.clone()) + }) + .ok_or_else(|| Status::failed_precondition("sandbox has no workload image"))?; if let Some(intent) = &pending { ensure_image_update_interlock(¤t, intent)?; - if intent.image != image { + if intent.image != image + || intent.command != update.command + || intent.environment != update.environment + || intent.labels != update.labels + || intent.annotations != update.annotations + { return Err(Status::failed_precondition( - "another image update is pending; retry that image before selecting a different image", + "another sandbox update is pending; retry the same selected fields and target values", )); } } else { @@ -98,7 +141,15 @@ impl ComputeRuntime { .map(|template| template.image.clone()) .filter(|image| !image.is_empty()) .ok_or_else(|| Status::failed_precondition("sandbox has no workload image"))?; - if pending.is_none() && old_image == image { + let mut candidate = current.clone(); + openshell_core::sandbox_update::apply_configuration( + &mut candidate, + update.command.as_ref(), + update.environment.as_ref(), + update.labels.as_ref(), + update.annotations.as_ref(), + ); + if pending.is_none() && old_image == image && candidate == current { return Ok(current); } let revision = state.as_ref().map_or(0, |state| state.revision); @@ -107,6 +158,10 @@ impl ComputeRuntime { previous_image: old_image, image, revision: revision.saturating_add(1), + command: update.command.clone(), + environment: update.environment.clone(), + labels: update.labels.clone(), + annotations: update.annotations.clone(), }); if pending.is_none() && revision == u64::MAX { return Err(Status::resource_exhausted( @@ -116,9 +171,9 @@ impl ComputeRuntime { let accepted = if pending.is_some() { current } else { - let request = image_update_driver_request(¤t, &intent, true); - self.call_image_update_driver(request).await?; - // The private intent, desired image, and OLD-understood pending + self.reconcile_sandbox_update(¤t, &intent, true) + .await?; + // The private intent, selected configuration, and OLD-understood pending // operation flag commit in one version-fenced transaction. self.store .begin_sandbox_image_update( @@ -152,8 +207,8 @@ impl ComputeRuntime { intent: SandboxImageUpdate, ) -> Result { ensure_image_update_interlock(&pending, &intent)?; - let request = image_update_driver_request(&pending, &intent, false); - self.call_image_update_driver(request).await?; + self.reconcile_sandbox_update(&pending, &intent, false) + .await?; let _guard = self.lock_sandbox_local(pending.object_id()).await; // An ambiguous error NEVER clears either the private intent or the // public operation interlock. Only exact successful reconciliation can. @@ -167,10 +222,73 @@ impl ComputeRuntime { self.sandbox_index.update_from_sandbox(&updated); self.sandbox_watch_bus.notify(updated.object_id()); info!(sandbox_id = %updated.object_id(), operation_id = %intent.operation_id, - "Sandbox workload image updated; sandbox remains stopped"); + "Sandbox configuration updated; sandbox remains stopped"); Ok(updated) } + async fn reconcile_sandbox_update( + &self, + sandbox: &Sandbox, + intent: &SandboxImageUpdate, + validate_only: bool, + ) -> Result<(), Status> { + let image_update = image_update_driver_request(sandbox, intent, validate_only); + if intent.command.is_none() + && intent.environment.is_none() + && intent.labels.is_none() + && intent.annotations.is_none() + { + self.call_image_update_driver(image_update).await?; + return Ok(()); + } + let mut candidate = sandbox.clone(); + openshell_core::sandbox_update::apply_configuration( + &mut candidate, + intent.command.as_ref(), + intent.environment.as_ref(), + intent.labels.as_ref(), + intent.annotations.as_ref(), + ); + let spec = candidate + .spec + .as_ref() + .ok_or_else(|| Status::failed_precondition("sandbox has no spec"))?; + let main_process = intent.command.as_ref().map(|_| { + openshell_core::proto::compute::v1::SandboxMainProcessUpdate { + command: spec.command.clone(), + tty: spec.tty, + } + }); + let environment = intent.environment.as_ref().map(|_| { + let mut values = spec + .template + .as_ref() + .map_or_else(Default::default, |template| template.environment.clone()); + values.extend(spec.environment.clone()); + openshell_core::proto::compute::v1::SandboxEnvironmentUpdate { values } + }); + let request = openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest { + image_update: Some(image_update), + main_process, + environment, + }; + let driver = self.image_update_driver.clone().ok_or_else(|| { + Status::unimplemented("compute driver has no registered configuration updater") + })?; + self.driver + .call_owned( + openshell_otel::rpc::UPDATE_SANDBOX_CONFIGURATION, + Some(sandbox.object_id()), + move |_| async move { + driver + .update_sandbox_configuration(Request::new(request)) + .await + }, + ) + .await?; + Ok(()) + } + async fn call_image_update_driver( &self, request: UpdateSandboxImageRequest, @@ -204,7 +322,7 @@ impl ComputeRuntime { .map_err(|_| Status::unavailable("cannot read private sandbox image state"))?; if state.as_ref().is_some_and(|state| state.pending.is_some()) { return Err(Status::failed_precondition( - "sandbox image update is pending; read the current resource version and retry UpdateSandbox with the same image before starting", + "sandbox update is pending; read the current resource version and retry UpdateSandbox with the same selected fields and target values before starting", )); } Ok(()) @@ -295,14 +413,17 @@ mod tests { ) .await .unwrap(); - runtime.image_updates_enabled = true; + runtime.sandbox_updates_enabled = true; if supported { runtime.image_update_driver = Some(driver.clone()); runtime .driver_info .negotiated_extension .supported_capabilities - .push(COMPUTE_UPDATE_SANDBOX_IMAGE.into()); + .extend([ + COMPUTE_UPDATE_SANDBOX_IMAGE.into(), + openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION.into(), + ]); } let mut sandbox = Sandbox { metadata: Some(ObjectMeta { @@ -357,6 +478,173 @@ mod tests { .collect() } + #[tokio::test] + async fn configuration_update_reconciles_all_fields_and_recovers_exact_pending_target() { + use openshell_core::proto::{SandboxCommandUpdate, SandboxMapUpdate, UpdateSandboxRequest}; + let (runtime, driver, original) = fixture(true).await; + let request = UpdateSandboxRequest { + image: Some("example/workload:new".into()), + command: Some(SandboxCommandUpdate { + argv: vec!["/usr/local/bin/start-agent".into(), "--new".into()], + }), + environment: Some(SandboxMapUpdate { + values: HashMap::from([("MODE".into(), "new".into())]), + }), + labels: Some(SandboxMapUpdate { + values: HashMap::from([("team".into(), "agents".into())]), + }), + annotations: Some(SandboxMapUpdate { + values: HashMap::from([("example.com/revision".into(), "2".into())]), + }), + expected_resource_version: original.get_resource_version(), + ..Default::default() + }; + driver.set_image_update_error(Some(Code::Unavailable)); + assert_eq!( + runtime + .update_sandbox_configuration(original.object_id(), &request) + .await + .unwrap_err() + .code(), + Code::Unavailable + ); + let pending = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + assert!( + pending + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .unwrap() + .driver_operation_pending + ); + let mut retry = request.clone(); + retry.expected_resource_version = pending.get_resource_version(); + retry + .command + .as_mut() + .unwrap() + .argv + .push("--different".into()); + assert_eq!( + runtime + .update_sandbox_configuration(original.object_id(), &retry) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + retry.command = request.command.clone(); + driver.set_image_update_error(None); + let updated = runtime + .update_sandbox_configuration(original.object_id(), &retry) + .await + .unwrap(); + assert_eq!(updated.phase(), SandboxPhase::Stopped as i32); + assert_eq!( + updated.spec.as_ref().unwrap().command, + request.command.unwrap().argv + ); + assert_eq!( + updated.spec.as_ref().unwrap().environment, + request.environment.unwrap().values + ); + for (key, value) in &original.metadata.as_ref().unwrap().annotations { + if openshell_core::sandbox_update::is_system_metadata_key(key) { + assert_eq!( + updated.metadata.as_ref().unwrap().annotations.get(key), + Some(value) + ); + } + } + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap() + .pending + .is_none() + ); + let clear = UpdateSandboxRequest { + command: Some(SandboxCommandUpdate::default()), + environment: Some(SandboxMapUpdate::default()), + labels: Some(SandboxMapUpdate::default()), + annotations: Some(SandboxMapUpdate::default()), + expected_resource_version: updated.get_resource_version(), + ..Default::default() + }; + let cleared = runtime + .update_sandbox_configuration(original.object_id(), &clear) + .await + .unwrap(); + assert!(cleared.spec.as_ref().unwrap().command.is_empty()); + assert!(cleared.spec.as_ref().unwrap().environment.is_empty()); + assert!(cleared.metadata.as_ref().unwrap().labels.is_empty()); + assert_eq!( + cleared + .spec + .as_ref() + .unwrap() + .template + .as_ref() + .unwrap() + .image, + "example/workload:new" + ); + } + + #[tokio::test] + async fn configuration_update_requires_capability_before_mutating() { + use openshell_core::proto::SandboxCommandUpdate; + let (mut runtime, _, original) = fixture(true).await; + runtime + .driver_info + .negotiated_extension + .supported_capabilities + .retain(|capability| { + capability + != openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION + }); + let update = openshell_core::proto::UpdateSandboxRequest { + command: Some(SandboxCommandUpdate::default()), + expected_resource_version: original.get_resource_version(), + ..Default::default() + }; + assert_eq!( + runtime + .update_sandbox_configuration(original.object_id(), &update) + .await + .unwrap_err() + .code(), + Code::Unimplemented + ); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_none() + ); + assert_eq!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(), + original + ); + } + #[tokio::test] async fn image_update_preserves_identity_and_every_other_spec_field() { let (runtime, driver, mut original) = fixture(true).await; @@ -1009,9 +1297,9 @@ mod tests { } #[tokio::test] - async fn image_update_activation_is_disabled_by_default_without_effects() { + async fn sandbox_update_activation_is_disabled_by_default_without_effects() { let (mut runtime, driver, original) = fixture(true).await; - runtime.image_updates_enabled = false; + runtime.sandbox_updates_enabled = false; assert_eq!( runtime .update_sandbox_image( diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index f7e331fada..5fbb083382 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -685,6 +685,7 @@ impl AcquiredRemoteDriverEndpoint { #[derive(Debug, Clone)] struct RemoteComputeDriver { client: RemoteComputeDriverClient, + configuration_updates_client: openshell_core::proto::compute::v1::compute_driver_configuration_updates_client::ComputeDriverConfigurationUpdatesClient>, image_updates_client: ComputeDriverImageUpdatesClient< tonic::service::interceptor::InterceptedService, >, @@ -699,6 +700,7 @@ impl RemoteComputeDriver { fn new(channel: Channel) -> Self { 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.clone(), TraceContextInterceptor), image_updates_client: ComputeDriverImageUpdatesClient::with_interceptor( channel, TraceContextInterceptor, @@ -745,6 +747,20 @@ impl RemoteComputeDriver { #[tonic::async_trait] impl openshell_core::compute::ComputeDriver for RemoteComputeDriver { + async fn update_sandbox_configuration( + &self, + request: Request, + ) -> Result< + tonic::Response, + Status, + > { + self.verify_admission_policy(false).await?; + self.configuration_updates_client + .clone() + .update_sandbox_configuration(request) + .await + } + async fn update_sandbox_image( &self, request: Request, @@ -923,7 +939,7 @@ pub struct ComputeRuntime { driver_process: Option>, default_image: String, image_preparation_timeout_seconds: u32, - image_updates_enabled: bool, + sandbox_updates_enabled: bool, store: Arc, sandbox_index: SandboxIndex, sandbox_watch_bus: SandboxWatchBus, @@ -1041,7 +1057,7 @@ impl ComputeRuntime { driver_process, default_image, image_preparation_timeout_seconds: 1800, - image_updates_enabled: false, + sandbox_updates_enabled: false, store, sandbox_index, sandbox_watch_bus, @@ -6157,9 +6173,15 @@ impl ComputeRuntime { .await .map_err(|e| e.to_string())?; if let Some(sandbox) = sandbox.as_ref() { + // Timeout cleanup can emit Deleted before an explicit stop exposes + // Stopped for repair. A delayed (or repeated) event must retain that + // recovery record too; explicit deletion still transitions to Deleting. if provisioning_deadline::driver_operation_pending(sandbox) || (provisioning_deadline::timed_out(sandbox) - && sandbox.phase() == i32::from(SandboxPhase::Error)) + && matches!( + SandboxPhase::try_from(sandbox.phase()), + Ok(SandboxPhase::Error | SandboxPhase::Stopped) + )) { return Ok(()); } @@ -8482,7 +8504,7 @@ pub fn new_test_runtime_with_driver( driver_process: None, default_image: "openshell/sandbox:test".to_string(), image_preparation_timeout_seconds: 1800, - image_updates_enabled: false, + sandbox_updates_enabled: false, store, sandbox_index: SandboxIndex::new(), sandbox_watch_bus: SandboxWatchBus::new(), @@ -9683,7 +9705,7 @@ mod tests { driver_process: None, default_image: "openshell/sandbox:test".to_string(), image_preparation_timeout_seconds: 1800, - image_updates_enabled: false, + sandbox_updates_enabled: false, store, sandbox_index: SandboxIndex::new(), sandbox_watch_bus: SandboxWatchBus::new(), @@ -18367,7 +18389,7 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" ) .await .unwrap(); - runtime.image_updates_enabled = true; + runtime.sandbox_updates_enabled = true; assert!( !runtime .driver_info @@ -18462,7 +18484,7 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" // NoopTestDriver implements only the baseline generated trait. let mut runtime = test_runtime(Arc::new(NoopTestDriver::default())) .await - .with_sandbox_image_updates(true); + .with_sandbox_updates(true); runtime .driver_info .negotiated_extension diff --git a/crates/openshell-server/src/compute/tests/error_recovery.rs b/crates/openshell-server/src/compute/tests/error_recovery.rs index 48d16fcc25..7fdfea0eeb 100644 --- a/crates/openshell-server/src/compute/tests/error_recovery.rs +++ b/crates/openshell-server/src/compute/tests/error_recovery.rs @@ -209,6 +209,12 @@ async fn timeout_stop_preserves_cleanup_and_direct_start_recovery() { repeated, stopped, "the retained stopped transition is idempotent" ); + // Docker cleanup and its snapshot poll can both report deletion of + // the cancelled preparation after explicit stop has returned. + for _ in 0..2 { + runtime.apply_deleted(sandbox.object_id()).await.unwrap(); + assert_eq!(stored(&runtime, sandbox.object_id()).await, stopped); + } } else { let error = stop.unwrap_err(); assert_eq!(error.code(), Code::FailedPrecondition); diff --git a/crates/openshell-server/src/compute_factory_compatibility.rs b/crates/openshell-server/src/compute_factory_compatibility.rs index c009597076..3ce003dd97 100644 --- a/crates/openshell-server/src/compute_factory_compatibility.rs +++ b/crates/openshell-server/src/compute_factory_compatibility.rs @@ -98,7 +98,7 @@ async fn registered_runtime(factory: impl ComputeDriverFactory + 'static) -> cra ) .await .unwrap() - .with_sandbox_image_updates(true) + .with_sandbox_updates(true) } #[tokio::test] diff --git a/crates/openshell-server/src/config_file.rs b/crates/openshell-server/src/config_file.rs index 9a25dfd7c8..a956bca9cd 100644 --- a/crates/openshell-server/src/config_file.rs +++ b/crates/openshell-server/src/config_file.rs @@ -145,7 +145,7 @@ pub struct GatewayFileSection { pub image_preparation_timeout_seconds: Option, /// Explicit activation only after the compatible deployment rollout ends. #[serde(default)] - pub enable_sandbox_image_updates: Option, + pub enable_sandbox_updates: Option, #[serde(default)] pub grpc_rate_limit_requests: Option, #[serde(default)] diff --git a/crates/openshell-server/src/gateway_members.rs b/crates/openshell-server/src/gateway_members.rs index 6c122ded29..a61df4b509 100644 --- a/crates/openshell-server/src/gateway_members.rs +++ b/crates/openshell-server/src/gateway_members.rs @@ -74,7 +74,7 @@ impl GatewayMemberIndex { let payload = MemberPayload { replica_id: replica_id.to_string(), peer_endpoint: peer_endpoint.to_string(), - image_update_protocol: 1, + image_update_protocol: 2, }; let bytes = serde_json::to_vec(&payload) .map_err(|err| PersistenceError::Encode(err.to_string()))?; diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index 5b2ed1905c..a80d7df2a7 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -335,24 +335,33 @@ pub(super) async fn handle_update_sandbox( super::workspace::resolve_workspace(state.store.as_ref(), sandbox.object_workspace()) .await? .ensure_active()?; - let mut candidate = sandbox + let mut candidate = sandbox.clone(); + let spec = candidate .spec - .clone() + .as_mut() .ok_or_else(|| Status::failed_precondition("sandbox has no spec"))?; - candidate - .template - .get_or_insert_with(Default::default) - .image - .clone_from(&request.image); - validate_sandbox_spec(&request.name, &candidate)?; - let sandbox = state - .compute - .update_sandbox_image( - sandbox.object_id(), - request.image, - request.expected_resource_version, - ) - .await?; + if let Some(image) = &request.image { + spec.template + .get_or_insert_with(Default::default) + .image + .clone_from(image); + } + openshell_core::sandbox_update::apply_configuration( + &mut candidate, + request.command.as_ref(), + request.environment.as_ref(), + request.labels.as_ref(), + request.annotations.as_ref(), + ); + let candidate_spec = candidate.spec.as_ref().expect("spec checked above"); + validate_sandbox_spec(&request.name, candidate_spec)?; + + let sandbox = Box::pin( + state + .compute + .update_sandbox_configuration(sandbox.object_id(), &request), + ) + .await?; Ok(Response::new(SandboxResponse { sandbox: Some(sandbox), service_urls: HashMap::new(), @@ -370,17 +379,45 @@ fn validate_image_update_request( "expected_resource_version must be nonzero", )); } - if request.image.is_empty() - || request.image.len() > super::MAX_TEMPLATE_STRING_LEN - || request - .image - .chars() - .any(|character| character.is_whitespace() || character.is_control()) + if request.image.is_none() + && request.command.is_none() + && request.environment.is_none() + && request.labels.is_none() + && request.annotations.is_none() + { + return Err(Status::invalid_argument( + "at least one update field is required", + )); + } + if let Some(image) = &request.image + && (image.is_empty() + || image.len() > super::MAX_TEMPLATE_STRING_LEN + || image.chars().any(|c| c.is_whitespace() || c.is_control())) { return Err(Status::invalid_argument( "image must be a nonempty bounded OCI reference without whitespace or control characters", )); } + for map in [request.labels.as_ref(), request.annotations.as_ref()] + .into_iter() + .flatten() + { + super::validation::validate_annotations(&map.values, "metadata")?; + if map + .values + .keys() + .any(|key| openshell_core::sandbox_update::is_system_metadata_key(key)) + { + return Err(Status::invalid_argument( + "system metadata cannot be updated", + )); + } + } + if let Some(labels) = &request.labels { + for value in labels.values.values() { + super::validation::validate_label_value(value)?; + } + } Ok(()) } 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 988b2aa267..50b1a9a96e 100644 --- a/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs +++ b/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs @@ -5,10 +5,10 @@ use super::*; use crate::auth::audit::ConnectionSource; use crate::grpc::test_support::{authed_request, test_server_state}; use crate::test_support::{FakeComputeDriver, FakeComputeDriverCall}; -use openshell_core::proto::UpdateSandboxRequest; use openshell_core::proto::compute::v1::GetCapabilitiesResponse; use openshell_core::proto::datamodel::v1::ObjectMeta; use openshell_core::proto::sandbox_updates_client::SandboxUpdatesClient; +use openshell_core::proto::{SandboxCommandUpdate, UpdateSandboxRequest}; use tonic::Code; struct RunningService(tokio::task::JoinHandle<()>); @@ -76,9 +76,10 @@ fn request() -> UpdateSandboxRequest { UpdateSandboxRequest { workspace_scope: Some(openshell_core::proto::workspace_selector("default")), name: "image-update".into(), - image: "example/workload:new".into(), + image: Some("example/workload:new".into()), expected_resource_version: 1, request_id: String::new(), + ..Default::default() } } @@ -89,7 +90,7 @@ fn image_only_request_requires_target_image_and_conditional_version() { for image in ["", " ", "example/workload:tag\n", "bad image", "a\0b"] { assert_eq!( validate_image_update_request(&UpdateSandboxRequest { - image: image.into(), + image: Some(image.into()), ..valid.clone() }) .unwrap_err() @@ -99,7 +100,7 @@ fn image_only_request_requires_target_image_and_conditional_version() { } assert!( validate_image_update_request(&UpdateSandboxRequest { - image: "a".repeat(super::super::MAX_TEMPLATE_STRING_LEN + 1), + image: Some("a".repeat(super::super::MAX_TEMPLATE_STRING_LEN + 1)), ..valid.clone() }) .is_err() @@ -125,7 +126,7 @@ async fn state() -> (Arc, Arc, Sandbox) { Arc::get_mut(&mut state) .unwrap() .config - .enable_sandbox_image_updates = true; + .enable_sandbox_updates = true; let driver = Arc::new( FakeComputeDriver::new().with_capabilities(GetCapabilitiesResponse { driver_name: "image-test".into(), @@ -134,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_IMAGE.into()], + [ + openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.into(), + openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION.into(), + ], )), ..Default::default() }), @@ -152,7 +156,7 @@ async fn state() -> (Arc, Arc, Sandbox) { .await .unwrap() .with_image_update_driver(Some(driver.clone())) - .with_sandbox_image_updates(true); + .with_sandbox_updates(true); Arc::get_mut(&mut state).unwrap().compute = compute; let mut sandbox = Sandbox { metadata: Some(ObjectMeta { @@ -235,6 +239,18 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re let req = UpdateSandboxRequest { expected_resource_version: sandbox.get_resource_version(), request_id: uuid::Uuid::new_v4().to_string(), + command: Some(SandboxCommandUpdate { + argv: vec!["/usr/local/bin/start-agent".into(), "--updated".into()], + }), + environment: Some(openshell_core::proto::SandboxMapUpdate { + values: HashMap::from([("AGENT_MODE".into(), "updated".into())]), + }), + labels: Some(openshell_core::proto::SandboxMapUpdate { + values: HashMap::from([("team".into(), "agents".into())]), + }), + annotations: Some(openshell_core::proto::SandboxMapUpdate { + values: HashMap::from([("example.com/revision".into(), "2".into())]), + }), ..request() }; let updated = client @@ -254,14 +270,26 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re .as_ref() .unwrap() .image, - req.image + req.image.as_ref().unwrap().as_str() + ); + assert_eq!( + updated.spec.as_ref().unwrap().command, + req.command.as_ref().unwrap().argv + ); + assert_eq!( + updated.spec.as_ref().unwrap().environment, + req.environment.as_ref().unwrap().values + ); + assert_eq!( + updated.metadata.as_ref().unwrap().labels, + req.labels.as_ref().unwrap().values ); let replay = client.update_sandbox(req.clone()).await.unwrap(); assert_eq!(replay.metadata().get("openshell-replayed").unwrap(), "true"); assert_eq!(replay.get_ref().sandbox.as_ref().unwrap(), &updated); - assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxImage { request } if !request.validate_only)).count(), 1); + assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxConfiguration { request } if !request.image_update.as_ref().unwrap().validate_only)).count(), 1); let changed = UpdateSandboxRequest { - image: "example/workload:other".into(), + image: Some("example/workload:other".into()), ..req.clone() }; assert_eq!( @@ -289,5 +317,118 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re .unwrap() .unwrap(); assert_eq!(replacement.spec, sandbox.spec); - assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxImage { request } if !request.validate_only)).count(), 1); + assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxConfiguration { request } if !request.image_update.as_ref().unwrap().validate_only)).count(), 1); +} + +#[test] +fn configuration_update_presence_and_reserved_metadata() { + let mut update = request(); + update.image = None; + assert!(validate_image_update_request(&update).is_err()); + update.command = Some(SandboxCommandUpdate::default()); + validate_image_update_request(&update).unwrap(); + for key in [ + "internal.openshell.ai/auth-epoch", + "openshell.ai/identity", + "agents.x-k8s.io/name", + ] { + update.annotations = Some(openshell_core::proto::SandboxMapUpdate { + values: HashMap::from([(key.into(), "forged".into())]), + }); + assert!(validate_image_update_request(&update).is_err()); + update.labels = update.annotations.take(); + assert!(validate_image_update_request(&update).is_err()); + } +} + +#[tokio::test] +async fn pending_update_retry_preserves_later_update_config_annotations() { + use openshell_core::proto::{SandboxMapUpdate, UpdateConfigRequest}; + + let (state, driver, sandbox) = state().await; + let mut update = UpdateSandboxRequest { + expected_resource_version: sandbox.get_resource_version(), + annotations: Some(SandboxMapUpdate { + values: HashMap::from([ + ("example.com/revision".into(), "original".into()), + ("example.com/retained".into(), "value".into()), + ]), + }), + ..request() + }; + driver.set_image_update_error(Some(Code::Unavailable)); + assert_eq!( + handle_update_sandbox(&state, authed_request(update.clone())) + .await + .unwrap_err() + .code(), + Code::Unavailable + ); + let pending = state + .store + .get_message::(sandbox.object_id()) + .await + .unwrap() + .unwrap(); + + // Exercise the existing public annotation writer while the update is + // pending, including both a new key and an overwrite of a selected key. + let annotations = crate::grpc::policy::handle_update_config( + &state, + authed_request(UpdateConfigRequest { + sandbox: sandbox.object_name().into(), + workspace_scope: update.workspace_scope.clone(), + expected_resource_version: pending.get_resource_version(), + setting_key: "log_level".into(), + delete_setting: true, + annotations: HashMap::from([ + ("example.com/revision".into(), "later".into()), + ("example.com/added".into(), "new".into()), + ]), + ..Default::default() + }), + ) + .await + .unwrap() + .into_inner() + .annotations; + assert_eq!(annotations.get("example.com/retained").unwrap(), "value"); + let current = state + .store + .get_message::(sandbox.object_id()) + .await + .unwrap() + .unwrap(); + update.expected_resource_version = current.get_resource_version(); + driver.set_image_update_error(None); + let completed = handle_update_sandbox(&state, authed_request(update)) + .await + .unwrap() + .into_inner() + .sandbox + .unwrap(); + assert_eq!( + completed.metadata.as_ref().unwrap().annotations, + annotations + ); + assert_eq!(completed.phase(), SandboxPhase::Stopped as i32); + assert!( + completed + .status + .as_ref() + .unwrap() + .provisioning + .as_ref() + .is_none_or(|record| !record.driver_operation_pending) + ); + assert!( + state + .store + .get_sandbox_image_state(sandbox.object_id()) + .await + .unwrap() + .unwrap() + .pending + .is_none() + ); } diff --git a/crates/openshell-server/src/lib.rs b/crates/openshell-server/src/lib.rs index 7e1961e546..0d9c1d85a1 100644 --- a/crates/openshell-server/src/lib.rs +++ b/crates/openshell-server/src/lib.rs @@ -482,7 +482,7 @@ impl ServerState { credentials: credentials::CredentialRuntime, ) -> Self { let replica_id = compute::lease::replica_id(); - let compute = compute.with_sandbox_image_updates(config.enable_sandbox_image_updates); + let compute = compute.with_sandbox_updates(config.enable_sandbox_updates); compute.configure_ssh_identities(credentials.clone()); let service_route_index = Arc::new(service_routing::ServiceRouteIndex::new( config.service_routing_discriminator().map(str::to_string), diff --git a/crates/openshell-server/src/persistence/image_activation.rs b/crates/openshell-server/src/persistence/image_activation.rs index badbc0eb3f..22acb430a6 100644 --- a/crates/openshell-server/src/persistence/image_activation.rs +++ b/crates/openshell-server/src/persistence/image_activation.rs @@ -18,7 +18,7 @@ use openshell_core::time::now_ms; /// /// This marker describes a protocol, not an exact build version. It is neither /// authentication nor a security boundary: database clients can set it too. -pub(super) const IMAGE_UPDATE_APPLICATION_NAME: &str = "openshell-image-update-v1"; +pub(super) const IMAGE_UPDATE_APPLICATION_NAME: &str = "openshell-image-update-v2"; const MEMBER_OBJECT_TYPE: &str = "gateway_member"; const MEMBER_LIMIT: u32 = 1024; @@ -95,9 +95,9 @@ fn ensure_live_members_compatible(records: &[ObjectRecord], now: i64) -> Persist let protocol = member .get("image_update_protocol") .and_then(serde_json::Value::as_u64); - if replica_id.is_none_or(|id| id.trim().is_empty()) || protocol != Some(1) { + if replica_id.is_none_or(|id| id.trim().is_empty()) || protocol != Some(2) { return Err(PersistenceError::Config( - "sandbox image updates require every live gateway membership record to advertise image-update protocol 1 and a nonempty replica id" + "sandbox image updates require every live gateway membership record to advertise image-update protocol 2 and a nonempty replica id" .into(), )); } @@ -231,7 +231,7 @@ mod tests { "gateway-member:legacy", "legacy", "", - br#"{"replica_id":"legacy","image_update_protocol":1}"#, + br#"{"replica_id":"legacy","image_update_protocol":2}"#, None, WriteCondition::MatchResourceVersion(member.resource_version), ) @@ -261,7 +261,7 @@ mod tests { fn compatible_live_members_and_empty_snapshot_pass() { assert!(ensure_live_members_compatible(&[], 100).is_ok()); let member = record( - br#"{"replica_id":"gw-0","peer_endpoint":"https://gw-0:8443","image_update_protocol":1}"#, + br#"{"replica_id":"gw-0","peer_endpoint":"https://gw-0:8443","image_update_protocol":2}"#, 100, ); assert!(ensure_live_members_compatible(&[member], 100).is_ok()); @@ -276,10 +276,10 @@ mod tests { br"null", br#"{"replica_id":"gw-0"}"#, br#"{"replica_id":"gw-0","image_update_protocol":0}"#, - br#"{"replica_id":"gw-0","image_update_protocol":2}"#, + br#"{"replica_id":"gw-0","image_update_protocol":1}"#, br#"{"replica_id":"gw-0","image_update_protocol":"1"}"#, br#"{"replica_id":"gw-0","image_update_protocol":true}"#, - br#"{"replica_id":"gw-0","image_update_protocol":1.0}"#, + br#"{"replica_id":"gw-0","image_update_protocol":2.0}"#, br#"{"image_update_protocol":1}"#, br#"{"replica_id":"","image_update_protocol":1}"#, br#"{"replica_id":" ","image_update_protocol":1}"#, @@ -301,7 +301,7 @@ mod tests { #[test] fn any_incompatible_live_member_rejects_the_snapshot() { - let compatible = record(br#"{"replica_id":"gw-0","image_update_protocol":1}"#, 100); + let compatible = record(br#"{"replica_id":"gw-0","image_update_protocol":2}"#, 100); let legacy = record(br#"{"replica_id":"gw-1"}"#, 100); assert!(ensure_live_members_compatible(&[compatible, legacy], 100).is_err()); } diff --git a/crates/openshell-server/src/persistence/postgres.rs b/crates/openshell-server/src/persistence/postgres.rs index caeae9c74c..9fdb08d42e 100644 --- a/crates/openshell-server/src/persistence/postgres.rs +++ b/crates/openshell-server/src/persistence/postgres.rs @@ -31,7 +31,7 @@ static POSTGRES_MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate!("./migrations /// A protocol capability, not an exact build version or an authorization /// credential. Identify every pool connection, including after reconnect. async fn identify_image_update_writer(connection: &mut PgConnection) -> Result<(), sqlx::Error> { - sqlx::query("SELECT set_config('application_name', 'openshell-image-update-v1', false)") + sqlx::query("SELECT set_config('application_name', 'openshell-image-update-v2', false)") .execute(connection) .await?; Ok(()) diff --git a/crates/openshell-server/src/persistence/sandbox_image.rs b/crates/openshell-server/src/persistence/sandbox_image.rs index a427062ffb..11ed0294f5 100644 --- a/crates/openshell-server/src/persistence/sandbox_image.rs +++ b/crates/openshell-server/src/persistence/sandbox_image.rs @@ -97,6 +97,20 @@ fn require_stopped(sandbox: &Sandbox) -> PersistenceResult<()> { } fn validate_intent(intent: &StoredSandboxImageUpdate) -> PersistenceResult<()> { + for map in [intent.labels.as_ref(), intent.annotations.as_ref()] + .into_iter() + .flatten() + { + if map + .values + .keys() + .any(|key| openshell_core::sandbox_update::is_system_metadata_key(key)) + { + return Err(PersistenceError::Encode( + "system metadata cannot be updated".into(), + )); + } + } if intent.operation_id.is_empty() || intent.previous_image.is_empty() || intent.image.is_empty() @@ -171,6 +185,13 @@ fn project_begin( return Err(conflict(Some(current_version))); } template.image.clone_from(&intent.image); + openshell_core::sandbox_update::apply_configuration( + &mut sandbox, + intent.command.as_ref(), + intent.environment.as_ref(), + intent.labels.as_ref(), + intent.annotations.as_ref(), + ); state.revision = next_revision; state.pending = Some(intent.clone()); state.previous_provisioning = previous_provisioning; @@ -215,6 +236,21 @@ fn project_complete( { return Err(conflict(Some(current_version))); } + // Acceptance already committed the annotation replacement. UpdateConfig + // may subsequently merge annotations while driver reconciliation is pending; + // preserve those accepted writes rather than requiring the old map forever. + // Annotations are gateway metadata and are not reconciled by the driver. + let mut target = sandbox.clone(); + openshell_core::sandbox_update::apply_configuration( + &mut target, + intent.command.as_ref(), + intent.environment.as_ref(), + intent.labels.as_ref(), + None, + ); + if target != sandbox { + return Err(conflict(Some(current_version))); + } let status = sandbox .status .as_mut() @@ -429,28 +465,33 @@ WHERE object_type = 'sandbox' AND id = $1 FOR UPDATE", })?; let now_ms = current_time_ms(); let sandbox_payload = sandbox.encode_to_vec(); + let labels = sandbox.metadata.as_ref().map(|metadata| &metadata.labels); + let labels = serde_json::to_value(labels) + .map_err(|error| PersistenceError::Encode(error.to_string()))?; let affected = match self { Self::Sqlite(tx) => sqlx::query( r#"UPDATE "objects" -SET "payload" = ?2, "updated_at_ms" = ?3, "resource_version" = "resource_version" + 1 +SET "payload" = ?2, "updated_at_ms" = ?3, "resource_version" = "resource_version" + 1, "labels" = ?5 WHERE "object_type" = 'sandbox' AND "id" = ?1 AND "resource_version" = ?4"#, ) .bind(sandbox_id) .bind(&sandbox_payload) .bind(now_ms) .bind(previous_version_sql) + .bind(labels.to_string()) .execute(&mut **tx) .await .map(|result| result.rows_affected()), Self::Postgres(tx) => sqlx::query( "UPDATE objects -SET payload = $2, updated_at_ms = $3, resource_version = resource_version + 1 +SET payload = $2, updated_at_ms = $3, resource_version = resource_version + 1, labels = $5 WHERE object_type = 'sandbox' AND id = $1 AND resource_version = $4", ) .bind(sandbox_id) .bind(&sandbox_payload) .bind(now_ms) .bind(previous_version_sql) + .bind(&labels) .execute(&mut **tx) .await .map(|result| result.rows_affected()), @@ -549,6 +590,7 @@ mod tests { previous_image: "old-image".into(), image: "new-image".into(), revision: 1, + ..Default::default() } } @@ -763,6 +805,7 @@ mod tests { previous_image: "new-image".into(), image: "newer-image".into(), revision: 2, + ..Default::default() }; assert!(project_begin(accepted, Some(state), 6, 1, &next).is_err()); } @@ -847,6 +890,99 @@ mod tests { (store, stored) } + #[test] + fn legacy_image_intent_decodes_without_configuration_selections() { + let decoded = + StoredSandboxImageUpdate::decode(&b"\x0a\x02op\x12\x01a\x1a\x01b\x20\x01"[..]).unwrap(); + assert_eq!(decoded.operation_id, "op"); + assert_eq!(decoded.previous_image, "a"); + assert_eq!(decoded.image, "b"); + assert_eq!(decoded.revision, 1); + assert!( + decoded.command.is_none() + && decoded.environment.is_none() + && decoded.labels.is_none() + && decoded.annotations.is_none() + ); + } + + #[tokio::test] + async fn sqlite_configuration_update_reindexes_labels_atomically() { + let (store, original) = fixture().await; + assert_configuration_update_reindexes_labels(&store, original).await; + } + + #[tokio::test] + #[ignore = "requires a disposable PostgreSQL database; run mise run test:rust:postgres"] + async fn postgres_sandbox_image_configuration_reindexes_labels_atomically() { + let schema = + super::super::test_postgres::TestSchema::create("sandbox_configuration_labels").await; + let store = schema.connect_store().await; + crate::ensure_default_workspace(&store).await.unwrap(); + store.put_message(&sandbox()).await.unwrap(); + let original = store + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(); + assert_configuration_update_reindexes_labels(&store, original).await; + store.close().await; + schema.drop_schema().await; + } + + async fn assert_configuration_update_reindexes_labels(store: &Store, mut original: Sandbox) { + use openshell_core::proto::SandboxMapUpdate; + original + .metadata + .as_mut() + .unwrap() + .labels + .insert("team".into(), "old".into()); + store.put_message(&original).await.unwrap(); + let original = store + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(); + let update = StoredSandboxImageUpdate { + labels: Some(SandboxMapUpdate { + values: std::collections::HashMap::from([("team".into(), "new".into())]), + }), + ..intent() + }; + store + .begin_sandbox_image_update("sandbox-id", resource_version(&original), 0, &update) + .await + .unwrap(); + assert!( + store + .list_with_selector("sandbox", "default", "team=old", 10, 0) + .await + .unwrap() + .is_empty() + ); + assert_eq!( + store + .list_with_selector("sandbox", "default", "team=new", 10, 0) + .await + .unwrap() + .len(), + 1 + ); + store + .complete_sandbox_image_update("sandbox-id", &update) + .await + .unwrap(); + assert_eq!( + store + .list_with_selector("sandbox", "default", "team=new", 10, 0) + .await + .unwrap() + .len(), + 1 + ); + } + #[tokio::test] async fn sqlite_accept_complete_and_legacy_rewrite_preserve_independent_state() { let (store, original) = fixture().await; @@ -944,6 +1080,7 @@ mod tests { previous_image: "new-image".into(), image: "newer-image".into(), revision: 2, + ..Default::default() }; store .begin_sandbox_image_update("sandbox-id", resource_version(&completed), 1, &next) @@ -1295,6 +1432,7 @@ updated_at_ms = $3 WHERE object_type = 'sandbox' AND id = $1 AND resource_versio previous_image: winning_intent.image.clone(), image: "next-generation-image".into(), revision: 2, + ..Default::default() }; let accepted_next = second .begin_sandbox_image_update("sandbox-id", resource_version(&completed), 1, &next) diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index 9212dfeea6..bdeb6cece7 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -172,12 +172,17 @@ mod tests { // Image updates add a separate public service/request and a new private // image-state format. Existing public status and frozen storage.v1 stay // unchanged; only the private durable closure grows. + // Configuration updates add presence-aware argv/map wrappers shared with + // private durable intent. Existing image-only payloads decode with all four + // selections absent; storage.v1 remains frozen. Public field 3 retains its + // 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 = - "15367b833a8ef74b18f4b1d06d88e43a6f6751ebd52135b70cd095808ee8438d"; + "be99bb3fcc7894eb85d774f54b642173e70dd37bc8e5fcaf3fdff2454ae689e1"; const DURABLE_SCHEMA_SHA256: &str = - "74d934bb33cc275730f193927d709f932681e8821868cf9b2261d10eba9e1195"; + "a20f41356b6cee4b543091c3533b0d4fd409d040fcfb2e17ecf1b6c4a3460794"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = - "ac1ffc4b5b81467de27270a4e33f6db1e31eeb2c52f79750dbaaf19515eadbb2"; + "c0c3ea17f105aaa6d843c466fd4240451c2105dce7675384935d4aaecdac8abf"; // 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"; @@ -647,7 +652,7 @@ mod tests { } assert_eq!( compiled_method_count, - 108 + PROVIDER_READINESS_RPC_SIGNATURES.len() + 109 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len() + PEER_CONFIG_RPC_SIGNATURES.len() + isolation_methods.len() @@ -718,9 +723,9 @@ mod tests { overlap_hash.as_str(), ), ( - (331, 31), - (97, 22), - (83, 22), + (334, 31), + (100, 22), + (86, 22), PUBLIC_RPC_SCHEMA_SHA256, DURABLE_SCHEMA_SHA256, PUBLIC_DURABLE_OVERLAP_SHA256 diff --git a/crates/openshell-server/src/test_support.rs b/crates/openshell-server/src/test_support.rs index b0c8fd8a94..85615e178a 100644 --- a/crates/openshell-server/src/test_support.rs +++ b/crates/openshell-server/src/test_support.rs @@ -107,6 +107,9 @@ pub enum FakeComputeDriverCall { CreateSandbox { sandbox: Option, }, + UpdateSandboxConfiguration { + request: openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest, + }, UpdateSandboxImage { request: openshell_core::proto::compute::v1::UpdateSandboxImageRequest, }, @@ -277,6 +280,7 @@ impl FakeComputeDriver { let task = tokio::spawn(async move { tonic::transport::Server::builder() .add_service(ComputeDriverServer::new(driver.clone())) + .add_service(openshell_core::proto::compute::v1::compute_driver_configuration_updates_server::ComputeDriverConfigurationUpdatesServer::new(driver.clone())) .add_service(ComputeDriverImageUpdatesServer::new(driver)) .serve_with_incoming(UnixIncoming { listener }) .await @@ -344,6 +348,32 @@ impl Stream for UnixIncoming { #[tonic::async_trait] impl openshell_core::compute::ComputeDriver for FakeComputeDriver { + async fn update_sandbox_configuration( + &self, + request: Request, + ) -> Result< + Response, + Status, + > { + self.record_traceparent(request.metadata()); + self.with_state(|state| { + let request = request.into_inner(); + let validate_only = request.image_update.as_ref().unwrap().validate_only; + state + .calls + .push(FakeComputeDriverCall::UpdateSandboxConfiguration { request }); + if let Some(code) = state.image_validation_error.filter(|_| validate_only) { + return Err(Status::new(code, "injected configuration validation error")); + } + if let Some(code) = state.image_update_error.filter(|_| !validate_only) { + return Err(Status::new(code, "injected configuration update error")); + } + Ok(Response::new( + openshell_core::proto::compute::v1::UpdateSandboxConfigurationResponse {}, + )) + }) + } + async fn update_sandbox_image( &self, request: Request, @@ -381,6 +411,13 @@ impl openshell_core::proto::compute::v1::compute_driver_image_updates_server::Co } } +#[tonic::async_trait] +impl openshell_core::proto::compute::v1::compute_driver_configuration_updates_server::ComputeDriverConfigurationUpdates for FakeComputeDriver { + async fn update_sandbox_configuration(&self, request: Request) -> Result, Status> { + openshell_core::compute::ComputeDriver::update_sandbox_configuration(self, request).await + } +} + #[tonic::async_trait] impl ComputeDriver for FakeComputeDriver { async fn authenticate_sandbox( diff --git a/docs/how-it-works/gateways/configuration.mdx b/docs/how-it-works/gateways/configuration.mdx index bdc25b875b..ce172ec393 100644 --- a/docs/how-it-works/gateways/configuration.mdx +++ b/docs/how-it-works/gateways/configuration.mdx @@ -256,7 +256,7 @@ metrics_bind_address = "0.0.0.0:9090" log_level = "info" # Activate only after retiring incompatible gateways and outstanding driver work. -enable_sandbox_image_updates = false +enable_sandbox_updates = false # Connection ceiling for the gateway's database pool. Omit to use the backend # default: 10 for Postgres, 5 for on-disk SQLite. @@ -502,16 +502,19 @@ Changing the installation name, the hostname format, or both changes every hash URL issued before the change; previously issued URLs stop resolving until callers request a fresh URL. -## Sandbox Image Updates +## Sandbox Updates -`[openshell.gateway] enable_sandbox_image_updates` defaults to `false`. It gates +`[openshell.gateway] enable_sandbox_updates` defaults to `false`. It gates the separate `openshell.v1.SandboxUpdates/UpdateSandbox` RPC on the existing -gateway listener. The equivalent gateway process flag and environment variable -are `--enable-sandbox-image-updates true` and -`OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES=true`. +gateway listener. It gates image, command, environment, label, and annotation +updates for stopped sandboxes. Protocol 2 requires upgrading all +gateways, including gateways that previously supported image-only updates. +The equivalent gateway process flag and environment variable +are `--enable-sandbox-updates true` and +`OPENSHELL_ENABLE_SANDBOX_UPDATES=true`. Enable it only after completing the -[activation checklist](/kubernetes/high-availability#activate-sandbox-image-updates). +[activation checklist](/kubernetes/high-availability#activate-sandbox-updates). Setting it to `true` attests that every gateway that can write the database is compatible and incompatible gateways cannot return. Keep it false throughout a rolling upgrade, including while outstanding operations from retired gateways @@ -521,7 +524,7 @@ For a schema-v2 file, set: ```toml [openshell.gateway] -enable_sandbox_image_updates = true +enable_sandbox_updates = true ``` The canonical Helm values form uses a dotted table key: @@ -529,7 +532,7 @@ The canonical Helm values form uses a dotted table key: ```yaml gatewayConfig: "openshell.gateway": - enable_sandbox_image_updates: true + enable_sandbox_updates: true ``` This is not an automatic mixed-version migration switch. Do not downgrade while diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index 2880287b09..18227567fc 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -1012,32 +1012,45 @@ For a provisioning timeout, wait for cleanup to finish, then run `sandbox start` ### Update the Image of a Stopped Sandbox -Use `openshell.v1.SandboxUpdates/UpdateSandbox` to change only a stopped -sandbox's workload image. This separate service uses the same gateway listener +Use `openshell.v1.SandboxUpdates/UpdateSandbox` to change a stopped sandbox's +workload image, command, environment overrides, labels, and annotations together. This separate service uses the same gateway listener and authentication as `OpenShell`; it requires `sandbox:write` and workspace user access. This operation initially supports the Kubernetes compute driver only; other drivers return `UNIMPLEMENTED` after activation. There is no `sandbox update` CLI command or curated SDK update method. Image updates default to disabled. Ask the operator to complete the -[compatible deployment rollout](/kubernetes/high-availability#activate-sandbox-image-updates) -before enabling `enable_sandbox_image_updates` in the -[gateway configuration](/how-it-works/gateways/configuration#sandbox-image-updates). +[compatible deployment rollout](/kubernetes/high-availability#activate-sandbox-updates) +before enabling `enable_sandbox_updates` in the +[gateway configuration](/how-it-works/gateways/configuration#sandbox-updates). The update preserves the sandbox ID, Kubernetes custom resource, and persistent volume claim. It does not delete and recreate the sandbox, reseed its existing workspace from the new image, or change the trusted supervisor and sandbox -runtime images. Other create-time configuration remains unchanged. Without a -pending update, submitting the same image reference is a no-op. Use a different -tag or an immutable digest to select new image content. +runtime images. Omitted fields retain their current values. A supplied command +replaces the argv list without shell expansion; an empty list restores the default +login shell resolved from the workload image. A supplied environment map replaces +sandbox-level overrides; clearing it restores any template-provided defaults. +Labels and annotations replace user metadata on the gateway resource, preserve +system-owned keys, and do not set Kubernetes pod metadata. Attempts to supply +system-owned keys are rejected. At least one update field is required. +Annotation changes accepted through `UpdateConfig` after the sandbox update is +accepted remain in place when the update completes, including after a retry. + +Without a pending update, a request whose target values already match is a no-op. +Use a different image tag or an immutable digest to select new image content. +Configuration updates require the driver's +`openshell.compute.update-sandbox-configuration` capability; image-only clients +can continue using `openshell.compute.update-sandbox-image`. Upgrade every gateway +before enabling updates: older gateways can ignore new request fields. Follow this sequence through the CLI and a generated/raw RPC client. 1. Run `openshell sandbox stop my-sandbox` and wait for `Stopped`. 2. Call `GetSandbox` with the named `workspace_scope` and sandbox `name`. Read `sandbox.metadata.resource_version` after stop completes. -3. Call `UpdateSandbox` with the same scope and name, the nonempty OCI workload - `image`, and `expected_resource_version` set to that current, nonzero +3. Call `UpdateSandbox` with the same scope and name, the selected update fields, + and `expected_resource_version` set to that current, nonzero version. The response is a `SandboxResponse`; the sandbox remains stopped. 4. After the update succeeds, run `openshell sandbox start my-sandbox` to launch the new image. @@ -1052,9 +1065,16 @@ let mut updates = client.raw_sandbox_updates_fresh().await?; let response = updates.update_sandbox(UpdateSandboxRequest { workspace_scope: Some(proto::workspace_selector("default")), name: "my-sandbox".into(), - image: "registry.example.com/agents/my-agent:2.0".into(), + image: Some("registry.example.com/agents/my-agent:2.0".into()), + command: Some(proto::SandboxCommandUpdate { + argv: vec!["/usr/local/bin/start-agent".into(), "--new-option".into()], + }), + environment: Some(proto::SandboxMapUpdate { + values: [("AGENT_MODE".into(), "updated".into())].into_iter().collect(), + }), expected_resource_version: current_resource_version, request_id: String::new(), + ..Default::default() }).await?; ``` @@ -1075,15 +1095,15 @@ target image. Start, stop, provisioning retry, and delete reject the pending operation. The public `SandboxStatus` shape is unchanged; image intent and revision remain private. Use the operation-pending error to guide recovery, not a status image -field. Read the current version and retry `UpdateSandbox` with the same image -you originally requested. Do not select another image or delete the sandbox to +field. Read the current version and retry `UpdateSandbox` with the same selected fields and target values +you originally requested. Do not select another configuration or delete the sandbox to bypass reconciliation. Only a successful retry clears the pending operation. The optional `request_id` uses [durable request admission](/sdk/api-errors#durable-request-admission). A retry with the same ID must keep the original payload, including its expected version. An unresolved admission returns `REQUEST_OUTCOME_UNCERTAIN` rather than executing again. Reconcile against the sandbox state and your original requested -image, then submit a new conditional same-image request with a fresh version +configuration, then submit a new conditional request for the same target with a fresh version and a new ID, or no ID. Do not change the expected version under the original ID or blindly switch IDs after a timeout. diff --git a/docs/kubernetes/high-availability.mdx b/docs/kubernetes/high-availability.mdx index ed7a6b0ce9..2d4eadf70b 100644 --- a/docs/kubernetes/high-availability.mdx +++ b/docs/kubernetes/high-availability.mdx @@ -504,10 +504,10 @@ during the upgrade, the older replicas serialize every mutation across the fleet. Mutations can be slower and can briefly fail under load until the rollout finishes. -### Activate Sandbox Image Updates +### Activate Sandbox Updates -Sandbox image updates default to disabled. Setting -`[openshell.gateway] enable_sandbox_image_updates = true` is an operator +Sandbox configuration updates default to disabled. Setting +`[openshell.gateway] enable_sandbox_updates = true` is an operator attestation that the deployment uniformly supports the image-update protocol. Use this sequence before activating the [separate update service](/how-it-works/sandboxes/overview#update-the-image-of-a-stopped-sandbox). @@ -520,18 +520,18 @@ Use this sequence before activating the retire old rollback targets, Jobs, and other launch configurations that could reconnect to the database. 3. Check all PostgreSQL client backends in the same database. The new binary - sets `application_name` to `openshell-image-update-v1` on every data-pool and + sets `application_name` to `openshell-image-update-v2` on every data-pool and lock-pool connection. Any unmarked client backend, including an administrative session, blocks image updates. Close those sessions or use a dedicated database. Do not relabel an old process to bypass this check. -4. Confirm live gateway membership records advertise image-update protocol 1. +4. Confirm live gateway membership records advertise image-update protocol 2. Missing or incompatible capabilities, malformed records, and truncated membership reads reject updates. These observations are not durable proof of fleet compatibility. Expiry or absence of a membership record does not prove that its process and driver work have stopped. 5. Activate the flag only after completing retirement and preventing old gateways from returning. See the exact - [TOML, environment, process flag, and Helm forms](/how-it-works/gateways/configuration#sandbox-image-updates). + [TOML, environment, process flag, and Helm forms](/how-it-works/gateways/configuration#sandbox-updates). A pending image update atomically sets the existing `provisioning.driver_operation_pending` and `provisioning.driver_operation_id` diff --git a/docs/sdk/api-errors.mdx b/docs/sdk/api-errors.mdx index 6efc52650b..b782afc4ba 100644 --- a/docs/sdk/api-errors.mdx +++ b/docs/sdk/api-errors.mdx @@ -198,11 +198,11 @@ before relying on IDs; older protobuf servers can silently ignore unknown fields ### Sandbox image update recovery -`SandboxUpdates.UpdateSandbox` is an image-only conditional mutation for stopped +`SandboxUpdates.UpdateSandbox` conditionally updates image, command, environment overrides, labels, and annotations for stopped Kubernetes sandboxes. It defaults to disabled and returns `FAILED_PRECONDITION` -until the operator [activates a compatible deployment](/kubernetes/high-availability#activate-sandbox-image-updates). +until the operator [activates a compatible deployment](/kubernetes/high-availability#activate-sandbox-updates). After activation, other compute drivers return `UNIMPLEMENTED`. Supply a named -`workspace_scope`, sandbox `name`, nonempty OCI `image`, and a required nonzero +`workspace_scope`, sandbox `name`, at least one selected update field, and a required nonzero `expected_resource_version` read from `sandbox.metadata.resource_version`. A stale version returns `ABORTED`; read fresh state before constructing another conditional request. The operation does not start compute. @@ -212,14 +212,14 @@ image alone does not prove driver reconciliation completed. Start, stop, provisioning retry, and delete return `FAILED_PRECONDITION` while that operation remains. Image intent and revision are private; the public `SandboxStatus` shape does not change. On an operation-pending error, read a fresh resource version and retry -the same image originally requested. A different target image cannot replace a +the same selected fields and target values originally requested. A different configuration cannot replace a pending update. If the original request supplied `request_id`, an error leaves its admission unresolved. Reusing that ID with the original payload returns `REQUEST_OUTCOME_UNCERTAIN`; changing its expected version returns -`REQUEST_ID_PAYLOAD_MISMATCH`. Reconcile against the original requested image, -then make a new conditional same-image request with the fresh version and a new +`REQUEST_ID_PAYLOAD_MISMATCH`. Reconcile against the original requested configuration, +then make a new conditional request for the same target with the fresh version and a new ID, or without an ID. This is explicit recovery, not permission to blindly repeat uncertain mutations. A replay of a confirmed success returns the sandbox's current state without applying the image again. diff --git a/e2e/rust/tests/kubernetes_image_update.rs b/e2e/rust/tests/kubernetes_image_update.rs index d04f42ff0e..d1ff02e71f 100644 --- a/e2e/rust/tests/kubernetes_image_update.rs +++ b/e2e/rust/tests/kubernetes_image_update.rs @@ -334,7 +334,7 @@ async fn assert_image_update_supported(client: &mut AuthedGrpcClient) { extension .supported_capabilities .iter() - .any(|capability| capability == "openshell.compute.update-sandbox-image") + .any(|capability| capability == "openshell.compute.update-sandbox-configuration") })); } @@ -371,13 +371,14 @@ async fn image_update_retains_workspace_and_identity() { let running_update = proto::UpdateSandboxRequest { workspace_scope: Some(proto::workspace_selector("default")), name: sandbox.name.clone(), - image: UPDATED_IMAGE.to_owned(), + image: Some(UPDATED_IMAGE.to_owned()), expected_resource_version: original .metadata .as_ref() .expect("metadata") .resource_version, request_id: String::new(), + ..Default::default() }; let error = image_client .update_sandbox(rpc(running_update.clone())) @@ -399,6 +400,14 @@ async fn image_update_retains_workspace_and_identity() { .expect("metadata") .resource_version, request_id: request_id(), + command: Some(proto::SandboxCommandUpdate { argv: vec![ + "/bin/sh".into(), "-c".into(), + "mkdir -p /sandbox/harness; printf '%s:%s' \"$AGENT_MODE\" \"$1\" > /sandbox/harness/configuration; exec sleep 86400".into(), + "agent-bootstrap".into(), "new-argument".into(), + ] }), + environment: Some(proto::SandboxMapUpdate { values: std::collections::HashMap::from([("AGENT_MODE".into(), "updated".into())]) }), + labels: Some(proto::SandboxMapUpdate { values: std::collections::HashMap::from([("team".into(), "updated-agent".into())]) }), + annotations: Some(proto::SandboxMapUpdate { values: std::collections::HashMap::from([("example.com/revision".into(), "2".into())]) }), ..running_update }; let updated = image_client @@ -419,6 +428,35 @@ async fn image_update_retains_workspace_and_identity() { .await .expect("updated sandbox ready"); assert_base_release(&sandbox, "3.22.").await; + assert_eq!( + sandbox + .exec(&["cat", "/sandbox/harness/configuration"]) + .await + .expect("updated command and environment ran on start") + .trim(), + "updated:new-argument" + ); + let observed = get_sandbox(&mut client, &sandbox.name).await; + assert_eq!( + observed + .metadata + .as_ref() + .unwrap() + .labels + .get("team") + .map(String::as_str), + Some("updated-agent") + ); + assert_eq!( + observed + .metadata + .as_ref() + .unwrap() + .annotations + .get("example.com/revision") + .map(String::as_str), + Some("2") + ); assert_eq!( sandbox .exec(&["cat", SENTINEL_PATH]) diff --git a/e2e/with-kube-gateway.sh b/e2e/with-kube-gateway.sh index 43d7ae5367..31c0771dc8 100755 --- a/e2e/with-kube-gateway.sh +++ b/e2e/with-kube-gateway.sh @@ -1323,7 +1323,7 @@ fi # production rolling upgrade. Explicitly activate the image-update scenario; # callers can keep activation disabled for negative coverage. if [ "${OPENSHELL_E2E_KUBE_IMAGE_UPDATES:-1}" = "1" ]; then - helm_extra_args+=(--set 'gatewayConfig.openshell\.gateway.enable_sandbox_image_updates=true') + helm_extra_args+=(--set 'gatewayConfig.openshell\.gateway.enable_sandbox_updates=true') fi if [ "${OPENSHELL_E2E_EXTERNAL_COMPUTE_DRIVER:-0}" = "1" ]; then if [ "${OPENSHELL_E2E_KUBE_BUILD_IMAGES}" != "1" ]; then diff --git a/proto/compute_driver.proto b/proto/compute_driver.proto index 3734db611d..12c7efc2aa 100644 --- a/proto/compute_driver.proto +++ b/proto/compute_driver.proto @@ -87,6 +87,33 @@ service ComputeDriverImageUpdates { returns (UpdateSandboxImageResponse); } +// Optional extension; never send configuration changes through the image-only RPC. +service ComputeDriverConfigurationUpdates { + rpc UpdateSandboxConfiguration(UpdateSandboxConfigurationRequest) + returns (UpdateSandboxConfigurationResponse); +} + +message UpdateSandboxConfigurationRequest { + // Shared lifecycle, image, revision and runtime identity preconditions. + UpdateSandboxImageRequest image_update = 1; + // Absent leaves the command unchanged; empty restores the default shell. + SandboxMainProcessUpdate main_process = 2; + // Effective user environment after template inheritance. Presence replaces it. + SandboxEnvironmentUpdate environment = 3; +} + +// Only workload argv and its existing TTY setting are carried to the driver. +message SandboxMainProcessUpdate { + repeated string command = 1; + bool tty = 2; +} + +message SandboxEnvironmentUpdate { + map values = 1; +} + +message UpdateSandboxConfigurationResponse {} + message GetCapabilitiesRequest { // Gateway protocol metadata. Drivers must reject unmet requirements. openshell.extension.v1.PeerMetadata gateway = 1; diff --git a/proto/openshell.proto b/proto/openshell.proto index e5cbd4651d..027be4a87c 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -861,9 +861,10 @@ service OpenShell { // Optional sandbox mutations are separate from OpenShell so existing generated // OpenShell server implementations remain source-compatible. service SandboxUpdates { - // Update only the workload image of a stopped sandbox without deleting its - // identity or retained storage. Requires compute-driver image-update support - // and explicit gateway activation of sandbox image updates. + // Update the workload image, command, environment, labels, or annotations of a + // stopped sandbox while preserving its identity and retained storage. Requires + // compute-driver support for the selected changes and explicit gateway activation + // of sandbox updates. rpc UpdateSandbox(UpdateSandboxRequest) returns (SandboxResponse) { option (openshell.options.v1.authorization) = { auth_mode: "bearer" @@ -1345,8 +1346,8 @@ message CreateSandboxRequest { repeated SandboxServiceExposure service_exposures = 9; } -// Image-only update. Other create-time configuration is not mutable through -// this RPC. Stop before updating; start explicitly after a successful update. +// Update selected configuration of a stopped sandbox. Omitted fields are unchanged. +// Start explicitly after a successful update. At least one field must be selected. message UpdateSandboxRequest { // Workspace scope. Only a named workspace selection is accepted. openshell.datamodel.v1.WorkspaceSelector workspace_scope = 1; @@ -1354,13 +1355,30 @@ message UpdateSandboxRequest { string name = 2; // Nonempty OCI workload image reference. This does not change trusted runtime // images or reseed an existing workspace. - string image = 3; + optional string image = 3; + // Replace workload argv; an empty list restores image-resolved default shell behavior. + SandboxCommandUpdate command = 6; + // Replace sandbox-level overrides. Empty clears overrides; template defaults remain. + SandboxMapUpdate environment = 7; + // Replace user metadata, preserving gateway-owned keys. These do not set pod metadata. + SandboxMapUpdate labels = 8; + SandboxMapUpdate annotations = 9; // Required nonzero resource version read by the caller. uint64 expected_resource_version = 4; // Optional nonzero UUID for durable at-most-once admission. string request_id = 5; } +// Presence selects replacement, including an explicitly empty list. +message SandboxCommandUpdate { + repeated string argv = 1; +} + +// Presence selects replacement, including an explicitly empty map. +message SandboxMapUpdate { + map values = 1; +} + message CreateSandboxTemplateRequest { // Workspace scope. Only a named workspace selection is accepted. openshell.datamodel.v1.WorkspaceSelector workspace_scope = 2; diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index 52474fd366..9214f4f9d0 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -3695,8 +3695,8 @@ func (x *CreateSandboxRequest) GetServiceExposures() []*SandboxServiceExposure { return nil } -// Image-only update. Other create-time configuration is not mutable through -// this RPC. Stop before updating; start explicitly after a successful update. +// Update selected configuration of a stopped sandbox. Omitted fields are unchanged. +// Start explicitly after a successful update. At least one field must be selected. type UpdateSandboxRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // Workspace scope. Only a named workspace selection is accepted. @@ -3705,7 +3705,14 @@ type UpdateSandboxRequest struct { Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // Nonempty OCI workload image reference. This does not change trusted runtime // images or reseed an existing workspace. - Image string `protobuf:"bytes,3,opt,name=image,proto3" json:"image,omitempty"` + Image *string `protobuf:"bytes,3,opt,name=image,proto3,oneof" json:"image,omitempty"` + // Replace workload argv; an empty list restores image-resolved default shell behavior. + Command *SandboxCommandUpdate `protobuf:"bytes,6,opt,name=command,proto3" json:"command,omitempty"` + // Replace sandbox-level overrides. Empty clears overrides; template defaults remain. + Environment *SandboxMapUpdate `protobuf:"bytes,7,opt,name=environment,proto3" json:"environment,omitempty"` + // Replace user metadata, preserving gateway-owned keys. These do not set pod metadata. + Labels *SandboxMapUpdate `protobuf:"bytes,8,opt,name=labels,proto3" json:"labels,omitempty"` + Annotations *SandboxMapUpdate `protobuf:"bytes,9,opt,name=annotations,proto3" json:"annotations,omitempty"` // Required nonzero resource version read by the caller. ExpectedResourceVersion uint64 `protobuf:"varint,4,opt,name=expected_resource_version,json=expectedResourceVersion,proto3" json:"expected_resource_version,omitempty"` // Optional nonzero UUID for durable at-most-once admission. @@ -3759,12 +3766,40 @@ func (x *UpdateSandboxRequest) GetName() string { } func (x *UpdateSandboxRequest) GetImage() string { - if x != nil { - return x.Image + if x != nil && x.Image != nil { + return *x.Image } return "" } +func (x *UpdateSandboxRequest) GetCommand() *SandboxCommandUpdate { + if x != nil { + return x.Command + } + return nil +} + +func (x *UpdateSandboxRequest) GetEnvironment() *SandboxMapUpdate { + if x != nil { + return x.Environment + } + return nil +} + +func (x *UpdateSandboxRequest) GetLabels() *SandboxMapUpdate { + if x != nil { + return x.Labels + } + return nil +} + +func (x *UpdateSandboxRequest) GetAnnotations() *SandboxMapUpdate { + if x != nil { + return x.Annotations + } + return nil +} + func (x *UpdateSandboxRequest) GetExpectedResourceVersion() uint64 { if x != nil { return x.ExpectedResourceVersion @@ -3779,6 +3814,96 @@ func (x *UpdateSandboxRequest) GetRequestId() string { return "" } +// Presence selects replacement, including an explicitly empty list. +type SandboxCommandUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + Argv []string `protobuf:"bytes,1,rep,name=argv,proto3" json:"argv,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxCommandUpdate) Reset() { + *x = SandboxCommandUpdate{} + mi := &file_openshell_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxCommandUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxCommandUpdate) ProtoMessage() {} + +func (x *SandboxCommandUpdate) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[34] + 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 SandboxCommandUpdate.ProtoReflect.Descriptor instead. +func (*SandboxCommandUpdate) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{34} +} + +func (x *SandboxCommandUpdate) GetArgv() []string { + if x != nil { + return x.Argv + } + return nil +} + +// Presence selects replacement, including an explicitly empty map. +type SandboxMapUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + Values map[string]string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxMapUpdate) Reset() { + *x = SandboxMapUpdate{} + mi := &file_openshell_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxMapUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxMapUpdate) ProtoMessage() {} + +func (x *SandboxMapUpdate) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[35] + 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 SandboxMapUpdate.ProtoReflect.Descriptor instead. +func (*SandboxMapUpdate) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{35} +} + +func (x *SandboxMapUpdate) GetValues() map[string]string { + if x != nil { + return x.Values + } + return nil +} + type CreateSandboxTemplateRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // Workspace scope. Only a named workspace selection is accepted. @@ -3793,7 +3918,7 @@ type CreateSandboxTemplateRequest struct { func (x *CreateSandboxTemplateRequest) Reset() { *x = CreateSandboxTemplateRequest{} - mi := &file_openshell_proto_msgTypes[34] + mi := &file_openshell_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3805,7 +3930,7 @@ func (x *CreateSandboxTemplateRequest) String() string { func (*CreateSandboxTemplateRequest) ProtoMessage() {} func (x *CreateSandboxTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[34] + mi := &file_openshell_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3818,7 +3943,7 @@ func (x *CreateSandboxTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSandboxTemplateRequest.ProtoReflect.Descriptor instead. func (*CreateSandboxTemplateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{34} + return file_openshell_proto_rawDescGZIP(), []int{36} } func (x *CreateSandboxTemplateRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3853,7 +3978,7 @@ type GetSandboxTemplateRequest struct { func (x *GetSandboxTemplateRequest) Reset() { *x = GetSandboxTemplateRequest{} - mi := &file_openshell_proto_msgTypes[35] + mi := &file_openshell_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3865,7 +3990,7 @@ func (x *GetSandboxTemplateRequest) String() string { func (*GetSandboxTemplateRequest) ProtoMessage() {} func (x *GetSandboxTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[35] + mi := &file_openshell_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3878,7 +4003,7 @@ func (x *GetSandboxTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxTemplateRequest.ProtoReflect.Descriptor instead. func (*GetSandboxTemplateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{35} + return file_openshell_proto_rawDescGZIP(), []int{37} } func (x *GetSandboxTemplateRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3913,7 +4038,7 @@ type ListSandboxTemplatesRequest struct { func (x *ListSandboxTemplatesRequest) Reset() { *x = ListSandboxTemplatesRequest{} - mi := &file_openshell_proto_msgTypes[36] + mi := &file_openshell_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3925,7 +4050,7 @@ func (x *ListSandboxTemplatesRequest) String() string { func (*ListSandboxTemplatesRequest) ProtoMessage() {} func (x *ListSandboxTemplatesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[36] + mi := &file_openshell_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3938,7 +4063,7 @@ func (x *ListSandboxTemplatesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxTemplatesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxTemplatesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{36} + return file_openshell_proto_rawDescGZIP(), []int{38} } func (x *ListSandboxTemplatesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -3985,7 +4110,7 @@ type DeleteSandboxTemplateRequest struct { func (x *DeleteSandboxTemplateRequest) Reset() { *x = DeleteSandboxTemplateRequest{} - mi := &file_openshell_proto_msgTypes[37] + mi := &file_openshell_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3997,7 +4122,7 @@ func (x *DeleteSandboxTemplateRequest) String() string { func (*DeleteSandboxTemplateRequest) ProtoMessage() {} func (x *DeleteSandboxTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[37] + mi := &file_openshell_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4010,7 +4135,7 @@ func (x *DeleteSandboxTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxTemplateRequest.ProtoReflect.Descriptor instead. func (*DeleteSandboxTemplateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{37} + return file_openshell_proto_rawDescGZIP(), []int{39} } func (x *DeleteSandboxTemplateRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4050,7 +4175,7 @@ type SandboxTemplateResponse struct { func (x *SandboxTemplateResponse) Reset() { *x = SandboxTemplateResponse{} - mi := &file_openshell_proto_msgTypes[38] + mi := &file_openshell_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4062,7 +4187,7 @@ func (x *SandboxTemplateResponse) String() string { func (*SandboxTemplateResponse) ProtoMessage() {} func (x *SandboxTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[38] + mi := &file_openshell_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4075,7 +4200,7 @@ func (x *SandboxTemplateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxTemplateResponse.ProtoReflect.Descriptor instead. func (*SandboxTemplateResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{38} + return file_openshell_proto_rawDescGZIP(), []int{40} } func (x *SandboxTemplateResponse) GetTemplate() *SandboxWorkloadTemplate { @@ -4096,7 +4221,7 @@ type ListSandboxTemplatesResponse struct { func (x *ListSandboxTemplatesResponse) Reset() { *x = ListSandboxTemplatesResponse{} - mi := &file_openshell_proto_msgTypes[39] + mi := &file_openshell_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4108,7 +4233,7 @@ func (x *ListSandboxTemplatesResponse) String() string { func (*ListSandboxTemplatesResponse) ProtoMessage() {} func (x *ListSandboxTemplatesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[39] + mi := &file_openshell_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4121,7 +4246,7 @@ func (x *ListSandboxTemplatesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxTemplatesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxTemplatesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{39} + return file_openshell_proto_rawDescGZIP(), []int{41} } func (x *ListSandboxTemplatesResponse) GetTemplates() []*SandboxWorkloadTemplate { @@ -4147,7 +4272,7 @@ type DeleteSandboxTemplateResponse struct { func (x *DeleteSandboxTemplateResponse) Reset() { *x = DeleteSandboxTemplateResponse{} - mi := &file_openshell_proto_msgTypes[40] + mi := &file_openshell_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4159,7 +4284,7 @@ func (x *DeleteSandboxTemplateResponse) String() string { func (*DeleteSandboxTemplateResponse) ProtoMessage() {} func (x *DeleteSandboxTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[40] + mi := &file_openshell_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4172,7 +4297,7 @@ func (x *DeleteSandboxTemplateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxTemplateResponse.ProtoReflect.Descriptor instead. func (*DeleteSandboxTemplateResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{40} + return file_openshell_proto_rawDescGZIP(), []int{42} } func (x *DeleteSandboxTemplateResponse) GetOutcome() DeletionOutcome { @@ -4199,7 +4324,7 @@ type BeginRootfsTarStagingRequest struct { func (x *BeginRootfsTarStagingRequest) Reset() { *x = BeginRootfsTarStagingRequest{} - mi := &file_openshell_proto_msgTypes[41] + mi := &file_openshell_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4211,7 +4336,7 @@ func (x *BeginRootfsTarStagingRequest) String() string { func (*BeginRootfsTarStagingRequest) ProtoMessage() {} func (x *BeginRootfsTarStagingRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[41] + mi := &file_openshell_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4224,7 +4349,7 @@ func (x *BeginRootfsTarStagingRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BeginRootfsTarStagingRequest.ProtoReflect.Descriptor instead. func (*BeginRootfsTarStagingRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{41} + return file_openshell_proto_rawDescGZIP(), []int{43} } func (x *BeginRootfsTarStagingRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4267,7 +4392,7 @@ type BeginRootfsTarStagingResponse struct { func (x *BeginRootfsTarStagingResponse) Reset() { *x = BeginRootfsTarStagingResponse{} - mi := &file_openshell_proto_msgTypes[42] + mi := &file_openshell_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4279,7 +4404,7 @@ func (x *BeginRootfsTarStagingResponse) String() string { func (*BeginRootfsTarStagingResponse) ProtoMessage() {} func (x *BeginRootfsTarStagingResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[42] + mi := &file_openshell_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4292,7 +4417,7 @@ func (x *BeginRootfsTarStagingResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BeginRootfsTarStagingResponse.ProtoReflect.Descriptor instead. func (*BeginRootfsTarStagingResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{42} + return file_openshell_proto_rawDescGZIP(), []int{44} } func (x *BeginRootfsTarStagingResponse) GetStagingToken() string { @@ -4335,7 +4460,7 @@ type GetSandboxRequest struct { func (x *GetSandboxRequest) Reset() { *x = GetSandboxRequest{} - mi := &file_openshell_proto_msgTypes[43] + mi := &file_openshell_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4347,7 +4472,7 @@ func (x *GetSandboxRequest) String() string { func (*GetSandboxRequest) ProtoMessage() {} func (x *GetSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[43] + mi := &file_openshell_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4360,7 +4485,7 @@ func (x *GetSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxRequest.ProtoReflect.Descriptor instead. func (*GetSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{43} + return file_openshell_proto_rawDescGZIP(), []int{45} } func (x *GetSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4396,7 +4521,7 @@ type ListSandboxesRequest struct { func (x *ListSandboxesRequest) Reset() { *x = ListSandboxesRequest{} - mi := &file_openshell_proto_msgTypes[44] + mi := &file_openshell_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4408,7 +4533,7 @@ func (x *ListSandboxesRequest) String() string { func (*ListSandboxesRequest) ProtoMessage() {} func (x *ListSandboxesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[44] + mi := &file_openshell_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4421,7 +4546,7 @@ func (x *ListSandboxesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{44} + return file_openshell_proto_rawDescGZIP(), []int{46} } func (x *ListSandboxesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4470,7 +4595,7 @@ type ListSandboxProvidersRequest struct { func (x *ListSandboxProvidersRequest) Reset() { *x = ListSandboxProvidersRequest{} - mi := &file_openshell_proto_msgTypes[45] + mi := &file_openshell_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4482,7 +4607,7 @@ func (x *ListSandboxProvidersRequest) String() string { func (*ListSandboxProvidersRequest) ProtoMessage() {} func (x *ListSandboxProvidersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[45] + mi := &file_openshell_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4495,7 +4620,7 @@ func (x *ListSandboxProvidersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxProvidersRequest.ProtoReflect.Descriptor instead. func (*ListSandboxProvidersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{45} + return file_openshell_proto_rawDescGZIP(), []int{47} } func (x *ListSandboxProvidersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4548,7 +4673,7 @@ type AttachSandboxProviderRequest struct { func (x *AttachSandboxProviderRequest) Reset() { *x = AttachSandboxProviderRequest{} - mi := &file_openshell_proto_msgTypes[46] + mi := &file_openshell_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4560,7 +4685,7 @@ func (x *AttachSandboxProviderRequest) String() string { func (*AttachSandboxProviderRequest) ProtoMessage() {} func (x *AttachSandboxProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[46] + mi := &file_openshell_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4573,7 +4698,7 @@ func (x *AttachSandboxProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachSandboxProviderRequest.ProtoReflect.Descriptor instead. func (*AttachSandboxProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{46} + return file_openshell_proto_rawDescGZIP(), []int{48} } func (x *AttachSandboxProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4633,7 +4758,7 @@ type DetachSandboxProviderRequest struct { func (x *DetachSandboxProviderRequest) Reset() { *x = DetachSandboxProviderRequest{} - mi := &file_openshell_proto_msgTypes[47] + mi := &file_openshell_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4645,7 +4770,7 @@ func (x *DetachSandboxProviderRequest) String() string { func (*DetachSandboxProviderRequest) ProtoMessage() {} func (x *DetachSandboxProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[47] + mi := &file_openshell_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4658,7 +4783,7 @@ func (x *DetachSandboxProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachSandboxProviderRequest.ProtoReflect.Descriptor instead. func (*DetachSandboxProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{47} + return file_openshell_proto_rawDescGZIP(), []int{49} } func (x *DetachSandboxProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4715,7 +4840,7 @@ type DeleteSandboxRequest struct { func (x *DeleteSandboxRequest) Reset() { *x = DeleteSandboxRequest{} - mi := &file_openshell_proto_msgTypes[48] + mi := &file_openshell_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4727,7 +4852,7 @@ func (x *DeleteSandboxRequest) String() string { func (*DeleteSandboxRequest) ProtoMessage() {} func (x *DeleteSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[48] + mi := &file_openshell_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4740,7 +4865,7 @@ func (x *DeleteSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxRequest.ProtoReflect.Descriptor instead. func (*DeleteSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{48} + return file_openshell_proto_rawDescGZIP(), []int{50} } func (x *DeleteSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4786,7 +4911,7 @@ type StopSandboxRequest struct { func (x *StopSandboxRequest) Reset() { *x = StopSandboxRequest{} - mi := &file_openshell_proto_msgTypes[49] + mi := &file_openshell_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4798,7 +4923,7 @@ func (x *StopSandboxRequest) String() string { func (*StopSandboxRequest) ProtoMessage() {} func (x *StopSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[49] + mi := &file_openshell_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4811,7 +4936,7 @@ func (x *StopSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StopSandboxRequest.ProtoReflect.Descriptor instead. func (*StopSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{49} + return file_openshell_proto_rawDescGZIP(), []int{51} } func (x *StopSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4850,7 +4975,7 @@ type StartSandboxRequest struct { func (x *StartSandboxRequest) Reset() { *x = StartSandboxRequest{} - mi := &file_openshell_proto_msgTypes[50] + mi := &file_openshell_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4862,7 +4987,7 @@ func (x *StartSandboxRequest) String() string { func (*StartSandboxRequest) ProtoMessage() {} func (x *StartSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[50] + mi := &file_openshell_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4875,7 +5000,7 @@ func (x *StartSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartSandboxRequest.ProtoReflect.Descriptor instead. func (*StartSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{50} + return file_openshell_proto_rawDescGZIP(), []int{52} } func (x *StartSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4911,7 +5036,7 @@ type SuspendSandboxRequest struct { func (x *SuspendSandboxRequest) Reset() { *x = SuspendSandboxRequest{} - mi := &file_openshell_proto_msgTypes[51] + mi := &file_openshell_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4923,7 +5048,7 @@ func (x *SuspendSandboxRequest) String() string { func (*SuspendSandboxRequest) ProtoMessage() {} func (x *SuspendSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[51] + mi := &file_openshell_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4936,7 +5061,7 @@ func (x *SuspendSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendSandboxRequest.ProtoReflect.Descriptor instead. func (*SuspendSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{51} + return file_openshell_proto_rawDescGZIP(), []int{53} } func (x *SuspendSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -4968,7 +5093,7 @@ type ResumeSandboxRequest struct { func (x *ResumeSandboxRequest) Reset() { *x = ResumeSandboxRequest{} - mi := &file_openshell_proto_msgTypes[52] + mi := &file_openshell_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4980,7 +5105,7 @@ func (x *ResumeSandboxRequest) String() string { func (*ResumeSandboxRequest) ProtoMessage() {} func (x *ResumeSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[52] + mi := &file_openshell_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4993,7 +5118,7 @@ func (x *ResumeSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeSandboxRequest.ProtoReflect.Descriptor instead. func (*ResumeSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{52} + return file_openshell_proto_rawDescGZIP(), []int{54} } func (x *ResumeSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -5030,7 +5155,7 @@ type SandboxResponse struct { func (x *SandboxResponse) Reset() { *x = SandboxResponse{} - mi := &file_openshell_proto_msgTypes[53] + mi := &file_openshell_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5042,7 +5167,7 @@ func (x *SandboxResponse) String() string { func (*SandboxResponse) ProtoMessage() {} func (x *SandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[53] + mi := &file_openshell_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5055,7 +5180,7 @@ func (x *SandboxResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxResponse.ProtoReflect.Descriptor instead. func (*SandboxResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{53} + return file_openshell_proto_rawDescGZIP(), []int{55} } func (x *SandboxResponse) GetSandbox() *Sandbox { @@ -5084,7 +5209,7 @@ type ListSandboxesResponse struct { func (x *ListSandboxesResponse) Reset() { *x = ListSandboxesResponse{} - mi := &file_openshell_proto_msgTypes[54] + mi := &file_openshell_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5096,7 +5221,7 @@ func (x *ListSandboxesResponse) String() string { func (*ListSandboxesResponse) ProtoMessage() {} func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[54] + mi := &file_openshell_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5109,7 +5234,7 @@ func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{54} + return file_openshell_proto_rawDescGZIP(), []int{56} } func (x *ListSandboxesResponse) GetSandboxes() []*Sandbox { @@ -5138,7 +5263,7 @@ type ListSandboxProvidersResponse struct { func (x *ListSandboxProvidersResponse) Reset() { *x = ListSandboxProvidersResponse{} - mi := &file_openshell_proto_msgTypes[55] + mi := &file_openshell_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5150,7 +5275,7 @@ func (x *ListSandboxProvidersResponse) String() string { func (*ListSandboxProvidersResponse) ProtoMessage() {} func (x *ListSandboxProvidersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[55] + mi := &file_openshell_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5163,7 +5288,7 @@ func (x *ListSandboxProvidersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxProvidersResponse.ProtoReflect.Descriptor instead. func (*ListSandboxProvidersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{55} + return file_openshell_proto_rawDescGZIP(), []int{57} } func (x *ListSandboxProvidersResponse) GetProviders() []*datamodelv1.Provider { @@ -5194,7 +5319,7 @@ type AttachSandboxProviderResponse struct { func (x *AttachSandboxProviderResponse) Reset() { *x = AttachSandboxProviderResponse{} - mi := &file_openshell_proto_msgTypes[56] + mi := &file_openshell_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5206,7 +5331,7 @@ func (x *AttachSandboxProviderResponse) String() string { func (*AttachSandboxProviderResponse) ProtoMessage() {} func (x *AttachSandboxProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[56] + mi := &file_openshell_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5219,7 +5344,7 @@ func (x *AttachSandboxProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachSandboxProviderResponse.ProtoReflect.Descriptor instead. func (*AttachSandboxProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{56} + return file_openshell_proto_rawDescGZIP(), []int{58} } func (x *AttachSandboxProviderResponse) GetSandbox() *Sandbox { @@ -5257,7 +5382,7 @@ type DetachSandboxProviderResponse struct { func (x *DetachSandboxProviderResponse) Reset() { *x = DetachSandboxProviderResponse{} - mi := &file_openshell_proto_msgTypes[57] + mi := &file_openshell_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5269,7 +5394,7 @@ func (x *DetachSandboxProviderResponse) String() string { func (*DetachSandboxProviderResponse) ProtoMessage() {} func (x *DetachSandboxProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[57] + mi := &file_openshell_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5282,7 +5407,7 @@ func (x *DetachSandboxProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachSandboxProviderResponse.ProtoReflect.Descriptor instead. func (*DetachSandboxProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{57} + return file_openshell_proto_rawDescGZIP(), []int{59} } func (x *DetachSandboxProviderResponse) GetSandbox() *Sandbox { @@ -5324,7 +5449,7 @@ type ProviderDesiredIdentity struct { func (x *ProviderDesiredIdentity) Reset() { *x = ProviderDesiredIdentity{} - mi := &file_openshell_proto_msgTypes[58] + mi := &file_openshell_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5336,7 +5461,7 @@ func (x *ProviderDesiredIdentity) String() string { func (*ProviderDesiredIdentity) ProtoMessage() {} func (x *ProviderDesiredIdentity) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[58] + mi := &file_openshell_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5349,7 +5474,7 @@ func (x *ProviderDesiredIdentity) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderDesiredIdentity.ProtoReflect.Descriptor instead. func (*ProviderDesiredIdentity) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{58} + return file_openshell_proto_rawDescGZIP(), []int{60} } func (x *ProviderDesiredIdentity) GetSandboxId() string { @@ -5424,7 +5549,7 @@ type ConfigSnapshotRevision struct { func (x *ConfigSnapshotRevision) Reset() { *x = ConfigSnapshotRevision{} - mi := &file_openshell_proto_msgTypes[59] + mi := &file_openshell_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5436,7 +5561,7 @@ func (x *ConfigSnapshotRevision) String() string { func (*ConfigSnapshotRevision) ProtoMessage() {} func (x *ConfigSnapshotRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[59] + mi := &file_openshell_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5449,7 +5574,7 @@ func (x *ConfigSnapshotRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigSnapshotRevision.ProtoReflect.Descriptor instead. func (*ConfigSnapshotRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{59} + return file_openshell_proto_rawDescGZIP(), []int{61} } func (x *ConfigSnapshotRevision) GetComponent() isConfigSnapshotRevision_Component { @@ -5526,7 +5651,7 @@ type SandboxConfigRevision struct { func (x *SandboxConfigRevision) Reset() { *x = SandboxConfigRevision{} - mi := &file_openshell_proto_msgTypes[60] + mi := &file_openshell_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5538,7 +5663,7 @@ func (x *SandboxConfigRevision) String() string { func (*SandboxConfigRevision) ProtoMessage() {} func (x *SandboxConfigRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[60] + mi := &file_openshell_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5551,7 +5676,7 @@ func (x *SandboxConfigRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfigRevision.ProtoReflect.Descriptor instead. func (*SandboxConfigRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{60} + return file_openshell_proto_rawDescGZIP(), []int{62} } func (x *SandboxConfigRevision) GetConfigRevision() uint64 { @@ -5610,7 +5735,7 @@ type ConfigUpdateOperation struct { func (x *ConfigUpdateOperation) Reset() { *x = ConfigUpdateOperation{} - mi := &file_openshell_proto_msgTypes[61] + mi := &file_openshell_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5622,7 +5747,7 @@ func (x *ConfigUpdateOperation) String() string { func (*ConfigUpdateOperation) ProtoMessage() {} func (x *ConfigUpdateOperation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[61] + mi := &file_openshell_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5635,7 +5760,7 @@ func (x *ConfigUpdateOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdateOperation.ProtoReflect.Descriptor instead. func (*ConfigUpdateOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{61} + return file_openshell_proto_rawDescGZIP(), []int{63} } func (x *ConfigUpdateOperation) GetOperationId() string { @@ -5725,7 +5850,7 @@ type ProviderMutationReceipt struct { func (x *ProviderMutationReceipt) Reset() { *x = ProviderMutationReceipt{} - mi := &file_openshell_proto_msgTypes[62] + mi := &file_openshell_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5737,7 +5862,7 @@ func (x *ProviderMutationReceipt) String() string { func (*ProviderMutationReceipt) ProtoMessage() {} func (x *ProviderMutationReceipt) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[62] + mi := &file_openshell_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5750,7 +5875,7 @@ func (x *ProviderMutationReceipt) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderMutationReceipt.ProtoReflect.Descriptor instead. func (*ProviderMutationReceipt) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{62} + return file_openshell_proto_rawDescGZIP(), []int{64} } func (x *ProviderMutationReceipt) GetReceiptId() string { @@ -5826,7 +5951,7 @@ type ProviderReadinessObservation struct { func (x *ProviderReadinessObservation) Reset() { *x = ProviderReadinessObservation{} - mi := &file_openshell_proto_msgTypes[63] + mi := &file_openshell_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5838,7 +5963,7 @@ func (x *ProviderReadinessObservation) String() string { func (*ProviderReadinessObservation) ProtoMessage() {} func (x *ProviderReadinessObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[63] + mi := &file_openshell_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5851,7 +5976,7 @@ func (x *ProviderReadinessObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderReadinessObservation.ProtoReflect.Descriptor instead. func (*ProviderReadinessObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{63} + return file_openshell_proto_rawDescGZIP(), []int{65} } func (x *ProviderReadinessObservation) GetSessionId() string { @@ -5950,7 +6075,7 @@ type ProviderReadinessStatus struct { func (x *ProviderReadinessStatus) Reset() { *x = ProviderReadinessStatus{} - mi := &file_openshell_proto_msgTypes[64] + mi := &file_openshell_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5962,7 +6087,7 @@ func (x *ProviderReadinessStatus) String() string { func (*ProviderReadinessStatus) ProtoMessage() {} func (x *ProviderReadinessStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[64] + mi := &file_openshell_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5975,7 +6100,7 @@ func (x *ProviderReadinessStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderReadinessStatus.ProtoReflect.Descriptor instead. func (*ProviderReadinessStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{64} + return file_openshell_proto_rawDescGZIP(), []int{66} } func (x *ProviderReadinessStatus) GetReceipt() *ProviderMutationReceipt { @@ -6049,7 +6174,7 @@ type GetSandboxProviderStatusRequest struct { func (x *GetSandboxProviderStatusRequest) Reset() { *x = GetSandboxProviderStatusRequest{} - mi := &file_openshell_proto_msgTypes[65] + mi := &file_openshell_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6061,7 +6186,7 @@ func (x *GetSandboxProviderStatusRequest) String() string { func (*GetSandboxProviderStatusRequest) ProtoMessage() {} func (x *GetSandboxProviderStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[65] + mi := &file_openshell_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6074,7 +6199,7 @@ func (x *GetSandboxProviderStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxProviderStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxProviderStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{65} + return file_openshell_proto_rawDescGZIP(), []int{67} } func (x *GetSandboxProviderStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6114,7 +6239,7 @@ type GetSandboxProviderStatusResponse struct { func (x *GetSandboxProviderStatusResponse) Reset() { *x = GetSandboxProviderStatusResponse{} - mi := &file_openshell_proto_msgTypes[66] + mi := &file_openshell_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6126,7 +6251,7 @@ func (x *GetSandboxProviderStatusResponse) String() string { func (*GetSandboxProviderStatusResponse) ProtoMessage() {} func (x *GetSandboxProviderStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[66] + mi := &file_openshell_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6139,7 +6264,7 @@ func (x *GetSandboxProviderStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxProviderStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxProviderStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{66} + return file_openshell_proto_rawDescGZIP(), []int{68} } func (x *GetSandboxProviderStatusResponse) GetStatus() *ProviderReadinessStatus { @@ -6161,7 +6286,7 @@ type ReportProviderReadinessRequest struct { func (x *ReportProviderReadinessRequest) Reset() { *x = ReportProviderReadinessRequest{} - mi := &file_openshell_proto_msgTypes[67] + mi := &file_openshell_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6173,7 +6298,7 @@ func (x *ReportProviderReadinessRequest) String() string { func (*ReportProviderReadinessRequest) ProtoMessage() {} func (x *ReportProviderReadinessRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[67] + mi := &file_openshell_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6186,7 +6311,7 @@ func (x *ReportProviderReadinessRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportProviderReadinessRequest.ProtoReflect.Descriptor instead. func (*ReportProviderReadinessRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{67} + return file_openshell_proto_rawDescGZIP(), []int{69} } func (x *ReportProviderReadinessRequest) GetSandboxId() string { @@ -6216,7 +6341,7 @@ type ReportProviderReadinessResponse struct { func (x *ReportProviderReadinessResponse) Reset() { *x = ReportProviderReadinessResponse{} - mi := &file_openshell_proto_msgTypes[68] + mi := &file_openshell_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6228,7 +6353,7 @@ func (x *ReportProviderReadinessResponse) String() string { func (*ReportProviderReadinessResponse) ProtoMessage() {} func (x *ReportProviderReadinessResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[68] + mi := &file_openshell_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6241,7 +6366,7 @@ func (x *ReportProviderReadinessResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportProviderReadinessResponse.ProtoReflect.Descriptor instead. func (*ReportProviderReadinessResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{68} + return file_openshell_proto_rawDescGZIP(), []int{70} } func (x *ReportProviderReadinessResponse) GetAcceptedSequence() uint64 { @@ -6278,7 +6403,7 @@ type DeleteSandboxResponse struct { func (x *DeleteSandboxResponse) Reset() { *x = DeleteSandboxResponse{} - mi := &file_openshell_proto_msgTypes[69] + mi := &file_openshell_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6290,7 +6415,7 @@ func (x *DeleteSandboxResponse) String() string { func (*DeleteSandboxResponse) ProtoMessage() {} func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[69] + mi := &file_openshell_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6303,7 +6428,7 @@ func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxResponse.ProtoReflect.Descriptor instead. func (*DeleteSandboxResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{69} + return file_openshell_proto_rawDescGZIP(), []int{71} } func (x *DeleteSandboxResponse) GetOutcome() DeletionOutcome { @@ -6332,7 +6457,7 @@ type CreateSshSessionRequest struct { func (x *CreateSshSessionRequest) Reset() { *x = CreateSshSessionRequest{} - mi := &file_openshell_proto_msgTypes[70] + mi := &file_openshell_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6344,7 +6469,7 @@ func (x *CreateSshSessionRequest) String() string { func (*CreateSshSessionRequest) ProtoMessage() {} func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[70] + mi := &file_openshell_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6357,7 +6482,7 @@ func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSshSessionRequest.ProtoReflect.Descriptor instead. func (*CreateSshSessionRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{70} + return file_openshell_proto_rawDescGZIP(), []int{72} } func (x *CreateSshSessionRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6408,7 +6533,7 @@ type CreateSshSessionResponse struct { func (x *CreateSshSessionResponse) Reset() { *x = CreateSshSessionResponse{} - mi := &file_openshell_proto_msgTypes[71] + mi := &file_openshell_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6420,7 +6545,7 @@ func (x *CreateSshSessionResponse) String() string { func (*CreateSshSessionResponse) ProtoMessage() {} func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[71] + mi := &file_openshell_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6433,7 +6558,7 @@ func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSshSessionResponse.ProtoReflect.Descriptor instead. func (*CreateSshSessionResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{71} + return file_openshell_proto_rawDescGZIP(), []int{73} } func (x *CreateSshSessionResponse) GetSandboxId() string { @@ -6508,7 +6633,7 @@ type ExposeServiceRequest struct { func (x *ExposeServiceRequest) Reset() { *x = ExposeServiceRequest{} - mi := &file_openshell_proto_msgTypes[72] + mi := &file_openshell_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6520,7 +6645,7 @@ func (x *ExposeServiceRequest) String() string { func (*ExposeServiceRequest) ProtoMessage() {} func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[72] + mi := &file_openshell_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6533,7 +6658,7 @@ func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExposeServiceRequest.ProtoReflect.Descriptor instead. func (*ExposeServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{72} + return file_openshell_proto_rawDescGZIP(), []int{74} } func (x *ExposeServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6599,7 +6724,7 @@ type GetServiceRequest struct { func (x *GetServiceRequest) Reset() { *x = GetServiceRequest{} - mi := &file_openshell_proto_msgTypes[73] + mi := &file_openshell_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6611,7 +6736,7 @@ func (x *GetServiceRequest) String() string { func (*GetServiceRequest) ProtoMessage() {} func (x *GetServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[73] + mi := &file_openshell_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6624,7 +6749,7 @@ func (x *GetServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetServiceRequest.ProtoReflect.Descriptor instead. func (*GetServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{73} + return file_openshell_proto_rawDescGZIP(), []int{75} } func (x *GetServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6667,7 +6792,7 @@ type ListServicesRequest struct { func (x *ListServicesRequest) Reset() { *x = ListServicesRequest{} - mi := &file_openshell_proto_msgTypes[74] + mi := &file_openshell_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6679,7 +6804,7 @@ func (x *ListServicesRequest) String() string { func (*ListServicesRequest) ProtoMessage() {} func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[74] + mi := &file_openshell_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6692,7 +6817,7 @@ func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesRequest.ProtoReflect.Descriptor instead. func (*ListServicesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{74} + return file_openshell_proto_rawDescGZIP(), []int{76} } func (x *ListServicesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6735,7 +6860,7 @@ type ListServicesResponse struct { func (x *ListServicesResponse) Reset() { *x = ListServicesResponse{} - mi := &file_openshell_proto_msgTypes[75] + mi := &file_openshell_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6747,7 +6872,7 @@ func (x *ListServicesResponse) String() string { func (*ListServicesResponse) ProtoMessage() {} func (x *ListServicesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[75] + mi := &file_openshell_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6760,7 +6885,7 @@ func (x *ListServicesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesResponse.ProtoReflect.Descriptor instead. func (*ListServicesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{75} + return file_openshell_proto_rawDescGZIP(), []int{77} } func (x *ListServicesResponse) GetServices() []*ServiceEndpointResponse { @@ -6795,7 +6920,7 @@ type DeleteServiceRequest struct { func (x *DeleteServiceRequest) Reset() { *x = DeleteServiceRequest{} - mi := &file_openshell_proto_msgTypes[76] + mi := &file_openshell_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6807,7 +6932,7 @@ func (x *DeleteServiceRequest) String() string { func (*DeleteServiceRequest) ProtoMessage() {} func (x *DeleteServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[76] + mi := &file_openshell_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6820,7 +6945,7 @@ func (x *DeleteServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteServiceRequest.ProtoReflect.Descriptor instead. func (*DeleteServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{76} + return file_openshell_proto_rawDescGZIP(), []int{78} } func (x *DeleteServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6868,7 +6993,7 @@ type DeleteServiceResponse struct { func (x *DeleteServiceResponse) Reset() { *x = DeleteServiceResponse{} - mi := &file_openshell_proto_msgTypes[77] + mi := &file_openshell_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6880,7 +7005,7 @@ func (x *DeleteServiceResponse) String() string { func (*DeleteServiceResponse) ProtoMessage() {} func (x *DeleteServiceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[77] + mi := &file_openshell_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6893,7 +7018,7 @@ func (x *DeleteServiceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteServiceResponse.ProtoReflect.Descriptor instead. func (*DeleteServiceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{77} + return file_openshell_proto_rawDescGZIP(), []int{79} } func (x *DeleteServiceResponse) GetOutcome() DeletionOutcome { @@ -6926,7 +7051,7 @@ type ServiceEndpoint struct { func (x *ServiceEndpoint) Reset() { *x = ServiceEndpoint{} - mi := &file_openshell_proto_msgTypes[78] + mi := &file_openshell_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6938,7 +7063,7 @@ func (x *ServiceEndpoint) String() string { func (*ServiceEndpoint) ProtoMessage() {} func (x *ServiceEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[78] + mi := &file_openshell_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6951,7 +7076,7 @@ func (x *ServiceEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceEndpoint.ProtoReflect.Descriptor instead. func (*ServiceEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{78} + return file_openshell_proto_rawDescGZIP(), []int{80} } func (x *ServiceEndpoint) GetMetadata() *datamodelv1.ObjectMeta { @@ -7014,7 +7139,7 @@ type ServiceEndpointResponse struct { func (x *ServiceEndpointResponse) Reset() { *x = ServiceEndpointResponse{} - mi := &file_openshell_proto_msgTypes[79] + mi := &file_openshell_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7026,7 +7151,7 @@ func (x *ServiceEndpointResponse) String() string { func (*ServiceEndpointResponse) ProtoMessage() {} func (x *ServiceEndpointResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[79] + mi := &file_openshell_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7039,7 +7164,7 @@ func (x *ServiceEndpointResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceEndpointResponse.ProtoReflect.Descriptor instead. func (*ServiceEndpointResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{79} + return file_openshell_proto_rawDescGZIP(), []int{81} } func (x *ServiceEndpointResponse) GetEndpoint() *ServiceEndpoint { @@ -7070,7 +7195,7 @@ type RevokeSshSessionRequest struct { func (x *RevokeSshSessionRequest) Reset() { *x = RevokeSshSessionRequest{} - mi := &file_openshell_proto_msgTypes[80] + mi := &file_openshell_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7082,7 +7207,7 @@ func (x *RevokeSshSessionRequest) String() string { func (*RevokeSshSessionRequest) ProtoMessage() {} func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[80] + mi := &file_openshell_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7095,7 +7220,7 @@ func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RevokeSshSessionRequest.ProtoReflect.Descriptor instead. func (*RevokeSshSessionRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{80} + return file_openshell_proto_rawDescGZIP(), []int{82} } func (x *RevokeSshSessionRequest) GetToken() string { @@ -7122,7 +7247,7 @@ type RevokeSshSessionResponse struct { func (x *RevokeSshSessionResponse) Reset() { *x = RevokeSshSessionResponse{} - mi := &file_openshell_proto_msgTypes[81] + mi := &file_openshell_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7134,7 +7259,7 @@ func (x *RevokeSshSessionResponse) String() string { func (*RevokeSshSessionResponse) ProtoMessage() {} func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[81] + mi := &file_openshell_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7147,7 +7272,7 @@ func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RevokeSshSessionResponse.ProtoReflect.Descriptor instead. func (*RevokeSshSessionResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{81} + return file_openshell_proto_rawDescGZIP(), []int{83} } func (x *RevokeSshSessionResponse) GetOutcome() DeletionOutcome { @@ -7197,7 +7322,7 @@ type ExecSandboxRequest struct { func (x *ExecSandboxRequest) Reset() { *x = ExecSandboxRequest{} - mi := &file_openshell_proto_msgTypes[82] + mi := &file_openshell_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7209,7 +7334,7 @@ func (x *ExecSandboxRequest) String() string { func (*ExecSandboxRequest) ProtoMessage() {} func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[82] + mi := &file_openshell_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7222,7 +7347,7 @@ func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxRequest.ProtoReflect.Descriptor instead. func (*ExecSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{82} + return file_openshell_proto_rawDescGZIP(), []int{84} } func (x *ExecSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -7319,7 +7444,7 @@ type ExecSandboxStdout struct { func (x *ExecSandboxStdout) Reset() { *x = ExecSandboxStdout{} - mi := &file_openshell_proto_msgTypes[83] + mi := &file_openshell_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7331,7 +7456,7 @@ func (x *ExecSandboxStdout) String() string { func (*ExecSandboxStdout) ProtoMessage() {} func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[83] + mi := &file_openshell_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7344,7 +7469,7 @@ func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxStdout.ProtoReflect.Descriptor instead. func (*ExecSandboxStdout) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{83} + return file_openshell_proto_rawDescGZIP(), []int{85} } func (x *ExecSandboxStdout) GetData() []byte { @@ -7364,7 +7489,7 @@ type ExecSandboxStderr struct { func (x *ExecSandboxStderr) Reset() { *x = ExecSandboxStderr{} - mi := &file_openshell_proto_msgTypes[84] + mi := &file_openshell_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7376,7 +7501,7 @@ func (x *ExecSandboxStderr) String() string { func (*ExecSandboxStderr) ProtoMessage() {} func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[84] + mi := &file_openshell_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7389,7 +7514,7 @@ func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxStderr.ProtoReflect.Descriptor instead. func (*ExecSandboxStderr) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{84} + return file_openshell_proto_rawDescGZIP(), []int{86} } func (x *ExecSandboxStderr) GetData() []byte { @@ -7409,7 +7534,7 @@ type ExecSandboxExit struct { func (x *ExecSandboxExit) Reset() { *x = ExecSandboxExit{} - mi := &file_openshell_proto_msgTypes[85] + mi := &file_openshell_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7421,7 +7546,7 @@ func (x *ExecSandboxExit) String() string { func (*ExecSandboxExit) ProtoMessage() {} func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[85] + mi := &file_openshell_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7434,7 +7559,7 @@ func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxExit.ProtoReflect.Descriptor instead. func (*ExecSandboxExit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{85} + return file_openshell_proto_rawDescGZIP(), []int{87} } func (x *ExecSandboxExit) GetExitCode() int32 { @@ -7459,7 +7584,7 @@ type ExecSandboxEvent struct { func (x *ExecSandboxEvent) Reset() { *x = ExecSandboxEvent{} - mi := &file_openshell_proto_msgTypes[86] + mi := &file_openshell_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7471,7 +7596,7 @@ func (x *ExecSandboxEvent) String() string { func (*ExecSandboxEvent) ProtoMessage() {} func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[86] + mi := &file_openshell_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7484,7 +7609,7 @@ func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxEvent.ProtoReflect.Descriptor instead. func (*ExecSandboxEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{86} + return file_openshell_proto_rawDescGZIP(), []int{88} } func (x *ExecSandboxEvent) GetPayload() isExecSandboxEvent_Payload { @@ -7566,7 +7691,7 @@ type TcpForwardInit struct { func (x *TcpForwardInit) Reset() { *x = TcpForwardInit{} - mi := &file_openshell_proto_msgTypes[87] + mi := &file_openshell_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7578,7 +7703,7 @@ func (x *TcpForwardInit) String() string { func (*TcpForwardInit) ProtoMessage() {} func (x *TcpForwardInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[87] + mi := &file_openshell_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7591,7 +7716,7 @@ func (x *TcpForwardInit) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpForwardInit.ProtoReflect.Descriptor instead. func (*TcpForwardInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{87} + return file_openshell_proto_rawDescGZIP(), []int{89} } func (x *TcpForwardInit) GetSandbox() string { @@ -7677,7 +7802,7 @@ type TcpForwardFrame struct { func (x *TcpForwardFrame) Reset() { *x = TcpForwardFrame{} - mi := &file_openshell_proto_msgTypes[88] + mi := &file_openshell_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7689,7 +7814,7 @@ func (x *TcpForwardFrame) String() string { func (*TcpForwardFrame) ProtoMessage() {} func (x *TcpForwardFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[88] + mi := &file_openshell_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7702,7 +7827,7 @@ func (x *TcpForwardFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpForwardFrame.ProtoReflect.Descriptor instead. func (*TcpForwardFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{88} + return file_openshell_proto_rawDescGZIP(), []int{90} } func (x *TcpForwardFrame) GetPayload() isTcpForwardFrame_Payload { @@ -7761,7 +7886,7 @@ type ExecSandboxInput struct { func (x *ExecSandboxInput) Reset() { *x = ExecSandboxInput{} - mi := &file_openshell_proto_msgTypes[89] + mi := &file_openshell_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7773,7 +7898,7 @@ func (x *ExecSandboxInput) String() string { func (*ExecSandboxInput) ProtoMessage() {} func (x *ExecSandboxInput) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[89] + mi := &file_openshell_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7786,7 +7911,7 @@ func (x *ExecSandboxInput) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxInput.ProtoReflect.Descriptor instead. func (*ExecSandboxInput) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{89} + return file_openshell_proto_rawDescGZIP(), []int{91} } func (x *ExecSandboxInput) GetPayload() isExecSandboxInput_Payload { @@ -7859,7 +7984,7 @@ type ExecSandboxWindowResize struct { func (x *ExecSandboxWindowResize) Reset() { *x = ExecSandboxWindowResize{} - mi := &file_openshell_proto_msgTypes[90] + mi := &file_openshell_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7871,7 +7996,7 @@ func (x *ExecSandboxWindowResize) String() string { func (*ExecSandboxWindowResize) ProtoMessage() {} func (x *ExecSandboxWindowResize) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[90] + mi := &file_openshell_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7884,7 +8009,7 @@ func (x *ExecSandboxWindowResize) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxWindowResize.ProtoReflect.Descriptor instead. func (*ExecSandboxWindowResize) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{90} + return file_openshell_proto_rawDescGZIP(), []int{92} } func (x *ExecSandboxWindowResize) GetCols() uint32 { @@ -7920,7 +8045,7 @@ type SshSession struct { func (x *SshSession) Reset() { *x = SshSession{} - mi := &file_openshell_proto_msgTypes[91] + mi := &file_openshell_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7932,7 +8057,7 @@ func (x *SshSession) String() string { func (*SshSession) ProtoMessage() {} func (x *SshSession) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[91] + mi := &file_openshell_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7945,7 +8070,7 @@ func (x *SshSession) ProtoReflect() protoreflect.Message { // Deprecated: Use SshSession.ProtoReflect.Descriptor instead. func (*SshSession) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{91} + return file_openshell_proto_rawDescGZIP(), []int{93} } func (x *SshSession) GetMetadata() *datamodelv1.ObjectMeta { @@ -8034,7 +8159,7 @@ type WatchSandboxRequest struct { func (x *WatchSandboxRequest) Reset() { *x = WatchSandboxRequest{} - mi := &file_openshell_proto_msgTypes[92] + mi := &file_openshell_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8046,7 +8171,7 @@ func (x *WatchSandboxRequest) String() string { func (*WatchSandboxRequest) ProtoMessage() {} func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[92] + mi := &file_openshell_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8059,7 +8184,7 @@ func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchSandboxRequest.ProtoReflect.Descriptor instead. func (*WatchSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{92} + return file_openshell_proto_rawDescGZIP(), []int{94} } func (x *WatchSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8175,7 +8300,7 @@ type SandboxStreamEvent struct { func (x *SandboxStreamEvent) Reset() { *x = SandboxStreamEvent{} - mi := &file_openshell_proto_msgTypes[93] + mi := &file_openshell_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8187,7 +8312,7 @@ func (x *SandboxStreamEvent) String() string { func (*SandboxStreamEvent) ProtoMessage() {} func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[93] + mi := &file_openshell_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8200,7 +8325,7 @@ func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStreamEvent.ProtoReflect.Descriptor instead. func (*SandboxStreamEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{93} + return file_openshell_proto_rawDescGZIP(), []int{95} } func (x *SandboxStreamEvent) GetPayload() isSandboxStreamEvent_Payload { @@ -8322,7 +8447,7 @@ type SandboxLogLine struct { func (x *SandboxLogLine) Reset() { *x = SandboxLogLine{} - mi := &file_openshell_proto_msgTypes[94] + mi := &file_openshell_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8334,7 +8459,7 @@ func (x *SandboxLogLine) String() string { func (*SandboxLogLine) ProtoMessage() {} func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[94] + mi := &file_openshell_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8347,7 +8472,7 @@ func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxLogLine.ProtoReflect.Descriptor instead. func (*SandboxLogLine) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{94} + return file_openshell_proto_rawDescGZIP(), []int{96} } func (x *SandboxLogLine) GetSandboxId() string { @@ -8413,7 +8538,7 @@ type SandboxStreamWarning struct { func (x *SandboxStreamWarning) Reset() { *x = SandboxStreamWarning{} - mi := &file_openshell_proto_msgTypes[95] + mi := &file_openshell_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8425,7 +8550,7 @@ func (x *SandboxStreamWarning) String() string { func (*SandboxStreamWarning) ProtoMessage() {} func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[95] + mi := &file_openshell_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8438,7 +8563,7 @@ func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStreamWarning.ProtoReflect.Descriptor instead. func (*SandboxStreamWarning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{95} + return file_openshell_proto_rawDescGZIP(), []int{97} } func (x *SandboxStreamWarning) GetMessage() string { @@ -8463,7 +8588,7 @@ type CreateProviderRequest struct { func (x *CreateProviderRequest) Reset() { *x = CreateProviderRequest{} - mi := &file_openshell_proto_msgTypes[96] + mi := &file_openshell_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8475,7 +8600,7 @@ func (x *CreateProviderRequest) String() string { func (*CreateProviderRequest) ProtoMessage() {} func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[96] + mi := &file_openshell_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8488,7 +8613,7 @@ func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateProviderRequest.ProtoReflect.Descriptor instead. func (*CreateProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{96} + return file_openshell_proto_rawDescGZIP(), []int{98} } func (x *CreateProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8524,7 +8649,7 @@ type GetProviderRequest struct { func (x *GetProviderRequest) Reset() { *x = GetProviderRequest{} - mi := &file_openshell_proto_msgTypes[97] + mi := &file_openshell_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8536,7 +8661,7 @@ func (x *GetProviderRequest) String() string { func (*GetProviderRequest) ProtoMessage() {} func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[97] + mi := &file_openshell_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8549,7 +8674,7 @@ func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRequest.ProtoReflect.Descriptor instead. func (*GetProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{97} + return file_openshell_proto_rawDescGZIP(), []int{99} } func (x *GetProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8584,7 +8709,7 @@ type GetProviderCredentialsRequest struct { func (x *GetProviderCredentialsRequest) Reset() { *x = GetProviderCredentialsRequest{} - mi := &file_openshell_proto_msgTypes[98] + mi := &file_openshell_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8596,7 +8721,7 @@ func (x *GetProviderCredentialsRequest) String() string { func (*GetProviderCredentialsRequest) ProtoMessage() {} func (x *GetProviderCredentialsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[98] + mi := &file_openshell_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8609,7 +8734,7 @@ func (x *GetProviderCredentialsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderCredentialsRequest.ProtoReflect.Descriptor instead. func (*GetProviderCredentialsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{98} + return file_openshell_proto_rawDescGZIP(), []int{100} } func (x *GetProviderCredentialsRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8652,7 +8777,7 @@ type ProviderCredentialValue struct { func (x *ProviderCredentialValue) Reset() { *x = ProviderCredentialValue{} - mi := &file_openshell_proto_msgTypes[99] + mi := &file_openshell_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8664,7 +8789,7 @@ func (x *ProviderCredentialValue) String() string { func (*ProviderCredentialValue) ProtoMessage() {} func (x *ProviderCredentialValue) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[99] + mi := &file_openshell_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8677,7 +8802,7 @@ func (x *ProviderCredentialValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialValue.ProtoReflect.Descriptor instead. func (*ProviderCredentialValue) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{99} + return file_openshell_proto_rawDescGZIP(), []int{101} } func (x *ProviderCredentialValue) GetValue() string { @@ -8704,7 +8829,7 @@ type GetProviderCredentialsResponse struct { func (x *GetProviderCredentialsResponse) Reset() { *x = GetProviderCredentialsResponse{} - mi := &file_openshell_proto_msgTypes[100] + mi := &file_openshell_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8716,7 +8841,7 @@ func (x *GetProviderCredentialsResponse) String() string { func (*GetProviderCredentialsResponse) ProtoMessage() {} func (x *GetProviderCredentialsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[100] + mi := &file_openshell_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8729,7 +8854,7 @@ func (x *GetProviderCredentialsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderCredentialsResponse.ProtoReflect.Descriptor instead. func (*GetProviderCredentialsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{100} + return file_openshell_proto_rawDescGZIP(), []int{102} } func (x *GetProviderCredentialsResponse) GetCredentials() map[string]*ProviderCredentialValue { @@ -8758,7 +8883,7 @@ type ListProvidersRequest struct { func (x *ListProvidersRequest) Reset() { *x = ListProvidersRequest{} - mi := &file_openshell_proto_msgTypes[101] + mi := &file_openshell_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8770,7 +8895,7 @@ func (x *ListProvidersRequest) String() string { func (*ListProvidersRequest) ProtoMessage() {} func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[101] + mi := &file_openshell_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8783,7 +8908,7 @@ func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProvidersRequest.ProtoReflect.Descriptor instead. func (*ListProvidersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{101} + return file_openshell_proto_rawDescGZIP(), []int{103} } func (x *ListProvidersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8835,7 +8960,7 @@ type UpdateProviderRequest struct { func (x *UpdateProviderRequest) Reset() { *x = UpdateProviderRequest{} - mi := &file_openshell_proto_msgTypes[102] + mi := &file_openshell_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8847,7 +8972,7 @@ func (x *UpdateProviderRequest) String() string { func (*UpdateProviderRequest) ProtoMessage() {} func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[102] + mi := &file_openshell_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8860,7 +8985,7 @@ func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{102} + return file_openshell_proto_rawDescGZIP(), []int{104} } func (x *UpdateProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8914,7 +9039,7 @@ type DeleteProviderRequest struct { func (x *DeleteProviderRequest) Reset() { *x = DeleteProviderRequest{} - mi := &file_openshell_proto_msgTypes[103] + mi := &file_openshell_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8926,7 +9051,7 @@ func (x *DeleteProviderRequest) String() string { func (*DeleteProviderRequest) ProtoMessage() {} func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[103] + mi := &file_openshell_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8939,7 +9064,7 @@ func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{103} + return file_openshell_proto_rawDescGZIP(), []int{105} } func (x *DeleteProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8985,7 +9110,7 @@ type ProviderResponse struct { func (x *ProviderResponse) Reset() { *x = ProviderResponse{} - mi := &file_openshell_proto_msgTypes[104] + mi := &file_openshell_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8997,7 +9122,7 @@ func (x *ProviderResponse) String() string { func (*ProviderResponse) ProtoMessage() {} func (x *ProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[104] + mi := &file_openshell_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9010,7 +9135,7 @@ func (x *ProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderResponse.ProtoReflect.Descriptor instead. func (*ProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{104} + return file_openshell_proto_rawDescGZIP(), []int{106} } func (x *ProviderResponse) GetProvider() *datamodelv1.Provider { @@ -9046,7 +9171,7 @@ type ListProvidersResponse struct { func (x *ListProvidersResponse) Reset() { *x = ListProvidersResponse{} - mi := &file_openshell_proto_msgTypes[105] + mi := &file_openshell_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9058,7 +9183,7 @@ func (x *ListProvidersResponse) String() string { func (*ListProvidersResponse) ProtoMessage() {} func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[105] + mi := &file_openshell_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9071,7 +9196,7 @@ func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProvidersResponse.ProtoReflect.Descriptor instead. func (*ListProvidersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{105} + return file_openshell_proto_rawDescGZIP(), []int{107} } func (x *ListProvidersResponse) GetProviders() []*datamodelv1.Provider { @@ -9105,7 +9230,7 @@ type ListProviderProfilesRequest struct { func (x *ListProviderProfilesRequest) Reset() { *x = ListProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[106] + mi := &file_openshell_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9117,7 +9242,7 @@ func (x *ListProviderProfilesRequest) String() string { func (*ListProviderProfilesRequest) ProtoMessage() {} func (x *ListProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[106] + mi := &file_openshell_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9130,7 +9255,7 @@ func (x *ListProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ListProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{106} + return file_openshell_proto_rawDescGZIP(), []int{108} } func (x *ListProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -9166,7 +9291,7 @@ type GetProviderProfileRequest struct { func (x *GetProviderProfileRequest) Reset() { *x = GetProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[107] + mi := &file_openshell_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9178,7 +9303,7 @@ func (x *GetProviderProfileRequest) String() string { func (*GetProviderProfileRequest) ProtoMessage() {} func (x *GetProviderProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[107] + mi := &file_openshell_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9191,7 +9316,7 @@ func (x *GetProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderProfileRequest.ProtoReflect.Descriptor instead. func (*GetProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{107} + return file_openshell_proto_rawDescGZIP(), []int{109} } func (x *GetProviderProfileRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -9219,7 +9344,7 @@ type ProviderProfileImportItem struct { func (x *ProviderProfileImportItem) Reset() { *x = ProviderProfileImportItem{} - mi := &file_openshell_proto_msgTypes[108] + mi := &file_openshell_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9231,7 +9356,7 @@ func (x *ProviderProfileImportItem) String() string { func (*ProviderProfileImportItem) ProtoMessage() {} func (x *ProviderProfileImportItem) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[108] + mi := &file_openshell_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9244,7 +9369,7 @@ func (x *ProviderProfileImportItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileImportItem.ProtoReflect.Descriptor instead. func (*ProviderProfileImportItem) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{108} + return file_openshell_proto_rawDescGZIP(), []int{110} } func (x *ProviderProfileImportItem) GetProfile() *ProviderProfile { @@ -9275,7 +9400,7 @@ type ProviderProfileDiagnostic struct { func (x *ProviderProfileDiagnostic) Reset() { *x = ProviderProfileDiagnostic{} - mi := &file_openshell_proto_msgTypes[109] + mi := &file_openshell_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9287,7 +9412,7 @@ func (x *ProviderProfileDiagnostic) String() string { func (*ProviderProfileDiagnostic) ProtoMessage() {} func (x *ProviderProfileDiagnostic) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[109] + mi := &file_openshell_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9300,7 +9425,7 @@ func (x *ProviderProfileDiagnostic) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileDiagnostic.ProtoReflect.Descriptor instead. func (*ProviderProfileDiagnostic) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{109} + return file_openshell_proto_rawDescGZIP(), []int{111} } func (x *ProviderProfileDiagnostic) GetSource() string { @@ -9357,7 +9482,7 @@ type ProviderCredentialTokenGrantAudienceOverride struct { func (x *ProviderCredentialTokenGrantAudienceOverride) Reset() { *x = ProviderCredentialTokenGrantAudienceOverride{} - mi := &file_openshell_proto_msgTypes[110] + mi := &file_openshell_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9369,7 +9494,7 @@ func (x *ProviderCredentialTokenGrantAudienceOverride) String() string { func (*ProviderCredentialTokenGrantAudienceOverride) ProtoMessage() {} func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[110] + mi := &file_openshell_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9382,7 +9507,7 @@ func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protorefle // Deprecated: Use ProviderCredentialTokenGrantAudienceOverride.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrantAudienceOverride) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{110} + return file_openshell_proto_rawDescGZIP(), []int{112} } func (x *ProviderCredentialTokenGrantAudienceOverride) GetHost() string { @@ -9436,7 +9561,7 @@ type ProviderCredentialTokenGrantSubjectToken struct { func (x *ProviderCredentialTokenGrantSubjectToken) Reset() { *x = ProviderCredentialTokenGrantSubjectToken{} - mi := &file_openshell_proto_msgTypes[111] + mi := &file_openshell_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9448,7 +9573,7 @@ func (x *ProviderCredentialTokenGrantSubjectToken) String() string { func (*ProviderCredentialTokenGrantSubjectToken) ProtoMessage() {} func (x *ProviderCredentialTokenGrantSubjectToken) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[111] + mi := &file_openshell_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9461,7 +9586,7 @@ func (x *ProviderCredentialTokenGrantSubjectToken) ProtoReflect() protoreflect.M // Deprecated: Use ProviderCredentialTokenGrantSubjectToken.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrantSubjectToken) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{111} + return file_openshell_proto_rawDescGZIP(), []int{113} } func (x *ProviderCredentialTokenGrantSubjectToken) GetSource() string { @@ -9517,7 +9642,7 @@ type ProviderCredentialTokenGrant struct { func (x *ProviderCredentialTokenGrant) Reset() { *x = ProviderCredentialTokenGrant{} - mi := &file_openshell_proto_msgTypes[112] + mi := &file_openshell_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9529,7 +9654,7 @@ func (x *ProviderCredentialTokenGrant) String() string { func (*ProviderCredentialTokenGrant) ProtoMessage() {} func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[112] + mi := &file_openshell_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9542,7 +9667,7 @@ func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialTokenGrant.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrant) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{112} + return file_openshell_proto_rawDescGZIP(), []int{114} } func (x *ProviderCredentialTokenGrant) GetTokenEndpoint() string { @@ -9646,7 +9771,7 @@ type ProviderProfileCredential struct { func (x *ProviderProfileCredential) Reset() { *x = ProviderProfileCredential{} - mi := &file_openshell_proto_msgTypes[113] + mi := &file_openshell_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9658,7 +9783,7 @@ func (x *ProviderProfileCredential) String() string { func (*ProviderProfileCredential) ProtoMessage() {} func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[113] + mi := &file_openshell_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9671,7 +9796,7 @@ func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileCredential.ProtoReflect.Descriptor instead. func (*ProviderProfileCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{113} + return file_openshell_proto_rawDescGZIP(), []int{115} } func (x *ProviderProfileCredential) GetName() string { @@ -9770,7 +9895,7 @@ type ProviderCredentialRefreshMaterial struct { func (x *ProviderCredentialRefreshMaterial) Reset() { *x = ProviderCredentialRefreshMaterial{} - mi := &file_openshell_proto_msgTypes[114] + mi := &file_openshell_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9782,7 +9907,7 @@ func (x *ProviderCredentialRefreshMaterial) String() string { func (*ProviderCredentialRefreshMaterial) ProtoMessage() {} func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[114] + mi := &file_openshell_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9795,7 +9920,7 @@ func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message // Deprecated: Use ProviderCredentialRefreshMaterial.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshMaterial) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{114} + return file_openshell_proto_rawDescGZIP(), []int{116} } func (x *ProviderCredentialRefreshMaterial) GetName() string { @@ -9840,7 +9965,7 @@ type ProviderCredentialRefreshOutput struct { func (x *ProviderCredentialRefreshOutput) Reset() { *x = ProviderCredentialRefreshOutput{} - mi := &file_openshell_proto_msgTypes[115] + mi := &file_openshell_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9852,7 +9977,7 @@ func (x *ProviderCredentialRefreshOutput) String() string { func (*ProviderCredentialRefreshOutput) ProtoMessage() {} func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[115] + mi := &file_openshell_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9865,7 +9990,7 @@ func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefreshOutput.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshOutput) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{115} + return file_openshell_proto_rawDescGZIP(), []int{117} } func (x *ProviderCredentialRefreshOutput) GetOutput() string { @@ -9897,7 +10022,7 @@ type ProviderCredentialRefresh struct { func (x *ProviderCredentialRefresh) Reset() { *x = ProviderCredentialRefresh{} - mi := &file_openshell_proto_msgTypes[116] + mi := &file_openshell_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9909,7 +10034,7 @@ func (x *ProviderCredentialRefresh) String() string { func (*ProviderCredentialRefresh) ProtoMessage() {} func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[116] + mi := &file_openshell_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9922,7 +10047,7 @@ func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefresh.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefresh) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{116} + return file_openshell_proto_rawDescGZIP(), []int{118} } func (x *ProviderCredentialRefresh) GetStrategy() ProviderCredentialRefreshStrategy { @@ -10003,7 +10128,7 @@ type ProviderCredentialRefreshStatus struct { func (x *ProviderCredentialRefreshStatus) Reset() { *x = ProviderCredentialRefreshStatus{} - mi := &file_openshell_proto_msgTypes[117] + mi := &file_openshell_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10015,7 +10140,7 @@ func (x *ProviderCredentialRefreshStatus) String() string { func (*ProviderCredentialRefreshStatus) ProtoMessage() {} func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[117] + mi := &file_openshell_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10028,7 +10153,7 @@ func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefreshStatus.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{117} + return file_openshell_proto_rawDescGZIP(), []int{119} } func (x *ProviderCredentialRefreshStatus) GetProvider() string { @@ -10133,7 +10258,7 @@ type ProviderProfileDiscovery struct { func (x *ProviderProfileDiscovery) Reset() { *x = ProviderProfileDiscovery{} - mi := &file_openshell_proto_msgTypes[118] + mi := &file_openshell_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10145,7 +10270,7 @@ func (x *ProviderProfileDiscovery) String() string { func (*ProviderProfileDiscovery) ProtoMessage() {} func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[118] + mi := &file_openshell_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10158,7 +10283,7 @@ func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileDiscovery.ProtoReflect.Descriptor instead. func (*ProviderProfileDiscovery) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{118} + return file_openshell_proto_rawDescGZIP(), []int{120} } func (x *ProviderProfileDiscovery) GetCredentials() []string { @@ -10180,7 +10305,7 @@ type GetProviderRefreshStatusRequest struct { func (x *GetProviderRefreshStatusRequest) Reset() { *x = GetProviderRefreshStatusRequest{} - mi := &file_openshell_proto_msgTypes[119] + mi := &file_openshell_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10192,7 +10317,7 @@ func (x *GetProviderRefreshStatusRequest) String() string { func (*GetProviderRefreshStatusRequest) ProtoMessage() {} func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[119] + mi := &file_openshell_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10205,7 +10330,7 @@ func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRefreshStatusRequest.ProtoReflect.Descriptor instead. func (*GetProviderRefreshStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{119} + return file_openshell_proto_rawDescGZIP(), []int{121} } func (x *GetProviderRefreshStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10238,7 +10363,7 @@ type GetProviderRefreshStatusResponse struct { func (x *GetProviderRefreshStatusResponse) Reset() { *x = GetProviderRefreshStatusResponse{} - mi := &file_openshell_proto_msgTypes[120] + mi := &file_openshell_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10250,7 +10375,7 @@ func (x *GetProviderRefreshStatusResponse) String() string { func (*GetProviderRefreshStatusResponse) ProtoMessage() {} func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[120] + mi := &file_openshell_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10263,7 +10388,7 @@ func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRefreshStatusResponse.ProtoReflect.Descriptor instead. func (*GetProviderRefreshStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{120} + return file_openshell_proto_rawDescGZIP(), []int{122} } func (x *GetProviderRefreshStatusResponse) GetCredentials() []*ProviderCredentialRefreshStatus { @@ -10295,7 +10420,7 @@ type ConfigureProviderRefreshRequest struct { func (x *ConfigureProviderRefreshRequest) Reset() { *x = ConfigureProviderRefreshRequest{} - mi := &file_openshell_proto_msgTypes[121] + mi := &file_openshell_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10307,7 +10432,7 @@ func (x *ConfigureProviderRefreshRequest) String() string { func (*ConfigureProviderRefreshRequest) ProtoMessage() {} func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[121] + mi := &file_openshell_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10320,7 +10445,7 @@ func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureProviderRefreshRequest.ProtoReflect.Descriptor instead. func (*ConfigureProviderRefreshRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{121} + return file_openshell_proto_rawDescGZIP(), []int{123} } func (x *ConfigureProviderRefreshRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10388,7 +10513,7 @@ type ConfigureProviderRefreshResponse struct { func (x *ConfigureProviderRefreshResponse) Reset() { *x = ConfigureProviderRefreshResponse{} - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10400,7 +10525,7 @@ func (x *ConfigureProviderRefreshResponse) String() string { func (*ConfigureProviderRefreshResponse) ProtoMessage() {} func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10413,7 +10538,7 @@ func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureProviderRefreshResponse.ProtoReflect.Descriptor instead. func (*ConfigureProviderRefreshResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{122} + return file_openshell_proto_rawDescGZIP(), []int{124} } func (x *ConfigureProviderRefreshResponse) GetStatus() *ProviderCredentialRefreshStatus { @@ -10438,7 +10563,7 @@ type RotateProviderCredentialRequest struct { func (x *RotateProviderCredentialRequest) Reset() { *x = RotateProviderCredentialRequest{} - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10450,7 +10575,7 @@ func (x *RotateProviderCredentialRequest) String() string { func (*RotateProviderCredentialRequest) ProtoMessage() {} func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10463,7 +10588,7 @@ func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateProviderCredentialRequest.ProtoReflect.Descriptor instead. func (*RotateProviderCredentialRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{123} + return file_openshell_proto_rawDescGZIP(), []int{125} } func (x *RotateProviderCredentialRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10503,7 +10628,7 @@ type RotateProviderCredentialResponse struct { func (x *RotateProviderCredentialResponse) Reset() { *x = RotateProviderCredentialResponse{} - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10515,7 +10640,7 @@ func (x *RotateProviderCredentialResponse) String() string { func (*RotateProviderCredentialResponse) ProtoMessage() {} func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10528,7 +10653,7 @@ func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateProviderCredentialResponse.ProtoReflect.Descriptor instead. func (*RotateProviderCredentialResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{124} + return file_openshell_proto_rawDescGZIP(), []int{126} } func (x *RotateProviderCredentialResponse) GetStatus() *ProviderCredentialRefreshStatus { @@ -10554,7 +10679,7 @@ type DeleteProviderRefreshRequest struct { func (x *DeleteProviderRefreshRequest) Reset() { *x = DeleteProviderRefreshRequest{} - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10566,7 +10691,7 @@ func (x *DeleteProviderRefreshRequest) String() string { func (*DeleteProviderRefreshRequest) ProtoMessage() {} func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10579,7 +10704,7 @@ func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRefreshRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderRefreshRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{125} + return file_openshell_proto_rawDescGZIP(), []int{127} } func (x *DeleteProviderRefreshRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10626,7 +10751,7 @@ type DeleteProviderRefreshResponse struct { func (x *DeleteProviderRefreshResponse) Reset() { *x = DeleteProviderRefreshResponse{} - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10638,7 +10763,7 @@ func (x *DeleteProviderRefreshResponse) String() string { func (*DeleteProviderRefreshResponse) ProtoMessage() {} func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10651,7 +10776,7 @@ func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRefreshResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderRefreshResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{126} + return file_openshell_proto_rawDescGZIP(), []int{128} } func (x *DeleteProviderRefreshResponse) GetOutcome() DeletionOutcome { @@ -10694,7 +10819,7 @@ type ProviderProfile struct { func (x *ProviderProfile) Reset() { *x = ProviderProfile{} - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10706,7 +10831,7 @@ func (x *ProviderProfile) String() string { func (*ProviderProfile) ProtoMessage() {} func (x *ProviderProfile) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10719,7 +10844,7 @@ func (x *ProviderProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfile.ProtoReflect.Descriptor instead. func (*ProviderProfile) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{127} + return file_openshell_proto_rawDescGZIP(), []int{129} } func (x *ProviderProfile) GetId() string { @@ -10835,7 +10960,7 @@ type ProviderProfileFile struct { func (x *ProviderProfileFile) Reset() { *x = ProviderProfileFile{} - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10847,7 +10972,7 @@ func (x *ProviderProfileFile) String() string { func (*ProviderProfileFile) ProtoMessage() {} func (x *ProviderProfileFile) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10860,7 +10985,7 @@ func (x *ProviderProfileFile) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileFile.ProtoReflect.Descriptor instead. func (*ProviderProfileFile) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{128} + return file_openshell_proto_rawDescGZIP(), []int{130} } func (x *ProviderProfileFile) GetPath() string { @@ -10894,7 +11019,7 @@ type ProviderProfileResponse struct { func (x *ProviderProfileResponse) Reset() { *x = ProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10906,7 +11031,7 @@ func (x *ProviderProfileResponse) String() string { func (*ProviderProfileResponse) ProtoMessage() {} func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[131] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10919,7 +11044,7 @@ func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileResponse.ProtoReflect.Descriptor instead. func (*ProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{129} + return file_openshell_proto_rawDescGZIP(), []int{131} } func (x *ProviderProfileResponse) GetProfile() *ProviderProfile { @@ -10941,7 +11066,7 @@ type ListProviderProfilesResponse struct { func (x *ListProviderProfilesResponse) Reset() { *x = ListProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10953,7 +11078,7 @@ func (x *ListProviderProfilesResponse) String() string { func (*ListProviderProfilesResponse) ProtoMessage() {} func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10966,7 +11091,7 @@ func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ListProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{130} + return file_openshell_proto_rawDescGZIP(), []int{132} } func (x *ListProviderProfilesResponse) GetProfiles() []*ProviderProfile { @@ -10998,7 +11123,7 @@ type ImportProviderProfilesRequest struct { func (x *ImportProviderProfilesRequest) Reset() { *x = ImportProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11010,7 +11135,7 @@ func (x *ImportProviderProfilesRequest) String() string { func (*ImportProviderProfilesRequest) ProtoMessage() {} func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11023,7 +11148,7 @@ func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{131} + return file_openshell_proto_rawDescGZIP(), []int{133} } func (x *ImportProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11059,7 +11184,7 @@ type ImportProviderProfilesResponse struct { func (x *ImportProviderProfilesResponse) Reset() { *x = ImportProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11071,7 +11196,7 @@ func (x *ImportProviderProfilesResponse) String() string { func (*ImportProviderProfilesResponse) ProtoMessage() {} func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[134] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11084,7 +11209,7 @@ func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{132} + return file_openshell_proto_rawDescGZIP(), []int{134} } func (x *ImportProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11130,7 +11255,7 @@ type UpdateProviderProfilesRequest struct { func (x *UpdateProviderProfilesRequest) Reset() { *x = UpdateProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11142,7 +11267,7 @@ func (x *UpdateProviderProfilesRequest) String() string { func (*UpdateProviderProfilesRequest) ProtoMessage() {} func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[135] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11155,7 +11280,7 @@ func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{133} + return file_openshell_proto_rawDescGZIP(), []int{135} } func (x *UpdateProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11205,7 +11330,7 @@ type UpdateProviderProfilesResponse struct { func (x *UpdateProviderProfilesResponse) Reset() { *x = UpdateProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11217,7 +11342,7 @@ func (x *UpdateProviderProfilesResponse) String() string { func (*UpdateProviderProfilesResponse) ProtoMessage() {} func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[136] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11230,7 +11355,7 @@ func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{134} + return file_openshell_proto_rawDescGZIP(), []int{136} } func (x *UpdateProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11266,7 +11391,7 @@ type LintProviderProfilesRequest struct { func (x *LintProviderProfilesRequest) Reset() { *x = LintProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11278,7 +11403,7 @@ func (x *LintProviderProfilesRequest) String() string { func (*LintProviderProfilesRequest) ProtoMessage() {} func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[137] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11291,7 +11416,7 @@ func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*LintProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{135} + return file_openshell_proto_rawDescGZIP(), []int{137} } func (x *LintProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11322,7 +11447,7 @@ type LintProviderProfilesResponse struct { func (x *LintProviderProfilesResponse) Reset() { *x = LintProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11334,7 +11459,7 @@ func (x *LintProviderProfilesResponse) String() string { func (*LintProviderProfilesResponse) ProtoMessage() {} func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[138] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11347,7 +11472,7 @@ func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*LintProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{136} + return file_openshell_proto_rawDescGZIP(), []int{138} } func (x *LintProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11381,7 +11506,7 @@ type DeleteProviderResponse struct { func (x *DeleteProviderResponse) Reset() { *x = DeleteProviderResponse{} - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11393,7 +11518,7 @@ func (x *DeleteProviderResponse) String() string { func (*DeleteProviderResponse) ProtoMessage() {} func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[139] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11406,7 +11531,7 @@ func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{137} + return file_openshell_proto_rawDescGZIP(), []int{139} } func (x *DeleteProviderResponse) GetOutcome() DeletionOutcome { @@ -11432,7 +11557,7 @@ type DeleteProviderProfileRequest struct { func (x *DeleteProviderProfileRequest) Reset() { *x = DeleteProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[140] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11444,7 +11569,7 @@ func (x *DeleteProviderProfileRequest) String() string { func (*DeleteProviderProfileRequest) ProtoMessage() {} func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[140] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11457,7 +11582,7 @@ func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{138} + return file_openshell_proto_rawDescGZIP(), []int{140} } func (x *DeleteProviderProfileRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11498,7 +11623,7 @@ type DeleteProviderProfileResponse struct { func (x *DeleteProviderProfileResponse) Reset() { *x = DeleteProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11510,7 +11635,7 @@ func (x *DeleteProviderProfileResponse) String() string { func (*DeleteProviderProfileResponse) ProtoMessage() {} func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[141] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11523,7 +11648,7 @@ func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{139} + return file_openshell_proto_rawDescGZIP(), []int{141} } func (x *DeleteProviderProfileResponse) GetOutcome() DeletionOutcome { @@ -11552,7 +11677,7 @@ type GetSandboxProviderEnvironmentRequest struct { func (x *GetSandboxProviderEnvironmentRequest) Reset() { *x = GetSandboxProviderEnvironmentRequest{} - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[142] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11564,7 +11689,7 @@ func (x *GetSandboxProviderEnvironmentRequest) String() string { func (*GetSandboxProviderEnvironmentRequest) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[142] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11577,7 +11702,7 @@ func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Messa // Deprecated: Use GetSandboxProviderEnvironmentRequest.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{140} + return file_openshell_proto_rawDescGZIP(), []int{142} } func (x *GetSandboxProviderEnvironmentRequest) GetSandboxId() string { @@ -11613,7 +11738,7 @@ type StaticCredentialEndpointBinding struct { func (x *StaticCredentialEndpointBinding) Reset() { *x = StaticCredentialEndpointBinding{} - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[143] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11625,7 +11750,7 @@ func (x *StaticCredentialEndpointBinding) String() string { func (*StaticCredentialEndpointBinding) ProtoMessage() {} func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[143] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11638,7 +11763,7 @@ func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialEndpointBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialEndpointBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{141} + return file_openshell_proto_rawDescGZIP(), []int{143} } func (x *StaticCredentialEndpointBinding) GetHost() string { @@ -11682,7 +11807,7 @@ type StaticCredentialBinding struct { func (x *StaticCredentialBinding) Reset() { *x = StaticCredentialBinding{} - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[144] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11694,7 +11819,7 @@ func (x *StaticCredentialBinding) String() string { func (*StaticCredentialBinding) ProtoMessage() {} func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[144] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11707,7 +11832,7 @@ func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{142} + return file_openshell_proto_rawDescGZIP(), []int{144} } func (x *StaticCredentialBinding) GetEndpoints() []*StaticCredentialEndpointBinding { @@ -11777,7 +11902,7 @@ type GetSandboxProviderEnvironmentResponse struct { func (x *GetSandboxProviderEnvironmentResponse) Reset() { *x = GetSandboxProviderEnvironmentResponse{} - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11789,7 +11914,7 @@ func (x *GetSandboxProviderEnvironmentResponse) String() string { func (*GetSandboxProviderEnvironmentResponse) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[145] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11802,7 +11927,7 @@ func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Mess // Deprecated: Use GetSandboxProviderEnvironmentResponse.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{143} + return file_openshell_proto_rawDescGZIP(), []int{145} } func (x *GetSandboxProviderEnvironmentResponse) GetEnvironment() map[string]string { @@ -11911,7 +12036,7 @@ type ProviderEnvironmentValue struct { func (x *ProviderEnvironmentValue) Reset() { *x = ProviderEnvironmentValue{} - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11923,7 +12048,7 @@ func (x *ProviderEnvironmentValue) String() string { func (*ProviderEnvironmentValue) ProtoMessage() {} func (x *ProviderEnvironmentValue) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[146] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11936,7 +12061,7 @@ func (x *ProviderEnvironmentValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderEnvironmentValue.ProtoReflect.Descriptor instead. func (*ProviderEnvironmentValue) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{144} + return file_openshell_proto_rawDescGZIP(), []int{146} } func (x *ProviderEnvironmentValue) GetName() string { @@ -12002,7 +12127,7 @@ type ProviderEnvironmentSnapshot struct { func (x *ProviderEnvironmentSnapshot) Reset() { *x = ProviderEnvironmentSnapshot{} - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[147] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12014,7 +12139,7 @@ func (x *ProviderEnvironmentSnapshot) String() string { func (*ProviderEnvironmentSnapshot) ProtoMessage() {} func (x *ProviderEnvironmentSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[147] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12027,7 +12152,7 @@ func (x *ProviderEnvironmentSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderEnvironmentSnapshot.ProtoReflect.Descriptor instead. func (*ProviderEnvironmentSnapshot) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{145} + return file_openshell_proto_rawDescGZIP(), []int{147} } func (x *ProviderEnvironmentSnapshot) GetProviderEnvRevision() uint64 { @@ -12096,7 +12221,7 @@ type ExchangeProviderSubjectTokenRequest struct { func (x *ExchangeProviderSubjectTokenRequest) Reset() { *x = ExchangeProviderSubjectTokenRequest{} - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12108,7 +12233,7 @@ func (x *ExchangeProviderSubjectTokenRequest) String() string { func (*ExchangeProviderSubjectTokenRequest) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[148] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12121,7 +12246,7 @@ func (x *ExchangeProviderSubjectTokenRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use ExchangeProviderSubjectTokenRequest.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{146} + return file_openshell_proto_rawDescGZIP(), []int{148} } func (x *ExchangeProviderSubjectTokenRequest) GetSandboxId() string { @@ -12163,7 +12288,7 @@ type ExchangeProviderSubjectTokenResponse struct { func (x *ExchangeProviderSubjectTokenResponse) Reset() { *x = ExchangeProviderSubjectTokenResponse{} - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12175,7 +12300,7 @@ func (x *ExchangeProviderSubjectTokenResponse) String() string { func (*ExchangeProviderSubjectTokenResponse) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[149] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12188,7 +12313,7 @@ func (x *ExchangeProviderSubjectTokenResponse) ProtoReflect() protoreflect.Messa // Deprecated: Use ExchangeProviderSubjectTokenResponse.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{147} + return file_openshell_proto_rawDescGZIP(), []int{149} } func (x *ExchangeProviderSubjectTokenResponse) GetAccessToken() string { @@ -12262,7 +12387,7 @@ type UpdateConfigRequest struct { func (x *UpdateConfigRequest) Reset() { *x = UpdateConfigRequest{} - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12274,7 +12399,7 @@ func (x *UpdateConfigRequest) String() string { func (*UpdateConfigRequest) ProtoMessage() {} func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[150] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12287,7 +12412,7 @@ func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigRequest.ProtoReflect.Descriptor instead. func (*UpdateConfigRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{148} + return file_openshell_proto_rawDescGZIP(), []int{150} } func (x *UpdateConfigRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -12384,7 +12509,7 @@ type PolicyMergeOperation struct { func (x *PolicyMergeOperation) Reset() { *x = PolicyMergeOperation{} - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12396,7 +12521,7 @@ func (x *PolicyMergeOperation) String() string { func (*PolicyMergeOperation) ProtoMessage() {} func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[151] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12409,7 +12534,7 @@ func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyMergeOperation.ProtoReflect.Descriptor instead. func (*PolicyMergeOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{149} + return file_openshell_proto_rawDescGZIP(), []int{151} } func (x *PolicyMergeOperation) GetOperation() isPolicyMergeOperation_Operation { @@ -12523,7 +12648,7 @@ type AddNetworkRule struct { func (x *AddNetworkRule) Reset() { *x = AddNetworkRule{} - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12535,7 +12660,7 @@ func (x *AddNetworkRule) String() string { func (*AddNetworkRule) ProtoMessage() {} func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[152] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12548,7 +12673,7 @@ func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use AddNetworkRule.ProtoReflect.Descriptor instead. func (*AddNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{150} + return file_openshell_proto_rawDescGZIP(), []int{152} } func (x *AddNetworkRule) GetRuleName() string { @@ -12576,7 +12701,7 @@ type RemoveNetworkEndpoint struct { func (x *RemoveNetworkEndpoint) Reset() { *x = RemoveNetworkEndpoint{} - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12588,7 +12713,7 @@ func (x *RemoveNetworkEndpoint) String() string { func (*RemoveNetworkEndpoint) ProtoMessage() {} func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[153] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12601,7 +12726,7 @@ func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkEndpoint.ProtoReflect.Descriptor instead. func (*RemoveNetworkEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{151} + return file_openshell_proto_rawDescGZIP(), []int{153} } func (x *RemoveNetworkEndpoint) GetRuleName() string { @@ -12634,7 +12759,7 @@ type RemoveNetworkRule struct { func (x *RemoveNetworkRule) Reset() { *x = RemoveNetworkRule{} - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[154] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12646,7 +12771,7 @@ func (x *RemoveNetworkRule) String() string { func (*RemoveNetworkRule) ProtoMessage() {} func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[154] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12659,7 +12784,7 @@ func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkRule.ProtoReflect.Descriptor instead. func (*RemoveNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{152} + return file_openshell_proto_rawDescGZIP(), []int{154} } func (x *RemoveNetworkRule) GetRuleName() string { @@ -12688,7 +12813,7 @@ type L7RuleTarget struct { func (x *L7RuleTarget) Reset() { *x = L7RuleTarget{} - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[155] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12700,7 +12825,7 @@ func (x *L7RuleTarget) String() string { func (*L7RuleTarget) ProtoMessage() {} func (x *L7RuleTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[155] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12713,7 +12838,7 @@ func (x *L7RuleTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RuleTarget.ProtoReflect.Descriptor instead. func (*L7RuleTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{153} + return file_openshell_proto_rawDescGZIP(), []int{155} } func (x *L7RuleTarget) GetRuleName() string { @@ -12768,7 +12893,7 @@ type AddDenyRules struct { func (x *AddDenyRules) Reset() { *x = AddDenyRules{} - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[156] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12780,7 +12905,7 @@ func (x *AddDenyRules) String() string { func (*AddDenyRules) ProtoMessage() {} func (x *AddDenyRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[156] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12793,7 +12918,7 @@ func (x *AddDenyRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddDenyRules.ProtoReflect.Descriptor instead. func (*AddDenyRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{154} + return file_openshell_proto_rawDescGZIP(), []int{156} } func (x *AddDenyRules) GetDenyRules() []*sandboxv1.L7DenyRule { @@ -12820,7 +12945,7 @@ type AddAllowRules struct { func (x *AddAllowRules) Reset() { *x = AddAllowRules{} - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[157] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12832,7 +12957,7 @@ func (x *AddAllowRules) String() string { func (*AddAllowRules) ProtoMessage() {} func (x *AddAllowRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[157] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12845,7 +12970,7 @@ func (x *AddAllowRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAllowRules.ProtoReflect.Descriptor instead. func (*AddAllowRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{155} + return file_openshell_proto_rawDescGZIP(), []int{157} } func (x *AddAllowRules) GetRules() []*sandboxv1.L7Rule { @@ -12872,7 +12997,7 @@ type RemoveNetworkBinary struct { func (x *RemoveNetworkBinary) Reset() { *x = RemoveNetworkBinary{} - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[158] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12884,7 +13009,7 @@ func (x *RemoveNetworkBinary) String() string { func (*RemoveNetworkBinary) ProtoMessage() {} func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[158] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12897,7 +13022,7 @@ func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkBinary.ProtoReflect.Descriptor instead. func (*RemoveNetworkBinary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{156} + return file_openshell_proto_rawDescGZIP(), []int{158} } func (x *RemoveNetworkBinary) GetRuleName() string { @@ -12933,7 +13058,7 @@ type UpdateConfigResponse struct { func (x *UpdateConfigResponse) Reset() { *x = UpdateConfigResponse{} - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[159] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12945,7 +13070,7 @@ func (x *UpdateConfigResponse) String() string { func (*UpdateConfigResponse) ProtoMessage() {} func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[159] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12958,7 +13083,7 @@ func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigResponse.ProtoReflect.Descriptor instead. func (*UpdateConfigResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{157} + return file_openshell_proto_rawDescGZIP(), []int{159} } func (x *UpdateConfigResponse) GetVersion() uint32 { @@ -13012,7 +13137,7 @@ type GetSandboxPolicyStatusRequest struct { func (x *GetSandboxPolicyStatusRequest) Reset() { *x = GetSandboxPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[160] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13024,7 +13149,7 @@ func (x *GetSandboxPolicyStatusRequest) String() string { func (*GetSandboxPolicyStatusRequest) ProtoMessage() {} func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[160] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13037,7 +13162,7 @@ func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{158} + return file_openshell_proto_rawDescGZIP(), []int{160} } func (x *GetSandboxPolicyStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -13081,7 +13206,7 @@ type GetSandboxPolicyStatusResponse struct { func (x *GetSandboxPolicyStatusResponse) Reset() { *x = GetSandboxPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[161] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13093,7 +13218,7 @@ func (x *GetSandboxPolicyStatusResponse) String() string { func (*GetSandboxPolicyStatusResponse) ProtoMessage() {} func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[161] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13106,7 +13231,7 @@ func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{159} + return file_openshell_proto_rawDescGZIP(), []int{161} } func (x *GetSandboxPolicyStatusResponse) GetRevision() *SandboxPolicyRevision { @@ -13143,7 +13268,7 @@ type ListSandboxPoliciesRequest struct { func (x *ListSandboxPoliciesRequest) Reset() { *x = ListSandboxPoliciesRequest{} - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[162] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13155,7 +13280,7 @@ func (x *ListSandboxPoliciesRequest) String() string { func (*ListSandboxPoliciesRequest) ProtoMessage() {} func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[162] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13168,7 +13293,7 @@ func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{160} + return file_openshell_proto_rawDescGZIP(), []int{162} } func (x *ListSandboxPoliciesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -13220,7 +13345,7 @@ type ListSandboxPoliciesResponse struct { func (x *ListSandboxPoliciesResponse) Reset() { *x = ListSandboxPoliciesResponse{} - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[163] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13232,7 +13357,7 @@ func (x *ListSandboxPoliciesResponse) String() string { func (*ListSandboxPoliciesResponse) ProtoMessage() {} func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[163] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13245,7 +13370,7 @@ func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{161} + return file_openshell_proto_rawDescGZIP(), []int{163} } func (x *ListSandboxPoliciesResponse) GetRevisions() []*SandboxPolicyRevision { @@ -13279,7 +13404,7 @@ type ReportPolicyStatusRequest struct { func (x *ReportPolicyStatusRequest) Reset() { *x = ReportPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[164] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13291,7 +13416,7 @@ func (x *ReportPolicyStatusRequest) String() string { func (*ReportPolicyStatusRequest) ProtoMessage() {} func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[164] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13304,7 +13429,7 @@ func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{162} + return file_openshell_proto_rawDescGZIP(), []int{164} } func (x *ReportPolicyStatusRequest) GetSandboxId() string { @@ -13344,7 +13469,7 @@ type ReportPolicyStatusResponse struct { func (x *ReportPolicyStatusResponse) Reset() { *x = ReportPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[165] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13356,7 +13481,7 @@ func (x *ReportPolicyStatusResponse) String() string { func (*ReportPolicyStatusResponse) ProtoMessage() {} func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[165] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13369,7 +13494,7 @@ func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{163} + return file_openshell_proto_rawDescGZIP(), []int{165} } type SandboxConfigurationAdmission struct { @@ -13387,7 +13512,7 @@ type SandboxConfigurationAdmission struct { func (x *SandboxConfigurationAdmission) Reset() { *x = SandboxConfigurationAdmission{} - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[166] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13399,7 +13524,7 @@ func (x *SandboxConfigurationAdmission) String() string { func (*SandboxConfigurationAdmission) ProtoMessage() {} func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[166] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13412,7 +13537,7 @@ func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfigurationAdmission.ProtoReflect.Descriptor instead. func (*SandboxConfigurationAdmission) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{164} + return file_openshell_proto_rawDescGZIP(), []int{166} } func (x *SandboxConfigurationAdmission) GetInstanceId() string { @@ -13476,7 +13601,7 @@ type ReportSandboxConfigurationRequest struct { func (x *ReportSandboxConfigurationRequest) Reset() { *x = ReportSandboxConfigurationRequest{} - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[167] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13488,7 +13613,7 @@ func (x *ReportSandboxConfigurationRequest) String() string { func (*ReportSandboxConfigurationRequest) ProtoMessage() {} func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[167] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13501,7 +13626,7 @@ func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ReportSandboxConfigurationRequest.ProtoReflect.Descriptor instead. func (*ReportSandboxConfigurationRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{165} + return file_openshell_proto_rawDescGZIP(), []int{167} } func (x *ReportSandboxConfigurationRequest) GetSandboxId() string { @@ -13533,7 +13658,7 @@ type ReportSandboxConfigurationResponse struct { func (x *ReportSandboxConfigurationResponse) Reset() { *x = ReportSandboxConfigurationResponse{} - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[168] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13545,7 +13670,7 @@ func (x *ReportSandboxConfigurationResponse) String() string { func (*ReportSandboxConfigurationResponse) ProtoMessage() {} func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[168] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13558,7 +13683,7 @@ func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ReportSandboxConfigurationResponse.ProtoReflect.Descriptor instead. func (*ReportSandboxConfigurationResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{166} + return file_openshell_proto_rawDescGZIP(), []int{168} } // A versioned policy revision with metadata. @@ -13591,7 +13716,7 @@ type SandboxPolicyRevision struct { func (x *SandboxPolicyRevision) Reset() { *x = SandboxPolicyRevision{} - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[169] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13603,7 +13728,7 @@ func (x *SandboxPolicyRevision) String() string { func (*SandboxPolicyRevision) ProtoMessage() {} func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[169] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13616,7 +13741,7 @@ func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxPolicyRevision.ProtoReflect.Descriptor instead. func (*SandboxPolicyRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{167} + return file_openshell_proto_rawDescGZIP(), []int{169} } func (x *SandboxPolicyRevision) GetVersion() uint32 { @@ -13696,7 +13821,7 @@ type GetSandboxLogsRequest struct { func (x *GetSandboxLogsRequest) Reset() { *x = GetSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[170] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13708,7 +13833,7 @@ func (x *GetSandboxLogsRequest) String() string { func (*GetSandboxLogsRequest) ProtoMessage() {} func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[170] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13721,7 +13846,7 @@ func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*GetSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{168} + return file_openshell_proto_rawDescGZIP(), []int{170} } func (x *GetSandboxLogsRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -13779,7 +13904,7 @@ type PushSandboxLogsRequest struct { func (x *PushSandboxLogsRequest) Reset() { *x = PushSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[171] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13791,7 +13916,7 @@ func (x *PushSandboxLogsRequest) String() string { func (*PushSandboxLogsRequest) ProtoMessage() {} func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[171] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13804,7 +13929,7 @@ func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*PushSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{169} + return file_openshell_proto_rawDescGZIP(), []int{171} } func (x *PushSandboxLogsRequest) GetSandboxId() string { @@ -13830,7 +13955,7 @@ type PushSandboxLogsResponse struct { func (x *PushSandboxLogsResponse) Reset() { *x = PushSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[172] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13842,7 +13967,7 @@ func (x *PushSandboxLogsResponse) String() string { func (*PushSandboxLogsResponse) ProtoMessage() {} func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[172] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13855,7 +13980,7 @@ func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*PushSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{170} + return file_openshell_proto_rawDescGZIP(), []int{172} } // Get sandbox logs response. @@ -13871,7 +13996,7 @@ type GetSandboxLogsResponse struct { func (x *GetSandboxLogsResponse) Reset() { *x = GetSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[173] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13883,7 +14008,7 @@ func (x *GetSandboxLogsResponse) String() string { func (*GetSandboxLogsResponse) ProtoMessage() {} func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[173] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13896,7 +14021,7 @@ func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*GetSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{171} + return file_openshell_proto_rawDescGZIP(), []int{173} } func (x *GetSandboxLogsResponse) GetLogs() []*SandboxLogLine { @@ -13930,7 +14055,7 @@ type SupervisorMessage struct { func (x *SupervisorMessage) Reset() { *x = SupervisorMessage{} - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[174] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13942,7 +14067,7 @@ func (x *SupervisorMessage) String() string { func (*SupervisorMessage) ProtoMessage() {} func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[174] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13955,7 +14080,7 @@ func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMessage.ProtoReflect.Descriptor instead. func (*SupervisorMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{172} + return file_openshell_proto_rawDescGZIP(), []int{174} } func (x *SupervisorMessage) GetPayload() isSupervisorMessage_Payload { @@ -14063,7 +14188,7 @@ type GatewayMessage struct { func (x *GatewayMessage) Reset() { *x = GatewayMessage{} - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[175] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14075,7 +14200,7 @@ func (x *GatewayMessage) String() string { func (*GatewayMessage) ProtoMessage() {} func (x *GatewayMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[175] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14088,7 +14213,7 @@ func (x *GatewayMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayMessage.ProtoReflect.Descriptor instead. func (*GatewayMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{173} + return file_openshell_proto_rawDescGZIP(), []int{175} } func (x *GatewayMessage) GetPayload() isGatewayMessage_Payload { @@ -14238,7 +14363,7 @@ type SupervisorHello struct { func (x *SupervisorHello) Reset() { *x = SupervisorHello{} - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[176] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14250,7 +14375,7 @@ func (x *SupervisorHello) String() string { func (*SupervisorHello) ProtoMessage() {} func (x *SupervisorHello) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[176] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14263,7 +14388,7 @@ func (x *SupervisorHello) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHello.ProtoReflect.Descriptor instead. func (*SupervisorHello) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{174} + return file_openshell_proto_rawDescGZIP(), []int{176} } func (x *SupervisorHello) GetSandboxId() string { @@ -14336,7 +14461,7 @@ type SessionAccepted struct { func (x *SessionAccepted) Reset() { *x = SessionAccepted{} - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[177] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14348,7 +14473,7 @@ func (x *SessionAccepted) String() string { func (*SessionAccepted) ProtoMessage() {} func (x *SessionAccepted) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[177] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14361,7 +14486,7 @@ func (x *SessionAccepted) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionAccepted.ProtoReflect.Descriptor instead. func (*SessionAccepted) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{175} + return file_openshell_proto_rawDescGZIP(), []int{177} } func (x *SessionAccepted) GetSessionId() string { @@ -14410,7 +14535,7 @@ type ConfigUpdate struct { func (x *ConfigUpdate) Reset() { *x = ConfigUpdate{} - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[178] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14422,7 +14547,7 @@ func (x *ConfigUpdate) String() string { func (*ConfigUpdate) ProtoMessage() {} func (x *ConfigUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[178] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14435,7 +14560,7 @@ func (x *ConfigUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdate.ProtoReflect.Descriptor instead. func (*ConfigUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{176} + return file_openshell_proto_rawDescGZIP(), []int{178} } func (x *ConfigUpdate) GetUpdateId() string { @@ -14472,7 +14597,7 @@ type ConfigApplyFailure struct { func (x *ConfigApplyFailure) Reset() { *x = ConfigApplyFailure{} - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[179] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14484,7 +14609,7 @@ func (x *ConfigApplyFailure) String() string { func (*ConfigApplyFailure) ProtoMessage() {} func (x *ConfigApplyFailure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[179] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14497,7 +14622,7 @@ func (x *ConfigApplyFailure) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigApplyFailure.ProtoReflect.Descriptor instead. func (*ConfigApplyFailure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{177} + return file_openshell_proto_rawDescGZIP(), []int{179} } func (x *ConfigApplyFailure) GetCode() string { @@ -14541,7 +14666,7 @@ type ConfigUpdateResult struct { func (x *ConfigUpdateResult) Reset() { *x = ConfigUpdateResult{} - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[180] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14553,7 +14678,7 @@ func (x *ConfigUpdateResult) String() string { func (*ConfigUpdateResult) ProtoMessage() {} func (x *ConfigUpdateResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[180] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14566,7 +14691,7 @@ func (x *ConfigUpdateResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdateResult.ProtoReflect.Descriptor instead. func (*ConfigUpdateResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{178} + return file_openshell_proto_rawDescGZIP(), []int{180} } func (x *ConfigUpdateResult) GetUpdateId() string { @@ -14617,7 +14742,7 @@ type PolicyLoadResult struct { func (x *PolicyLoadResult) Reset() { *x = PolicyLoadResult{} - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[181] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14629,7 +14754,7 @@ func (x *PolicyLoadResult) String() string { func (*PolicyLoadResult) ProtoMessage() {} func (x *PolicyLoadResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[181] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14642,7 +14767,7 @@ func (x *PolicyLoadResult) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyLoadResult.ProtoReflect.Descriptor instead. func (*PolicyLoadResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{179} + return file_openshell_proto_rawDescGZIP(), []int{181} } func (x *PolicyLoadResult) GetVersion() uint32 { @@ -14677,7 +14802,7 @@ type SessionRejected struct { func (x *SessionRejected) Reset() { *x = SessionRejected{} - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[182] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14689,7 +14814,7 @@ func (x *SessionRejected) String() string { func (*SessionRejected) ProtoMessage() {} func (x *SessionRejected) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[182] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14702,7 +14827,7 @@ func (x *SessionRejected) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRejected.ProtoReflect.Descriptor instead. func (*SessionRejected) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{180} + return file_openshell_proto_rawDescGZIP(), []int{182} } func (x *SessionRejected) GetReason() string { @@ -14731,7 +14856,7 @@ type SessionRedirect struct { func (x *SessionRedirect) Reset() { *x = SessionRedirect{} - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[183] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14743,7 +14868,7 @@ func (x *SessionRedirect) String() string { func (*SessionRedirect) ProtoMessage() {} func (x *SessionRedirect) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[183] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14756,7 +14881,7 @@ func (x *SessionRedirect) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRedirect.ProtoReflect.Descriptor instead. func (*SessionRedirect) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{181} + return file_openshell_proto_rawDescGZIP(), []int{183} } func (x *SessionRedirect) GetPeerEndpoint() string { @@ -14782,7 +14907,7 @@ type SupervisorHeartbeat struct { func (x *SupervisorHeartbeat) Reset() { *x = SupervisorHeartbeat{} - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[184] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14794,7 +14919,7 @@ func (x *SupervisorHeartbeat) String() string { func (*SupervisorHeartbeat) ProtoMessage() {} func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[184] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14807,7 +14932,7 @@ func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHeartbeat.ProtoReflect.Descriptor instead. func (*SupervisorHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{182} + return file_openshell_proto_rawDescGZIP(), []int{184} } // Gateway heartbeat. @@ -14819,7 +14944,7 @@ type GatewayHeartbeat struct { func (x *GatewayHeartbeat) Reset() { *x = GatewayHeartbeat{} - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[185] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14831,7 +14956,7 @@ func (x *GatewayHeartbeat) String() string { func (*GatewayHeartbeat) ProtoMessage() {} func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[185] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14844,7 +14969,7 @@ func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayHeartbeat.ProtoReflect.Descriptor instead. func (*GatewayHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{183} + return file_openshell_proto_rawDescGZIP(), []int{185} } // Terminal result reported before the supervisor shuts down. A successful RPC @@ -14861,7 +14986,7 @@ type ReportMainProcessExitRequest struct { func (x *ReportMainProcessExitRequest) Reset() { *x = ReportMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[186] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14873,7 +14998,7 @@ func (x *ReportMainProcessExitRequest) String() string { func (*ReportMainProcessExitRequest) ProtoMessage() {} func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[186] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14886,7 +15011,7 @@ func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{184} + return file_openshell_proto_rawDescGZIP(), []int{186} } func (x *ReportMainProcessExitRequest) GetSandboxId() string { @@ -14918,7 +15043,7 @@ type ReportMainProcessExitResponse struct { func (x *ReportMainProcessExitResponse) Reset() { *x = ReportMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[187] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14930,7 +15055,7 @@ func (x *ReportMainProcessExitResponse) String() string { func (*ReportMainProcessExitResponse) ProtoMessage() {} func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[187] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14943,7 +15068,7 @@ func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{185} + return file_openshell_proto_rawDescGZIP(), []int{187} } // Terminal-delivery completion reported after all expected foreground SSH @@ -14958,7 +15083,7 @@ type FinalizeMainProcessExitRequest struct { func (x *FinalizeMainProcessExitRequest) Reset() { *x = FinalizeMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[188] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14970,7 +15095,7 @@ func (x *FinalizeMainProcessExitRequest) String() string { func (*FinalizeMainProcessExitRequest) ProtoMessage() {} func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[188] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14983,7 +15108,7 @@ func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{186} + return file_openshell_proto_rawDescGZIP(), []int{188} } func (x *FinalizeMainProcessExitRequest) GetSandboxId() string { @@ -15008,7 +15133,7 @@ type FinalizeMainProcessExitResponse struct { func (x *FinalizeMainProcessExitResponse) Reset() { *x = FinalizeMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[189] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15020,7 +15145,7 @@ func (x *FinalizeMainProcessExitResponse) String() string { func (*FinalizeMainProcessExitResponse) ProtoMessage() {} func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[189] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15033,7 +15158,7 @@ func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{187} + return file_openshell_proto_rawDescGZIP(), []int{189} } // Gateway requests the supervisor to open a relay channel. @@ -15062,7 +15187,7 @@ type RelayOpen struct { func (x *RelayOpen) Reset() { *x = RelayOpen{} - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[190] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15074,7 +15199,7 @@ func (x *RelayOpen) String() string { func (*RelayOpen) ProtoMessage() {} func (x *RelayOpen) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[190] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15087,7 +15212,7 @@ func (x *RelayOpen) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpen.ProtoReflect.Descriptor instead. func (*RelayOpen) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{188} + return file_openshell_proto_rawDescGZIP(), []int{190} } func (x *RelayOpen) GetChannelId() string { @@ -15154,7 +15279,7 @@ type SshRelayTarget struct { func (x *SshRelayTarget) Reset() { *x = SshRelayTarget{} - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[191] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15166,7 +15291,7 @@ func (x *SshRelayTarget) String() string { func (*SshRelayTarget) ProtoMessage() {} func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[191] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15179,7 +15304,7 @@ func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use SshRelayTarget.ProtoReflect.Descriptor instead. func (*SshRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{189} + return file_openshell_proto_rawDescGZIP(), []int{191} } // TCP target dialed by the supervisor from inside the sandbox. @@ -15195,7 +15320,7 @@ type TcpRelayTarget struct { func (x *TcpRelayTarget) Reset() { *x = TcpRelayTarget{} - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[192] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15207,7 +15332,7 @@ func (x *TcpRelayTarget) String() string { func (*TcpRelayTarget) ProtoMessage() {} func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[192] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15220,7 +15345,7 @@ func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpRelayTarget.ProtoReflect.Descriptor instead. func (*TcpRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{190} + return file_openshell_proto_rawDescGZIP(), []int{192} } func (x *TcpRelayTarget) GetHost() string { @@ -15248,7 +15373,7 @@ type RelayInit struct { func (x *RelayInit) Reset() { *x = RelayInit{} - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15260,7 +15385,7 @@ func (x *RelayInit) String() string { func (*RelayInit) ProtoMessage() {} func (x *RelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[193] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15273,7 +15398,7 @@ func (x *RelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayInit.ProtoReflect.Descriptor instead. func (*RelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{191} + return file_openshell_proto_rawDescGZIP(), []int{193} } func (x *RelayInit) GetChannelId() string { @@ -15300,7 +15425,7 @@ type RelayFrame struct { func (x *RelayFrame) Reset() { *x = RelayFrame{} - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15312,7 +15437,7 @@ func (x *RelayFrame) String() string { func (*RelayFrame) ProtoMessage() {} func (x *RelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[194] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15325,7 +15450,7 @@ func (x *RelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayFrame.ProtoReflect.Descriptor instead. func (*RelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{192} + return file_openshell_proto_rawDescGZIP(), []int{194} } func (x *RelayFrame) GetPayload() isRelayFrame_Payload { @@ -15385,7 +15510,7 @@ type PeerRelayInit struct { func (x *PeerRelayInit) Reset() { *x = PeerRelayInit{} - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15397,7 +15522,7 @@ func (x *PeerRelayInit) String() string { func (*PeerRelayInit) ProtoMessage() {} func (x *PeerRelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[195] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15410,7 +15535,7 @@ func (x *PeerRelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerRelayInit.ProtoReflect.Descriptor instead. func (*PeerRelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{193} + return file_openshell_proto_rawDescGZIP(), []int{195} } func (x *PeerRelayInit) GetSandboxId() string { @@ -15448,7 +15573,7 @@ type PeerRelayFrame struct { func (x *PeerRelayFrame) Reset() { *x = PeerRelayFrame{} - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15460,7 +15585,7 @@ func (x *PeerRelayFrame) String() string { func (*PeerRelayFrame) ProtoMessage() {} func (x *PeerRelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[196] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15473,7 +15598,7 @@ func (x *PeerRelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerRelayFrame.ProtoReflect.Descriptor instead. func (*PeerRelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{194} + return file_openshell_proto_rawDescGZIP(), []int{196} } func (x *PeerRelayFrame) GetPayload() isPeerRelayFrame_Payload { @@ -15528,7 +15653,7 @@ type PeerConfigSandboxTarget struct { func (x *PeerConfigSandboxTarget) Reset() { *x = PeerConfigSandboxTarget{} - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15540,7 +15665,7 @@ func (x *PeerConfigSandboxTarget) String() string { func (*PeerConfigSandboxTarget) ProtoMessage() {} func (x *PeerConfigSandboxTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[197] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15553,7 +15678,7 @@ func (x *PeerConfigSandboxTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerConfigSandboxTarget.ProtoReflect.Descriptor instead. func (*PeerConfigSandboxTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{195} + return file_openshell_proto_rawDescGZIP(), []int{197} } func (x *PeerConfigSandboxTarget) GetSandboxId() string { @@ -15581,7 +15706,7 @@ type PeerConfigProviderTarget struct { func (x *PeerConfigProviderTarget) Reset() { *x = PeerConfigProviderTarget{} - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15593,7 +15718,7 @@ func (x *PeerConfigProviderTarget) String() string { func (*PeerConfigProviderTarget) ProtoMessage() {} func (x *PeerConfigProviderTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[198] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15606,7 +15731,7 @@ func (x *PeerConfigProviderTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerConfigProviderTarget.ProtoReflect.Descriptor instead. func (*PeerConfigProviderTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{196} + return file_openshell_proto_rawDescGZIP(), []int{198} } func (x *PeerConfigProviderTarget) GetWorkspace() string { @@ -15638,7 +15763,7 @@ type PeerNotifyConfigUpdateRequest struct { func (x *PeerNotifyConfigUpdateRequest) Reset() { *x = PeerNotifyConfigUpdateRequest{} - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15650,7 +15775,7 @@ func (x *PeerNotifyConfigUpdateRequest) String() string { func (*PeerNotifyConfigUpdateRequest) ProtoMessage() {} func (x *PeerNotifyConfigUpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[199] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15663,7 +15788,7 @@ func (x *PeerNotifyConfigUpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerNotifyConfigUpdateRequest.ProtoReflect.Descriptor instead. func (*PeerNotifyConfigUpdateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{197} + return file_openshell_proto_rawDescGZIP(), []int{199} } func (x *PeerNotifyConfigUpdateRequest) GetScope() isPeerNotifyConfigUpdateRequest_Scope { @@ -15747,7 +15872,7 @@ type PeerNotifyConfigUpdateResponse struct { func (x *PeerNotifyConfigUpdateResponse) Reset() { *x = PeerNotifyConfigUpdateResponse{} - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[200] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15759,7 +15884,7 @@ func (x *PeerNotifyConfigUpdateResponse) String() string { func (*PeerNotifyConfigUpdateResponse) ProtoMessage() {} func (x *PeerNotifyConfigUpdateResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[200] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15772,7 +15897,7 @@ func (x *PeerNotifyConfigUpdateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerNotifyConfigUpdateResponse.ProtoReflect.Descriptor instead. func (*PeerNotifyConfigUpdateResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{198} + return file_openshell_proto_rawDescGZIP(), []int{200} } func (x *PeerNotifyConfigUpdateResponse) GetStaleOwner() bool { @@ -15797,7 +15922,7 @@ type RelayOpenResult struct { func (x *RelayOpenResult) Reset() { *x = RelayOpenResult{} - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[201] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15809,7 +15934,7 @@ func (x *RelayOpenResult) String() string { func (*RelayOpenResult) ProtoMessage() {} func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[201] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15822,7 +15947,7 @@ func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpenResult.ProtoReflect.Descriptor instead. func (*RelayOpenResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{199} + return file_openshell_proto_rawDescGZIP(), []int{201} } func (x *RelayOpenResult) GetChannelId() string { @@ -15859,7 +15984,7 @@ type RelayClose struct { func (x *RelayClose) Reset() { *x = RelayClose{} - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[202] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15871,7 +15996,7 @@ func (x *RelayClose) String() string { func (*RelayClose) ProtoMessage() {} func (x *RelayClose) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[202] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15884,7 +16009,7 @@ func (x *RelayClose) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayClose.ProtoReflect.Descriptor instead. func (*RelayClose) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{200} + return file_openshell_proto_rawDescGZIP(), []int{202} } func (x *RelayClose) GetChannelId() string { @@ -15918,7 +16043,7 @@ type L7RequestSample struct { func (x *L7RequestSample) Reset() { *x = L7RequestSample{} - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[203] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15930,7 +16055,7 @@ func (x *L7RequestSample) String() string { func (*L7RequestSample) ProtoMessage() {} func (x *L7RequestSample) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[203] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15943,7 +16068,7 @@ func (x *L7RequestSample) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RequestSample.ProtoReflect.Descriptor instead. func (*L7RequestSample) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{201} + return file_openshell_proto_rawDescGZIP(), []int{203} } func (x *L7RequestSample) GetMethod() string { @@ -16017,7 +16142,7 @@ type DenialSummary struct { func (x *DenialSummary) Reset() { *x = DenialSummary{} - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[204] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16029,7 +16154,7 @@ func (x *DenialSummary) String() string { func (*DenialSummary) ProtoMessage() {} func (x *DenialSummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[204] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16042,7 +16167,7 @@ func (x *DenialSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialSummary.ProtoReflect.Descriptor instead. func (*DenialSummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{202} + return file_openshell_proto_rawDescGZIP(), []int{204} } func (x *DenialSummary) GetSandboxId() string { @@ -16177,7 +16302,7 @@ type DenialGroupCount struct { func (x *DenialGroupCount) Reset() { *x = DenialGroupCount{} - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[205] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16189,7 +16314,7 @@ func (x *DenialGroupCount) String() string { func (*DenialGroupCount) ProtoMessage() {} func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[205] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16202,7 +16327,7 @@ func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialGroupCount.ProtoReflect.Descriptor instead. func (*DenialGroupCount) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{203} + return file_openshell_proto_rawDescGZIP(), []int{205} } func (x *DenialGroupCount) GetDenyGroup() string { @@ -16235,7 +16360,7 @@ type NetworkActivitySummary struct { func (x *NetworkActivitySummary) Reset() { *x = NetworkActivitySummary{} - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[206] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16247,7 +16372,7 @@ func (x *NetworkActivitySummary) String() string { func (*NetworkActivitySummary) ProtoMessage() {} func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[206] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16260,7 +16385,7 @@ func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkActivitySummary.ProtoReflect.Descriptor instead. func (*NetworkActivitySummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{204} + return file_openshell_proto_rawDescGZIP(), []int{206} } func (x *NetworkActivitySummary) GetNetworkActivityCount() uint32 { @@ -16348,7 +16473,7 @@ type PolicyChunk struct { func (x *PolicyChunk) Reset() { *x = PolicyChunk{} - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[207] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16360,7 +16485,7 @@ func (x *PolicyChunk) String() string { func (*PolicyChunk) ProtoMessage() {} func (x *PolicyChunk) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[207] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16373,7 +16498,7 @@ func (x *PolicyChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyChunk.ProtoReflect.Descriptor instead. func (*PolicyChunk) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{205} + return file_openshell_proto_rawDescGZIP(), []int{207} } func (x *PolicyChunk) GetId() string { @@ -16561,7 +16686,7 @@ type DraftPolicyUpdate struct { func (x *DraftPolicyUpdate) Reset() { *x = DraftPolicyUpdate{} - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[208] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16573,7 +16698,7 @@ func (x *DraftPolicyUpdate) String() string { func (*DraftPolicyUpdate) ProtoMessage() {} func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[208] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16586,7 +16711,7 @@ func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftPolicyUpdate.ProtoReflect.Descriptor instead. func (*DraftPolicyUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{206} + return file_openshell_proto_rawDescGZIP(), []int{208} } func (x *DraftPolicyUpdate) GetDraftVersion() uint64 { @@ -16645,7 +16770,7 @@ type SubmitPolicyAnalysisRequest struct { func (x *SubmitPolicyAnalysisRequest) Reset() { *x = SubmitPolicyAnalysisRequest{} - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[209] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16657,7 +16782,7 @@ func (x *SubmitPolicyAnalysisRequest) String() string { func (*SubmitPolicyAnalysisRequest) ProtoMessage() {} func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[209] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16670,7 +16795,7 @@ func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisRequest.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{207} + return file_openshell_proto_rawDescGZIP(), []int{209} } func (x *SubmitPolicyAnalysisRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16733,7 +16858,7 @@ type SubmitPolicyAnalysisResponse struct { func (x *SubmitPolicyAnalysisResponse) Reset() { *x = SubmitPolicyAnalysisResponse{} - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[210] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16745,7 +16870,7 @@ func (x *SubmitPolicyAnalysisResponse) String() string { func (*SubmitPolicyAnalysisResponse) ProtoMessage() {} func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[210] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16758,7 +16883,7 @@ func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisResponse.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{208} + return file_openshell_proto_rawDescGZIP(), []int{210} } func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunks() uint32 { @@ -16803,7 +16928,7 @@ type GetDraftPolicyRequest struct { func (x *GetDraftPolicyRequest) Reset() { *x = GetDraftPolicyRequest{} - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[211] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16815,7 +16940,7 @@ func (x *GetDraftPolicyRequest) String() string { func (*GetDraftPolicyRequest) ProtoMessage() {} func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[211] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16828,7 +16953,7 @@ func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyRequest.ProtoReflect.Descriptor instead. func (*GetDraftPolicyRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{209} + return file_openshell_proto_rawDescGZIP(), []int{211} } func (x *GetDraftPolicyRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16868,7 +16993,7 @@ type GetDraftPolicyResponse struct { func (x *GetDraftPolicyResponse) Reset() { *x = GetDraftPolicyResponse{} - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[212] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16880,7 +17005,7 @@ func (x *GetDraftPolicyResponse) String() string { func (*GetDraftPolicyResponse) ProtoMessage() {} func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[212] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16893,7 +17018,7 @@ func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyResponse.ProtoReflect.Descriptor instead. func (*GetDraftPolicyResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{210} + return file_openshell_proto_rawDescGZIP(), []int{212} } func (x *GetDraftPolicyResponse) GetChunks() []*PolicyChunk { @@ -16944,7 +17069,7 @@ type ApproveDraftChunkRequest struct { func (x *ApproveDraftChunkRequest) Reset() { *x = ApproveDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[213] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16956,7 +17081,7 @@ func (x *ApproveDraftChunkRequest) String() string { func (*ApproveDraftChunkRequest) ProtoMessage() {} func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[213] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16969,7 +17094,7 @@ func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkRequest.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{211} + return file_openshell_proto_rawDescGZIP(), []int{213} } func (x *ApproveDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17019,7 +17144,7 @@ type ApproveDraftChunkResponse struct { func (x *ApproveDraftChunkResponse) Reset() { *x = ApproveDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[214] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17031,7 +17156,7 @@ func (x *ApproveDraftChunkResponse) String() string { func (*ApproveDraftChunkResponse) ProtoMessage() {} func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[214] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17044,7 +17169,7 @@ func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkResponse.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{212} + return file_openshell_proto_rawDescGZIP(), []int{214} } func (x *ApproveDraftChunkResponse) GetPolicyVersion() uint32 { @@ -17080,7 +17205,7 @@ type RejectDraftChunkRequest struct { func (x *RejectDraftChunkRequest) Reset() { *x = RejectDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[215] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17092,7 +17217,7 @@ func (x *RejectDraftChunkRequest) String() string { func (*RejectDraftChunkRequest) ProtoMessage() {} func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[215] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17105,7 +17230,7 @@ func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkRequest.ProtoReflect.Descriptor instead. func (*RejectDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{213} + return file_openshell_proto_rawDescGZIP(), []int{215} } func (x *RejectDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17151,7 +17276,7 @@ type RejectDraftChunkResponse struct { func (x *RejectDraftChunkResponse) Reset() { *x = RejectDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[216] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17163,7 +17288,7 @@ func (x *RejectDraftChunkResponse) String() string { func (*RejectDraftChunkResponse) ProtoMessage() {} func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[216] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17176,7 +17301,7 @@ func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkResponse.ProtoReflect.Descriptor instead. func (*RejectDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{214} + return file_openshell_proto_rawDescGZIP(), []int{216} } // Approve all pending chunks. @@ -17190,7 +17315,7 @@ type DraftChunkApproval struct { func (x *DraftChunkApproval) Reset() { *x = DraftChunkApproval{} - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[217] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17202,7 +17327,7 @@ func (x *DraftChunkApproval) String() string { func (*DraftChunkApproval) ProtoMessage() {} func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[217] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17215,7 +17340,7 @@ func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftChunkApproval.ProtoReflect.Descriptor instead. func (*DraftChunkApproval) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{215} + return file_openshell_proto_rawDescGZIP(), []int{217} } func (x *DraftChunkApproval) GetChunkId() string { @@ -17251,7 +17376,7 @@ type ApproveAllDraftChunksRequest struct { func (x *ApproveAllDraftChunksRequest) Reset() { *x = ApproveAllDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[218] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17263,7 +17388,7 @@ func (x *ApproveAllDraftChunksRequest) String() string { func (*ApproveAllDraftChunksRequest) ProtoMessage() {} func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[218] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17276,7 +17401,7 @@ func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{216} + return file_openshell_proto_rawDescGZIP(), []int{218} } func (x *ApproveAllDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17331,7 +17456,7 @@ type ApproveAllDraftChunksResponse struct { func (x *ApproveAllDraftChunksResponse) Reset() { *x = ApproveAllDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[219] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17343,7 +17468,7 @@ func (x *ApproveAllDraftChunksResponse) String() string { func (*ApproveAllDraftChunksResponse) ProtoMessage() {} func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[219] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17356,7 +17481,7 @@ func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{217} + return file_openshell_proto_rawDescGZIP(), []int{219} } func (x *ApproveAllDraftChunksResponse) GetPolicyVersion() uint32 { @@ -17406,7 +17531,7 @@ type EditDraftChunkRequest struct { func (x *EditDraftChunkRequest) Reset() { *x = EditDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[220] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17418,7 +17543,7 @@ func (x *EditDraftChunkRequest) String() string { func (*EditDraftChunkRequest) ProtoMessage() {} func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[220] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17431,7 +17556,7 @@ func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkRequest.ProtoReflect.Descriptor instead. func (*EditDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{218} + return file_openshell_proto_rawDescGZIP(), []int{220} } func (x *EditDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17477,7 +17602,7 @@ type EditDraftChunkResponse struct { func (x *EditDraftChunkResponse) Reset() { *x = EditDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[221] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17489,7 +17614,7 @@ func (x *EditDraftChunkResponse) String() string { func (*EditDraftChunkResponse) ProtoMessage() {} func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[221] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17502,7 +17627,7 @@ func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkResponse.ProtoReflect.Descriptor instead. func (*EditDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{219} + return file_openshell_proto_rawDescGZIP(), []int{221} } // Reverse an approval (remove merged rule from active policy). @@ -17522,7 +17647,7 @@ type UndoDraftChunkRequest struct { func (x *UndoDraftChunkRequest) Reset() { *x = UndoDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[222] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17534,7 +17659,7 @@ func (x *UndoDraftChunkRequest) String() string { func (*UndoDraftChunkRequest) ProtoMessage() {} func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[222] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17547,7 +17672,7 @@ func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkRequest.ProtoReflect.Descriptor instead. func (*UndoDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{220} + return file_openshell_proto_rawDescGZIP(), []int{222} } func (x *UndoDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17590,7 +17715,7 @@ type UndoDraftChunkResponse struct { func (x *UndoDraftChunkResponse) Reset() { *x = UndoDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[223] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17602,7 +17727,7 @@ func (x *UndoDraftChunkResponse) String() string { func (*UndoDraftChunkResponse) ProtoMessage() {} func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[223] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17615,7 +17740,7 @@ func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkResponse.ProtoReflect.Descriptor instead. func (*UndoDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{221} + return file_openshell_proto_rawDescGZIP(), []int{223} } func (x *UndoDraftChunkResponse) GetPolicyVersion() uint32 { @@ -17647,7 +17772,7 @@ type ClearDraftChunksRequest struct { func (x *ClearDraftChunksRequest) Reset() { *x = ClearDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[224] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17659,7 +17784,7 @@ func (x *ClearDraftChunksRequest) String() string { func (*ClearDraftChunksRequest) ProtoMessage() {} func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[224] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17672,7 +17797,7 @@ func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ClearDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{222} + return file_openshell_proto_rawDescGZIP(), []int{224} } func (x *ClearDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17706,7 +17831,7 @@ type ClearDraftChunksResponse struct { func (x *ClearDraftChunksResponse) Reset() { *x = ClearDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[225] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17718,7 +17843,7 @@ func (x *ClearDraftChunksResponse) String() string { func (*ClearDraftChunksResponse) ProtoMessage() {} func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[225] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17731,7 +17856,7 @@ func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ClearDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{223} + return file_openshell_proto_rawDescGZIP(), []int{225} } func (x *ClearDraftChunksResponse) GetChunksCleared() uint32 { @@ -17753,7 +17878,7 @@ type GetDraftHistoryRequest struct { func (x *GetDraftHistoryRequest) Reset() { *x = GetDraftHistoryRequest{} - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[226] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17765,7 +17890,7 @@ func (x *GetDraftHistoryRequest) String() string { func (*GetDraftHistoryRequest) ProtoMessage() {} func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[226] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17778,7 +17903,7 @@ func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryRequest.ProtoReflect.Descriptor instead. func (*GetDraftHistoryRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{224} + return file_openshell_proto_rawDescGZIP(), []int{226} } func (x *GetDraftHistoryRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17812,7 +17937,7 @@ type DraftHistoryEntry struct { func (x *DraftHistoryEntry) Reset() { *x = DraftHistoryEntry{} - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[227] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17824,7 +17949,7 @@ func (x *DraftHistoryEntry) String() string { func (*DraftHistoryEntry) ProtoMessage() {} func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[227] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17837,7 +17962,7 @@ func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftHistoryEntry.ProtoReflect.Descriptor instead. func (*DraftHistoryEntry) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{225} + return file_openshell_proto_rawDescGZIP(), []int{227} } func (x *DraftHistoryEntry) GetEventTime() *timestamppb.Timestamp { @@ -17878,7 +18003,7 @@ type GetDraftHistoryResponse struct { func (x *GetDraftHistoryResponse) Reset() { *x = GetDraftHistoryResponse{} - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[228] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17890,7 +18015,7 @@ func (x *GetDraftHistoryResponse) String() string { func (*GetDraftHistoryResponse) ProtoMessage() {} func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[228] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17903,7 +18028,7 @@ func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryResponse.ProtoReflect.Descriptor instead. func (*GetDraftHistoryResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{226} + return file_openshell_proto_rawDescGZIP(), []int{228} } func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry { @@ -17928,7 +18053,7 @@ type CreateWorkspaceRequest struct { func (x *CreateWorkspaceRequest) Reset() { *x = CreateWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[229] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17940,7 +18065,7 @@ func (x *CreateWorkspaceRequest) String() string { func (*CreateWorkspaceRequest) ProtoMessage() {} func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[229] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17953,7 +18078,7 @@ func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceRequest.ProtoReflect.Descriptor instead. func (*CreateWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{227} + return file_openshell_proto_rawDescGZIP(), []int{229} } func (x *CreateWorkspaceRequest) GetName() string { @@ -17987,7 +18112,7 @@ type CreateWorkspaceResponse struct { func (x *CreateWorkspaceResponse) Reset() { *x = CreateWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[230] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17999,7 +18124,7 @@ func (x *CreateWorkspaceResponse) String() string { func (*CreateWorkspaceResponse) ProtoMessage() {} func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[230] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18012,7 +18137,7 @@ func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceResponse.ProtoReflect.Descriptor instead. func (*CreateWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{228} + return file_openshell_proto_rawDescGZIP(), []int{230} } func (x *CreateWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -18033,7 +18158,7 @@ type GetWorkspaceRequest struct { func (x *GetWorkspaceRequest) Reset() { *x = GetWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[231] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18045,7 +18170,7 @@ func (x *GetWorkspaceRequest) String() string { func (*GetWorkspaceRequest) ProtoMessage() {} func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[231] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18058,7 +18183,7 @@ func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceRequest.ProtoReflect.Descriptor instead. func (*GetWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{229} + return file_openshell_proto_rawDescGZIP(), []int{231} } func (x *GetWorkspaceRequest) GetName() string { @@ -18078,7 +18203,7 @@ type GetWorkspaceResponse struct { func (x *GetWorkspaceResponse) Reset() { *x = GetWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[232] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18090,7 +18215,7 @@ func (x *GetWorkspaceResponse) String() string { func (*GetWorkspaceResponse) ProtoMessage() {} func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[232] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18103,7 +18228,7 @@ func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceResponse.ProtoReflect.Descriptor instead. func (*GetWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{230} + return file_openshell_proto_rawDescGZIP(), []int{232} } func (x *GetWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -18130,7 +18255,7 @@ type ListWorkspacesRequest struct { func (x *ListWorkspacesRequest) Reset() { *x = ListWorkspacesRequest{} - mi := &file_openshell_proto_msgTypes[231] + mi := &file_openshell_proto_msgTypes[233] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18142,7 +18267,7 @@ func (x *ListWorkspacesRequest) String() string { func (*ListWorkspacesRequest) ProtoMessage() {} func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[231] + mi := &file_openshell_proto_msgTypes[233] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18155,7 +18280,7 @@ func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesRequest.ProtoReflect.Descriptor instead. func (*ListWorkspacesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{231} + return file_openshell_proto_rawDescGZIP(), []int{233} } func (x *ListWorkspacesRequest) GetPageSize() int32 { @@ -18191,7 +18316,7 @@ type ListWorkspacesResponse struct { func (x *ListWorkspacesResponse) Reset() { *x = ListWorkspacesResponse{} - mi := &file_openshell_proto_msgTypes[232] + mi := &file_openshell_proto_msgTypes[234] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18203,7 +18328,7 @@ func (x *ListWorkspacesResponse) String() string { func (*ListWorkspacesResponse) ProtoMessage() {} func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[232] + mi := &file_openshell_proto_msgTypes[234] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18216,7 +18341,7 @@ func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesResponse.ProtoReflect.Descriptor instead. func (*ListWorkspacesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{232} + return file_openshell_proto_rawDescGZIP(), []int{234} } func (x *ListWorkspacesResponse) GetWorkspaces() []*datamodelv1.Workspace { @@ -18247,7 +18372,7 @@ type DeleteWorkspaceRequest struct { func (x *DeleteWorkspaceRequest) Reset() { *x = DeleteWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[233] + mi := &file_openshell_proto_msgTypes[235] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18259,7 +18384,7 @@ func (x *DeleteWorkspaceRequest) String() string { func (*DeleteWorkspaceRequest) ProtoMessage() {} func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[233] + mi := &file_openshell_proto_msgTypes[235] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18272,7 +18397,7 @@ func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{233} + return file_openshell_proto_rawDescGZIP(), []int{235} } func (x *DeleteWorkspaceRequest) GetName() string { @@ -18306,7 +18431,7 @@ type DeleteWorkspaceResponse struct { func (x *DeleteWorkspaceResponse) Reset() { *x = DeleteWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[234] + mi := &file_openshell_proto_msgTypes[236] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18318,7 +18443,7 @@ func (x *DeleteWorkspaceResponse) String() string { func (*DeleteWorkspaceResponse) ProtoMessage() {} func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[234] + mi := &file_openshell_proto_msgTypes[236] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18331,7 +18456,7 @@ func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceResponse.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{234} + return file_openshell_proto_rawDescGZIP(), []int{236} } func (x *DeleteWorkspaceResponse) GetOutcome() DeletionOutcome { @@ -18355,7 +18480,7 @@ type WorkspaceMember struct { func (x *WorkspaceMember) Reset() { *x = WorkspaceMember{} - mi := &file_openshell_proto_msgTypes[235] + mi := &file_openshell_proto_msgTypes[237] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18367,7 +18492,7 @@ func (x *WorkspaceMember) String() string { func (*WorkspaceMember) ProtoMessage() {} func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[235] + mi := &file_openshell_proto_msgTypes[237] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18380,7 +18505,7 @@ func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkspaceMember.ProtoReflect.Descriptor instead. func (*WorkspaceMember) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{235} + return file_openshell_proto_rawDescGZIP(), []int{237} } func (x *WorkspaceMember) GetMetadata() *datamodelv1.ObjectMeta { @@ -18421,7 +18546,7 @@ type AddWorkspaceMemberRequest struct { func (x *AddWorkspaceMemberRequest) Reset() { *x = AddWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[236] + mi := &file_openshell_proto_msgTypes[238] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18433,7 +18558,7 @@ func (x *AddWorkspaceMemberRequest) String() string { func (*AddWorkspaceMemberRequest) ProtoMessage() {} func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[236] + mi := &file_openshell_proto_msgTypes[238] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18446,7 +18571,7 @@ func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{236} + return file_openshell_proto_rawDescGZIP(), []int{238} } func (x *AddWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18487,7 +18612,7 @@ type AddWorkspaceMemberResponse struct { func (x *AddWorkspaceMemberResponse) Reset() { *x = AddWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[237] + mi := &file_openshell_proto_msgTypes[239] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18499,7 +18624,7 @@ func (x *AddWorkspaceMemberResponse) String() string { func (*AddWorkspaceMemberResponse) ProtoMessage() {} func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[237] + mi := &file_openshell_proto_msgTypes[239] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18512,7 +18637,7 @@ func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{237} + return file_openshell_proto_rawDescGZIP(), []int{239} } func (x *AddWorkspaceMemberResponse) GetMember() *WorkspaceMember { @@ -18538,7 +18663,7 @@ type RemoveWorkspaceMemberRequest struct { func (x *RemoveWorkspaceMemberRequest) Reset() { *x = RemoveWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[238] + mi := &file_openshell_proto_msgTypes[240] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18550,7 +18675,7 @@ func (x *RemoveWorkspaceMemberRequest) String() string { func (*RemoveWorkspaceMemberRequest) ProtoMessage() {} func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[238] + mi := &file_openshell_proto_msgTypes[240] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18563,7 +18688,7 @@ func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{238} + return file_openshell_proto_rawDescGZIP(), []int{240} } func (x *RemoveWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18604,7 +18729,7 @@ type RemoveWorkspaceMemberResponse struct { func (x *RemoveWorkspaceMemberResponse) Reset() { *x = RemoveWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[239] + mi := &file_openshell_proto_msgTypes[241] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18616,7 +18741,7 @@ func (x *RemoveWorkspaceMemberResponse) String() string { func (*RemoveWorkspaceMemberResponse) ProtoMessage() {} func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[239] + mi := &file_openshell_proto_msgTypes[241] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18629,7 +18754,7 @@ func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{239} + return file_openshell_proto_rawDescGZIP(), []int{241} } func (x *RemoveWorkspaceMemberResponse) GetOutcome() DeletionOutcome { @@ -18656,7 +18781,7 @@ type ListWorkspaceMembersRequest struct { func (x *ListWorkspaceMembersRequest) Reset() { *x = ListWorkspaceMembersRequest{} - mi := &file_openshell_proto_msgTypes[240] + mi := &file_openshell_proto_msgTypes[242] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18668,7 +18793,7 @@ func (x *ListWorkspaceMembersRequest) String() string { func (*ListWorkspaceMembersRequest) ProtoMessage() {} func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[240] + mi := &file_openshell_proto_msgTypes[242] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18681,7 +18806,7 @@ func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersRequest.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{240} + return file_openshell_proto_rawDescGZIP(), []int{242} } func (x *ListWorkspaceMembersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18717,7 +18842,7 @@ type ListWorkspaceMembersResponse struct { func (x *ListWorkspaceMembersResponse) Reset() { *x = ListWorkspaceMembersResponse{} - mi := &file_openshell_proto_msgTypes[241] + mi := &file_openshell_proto_msgTypes[243] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18729,7 +18854,7 @@ func (x *ListWorkspaceMembersResponse) String() string { func (*ListWorkspaceMembersResponse) ProtoMessage() {} func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[241] + mi := &file_openshell_proto_msgTypes[243] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18742,7 +18867,7 @@ func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersResponse.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{241} + return file_openshell_proto_rawDescGZIP(), []int{243} } func (x *ListWorkspaceMembersResponse) GetMembers() []*WorkspaceMember { @@ -18777,7 +18902,7 @@ type ExtensionServiceCredential struct { func (x *ExtensionServiceCredential) Reset() { *x = ExtensionServiceCredential{} - mi := &file_openshell_proto_msgTypes[242] + mi := &file_openshell_proto_msgTypes[244] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18789,7 +18914,7 @@ func (x *ExtensionServiceCredential) String() string { func (*ExtensionServiceCredential) ProtoMessage() {} func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[242] + mi := &file_openshell_proto_msgTypes[244] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18802,7 +18927,7 @@ func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionServiceCredential.ProtoReflect.Descriptor instead. func (*ExtensionServiceCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{242} + return file_openshell_proto_rawDescGZIP(), []int{244} } func (x *ExtensionServiceCredential) GetServiceName() string { @@ -18842,7 +18967,7 @@ type EndpointObservation struct { func (x *EndpointObservation) Reset() { *x = EndpointObservation{} - mi := &file_openshell_proto_msgTypes[243] + mi := &file_openshell_proto_msgTypes[245] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18854,7 +18979,7 @@ func (x *EndpointObservation) String() string { func (*EndpointObservation) ProtoMessage() {} func (x *EndpointObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[243] + mi := &file_openshell_proto_msgTypes[245] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18867,7 +18992,7 @@ func (x *EndpointObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointObservation.ProtoReflect.Descriptor instead. func (*EndpointObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{243} + return file_openshell_proto_rawDescGZIP(), []int{245} } func (x *EndpointObservation) GetEndpointId() string { @@ -18920,7 +19045,7 @@ type ReportEndpointStatusRequest struct { func (x *ReportEndpointStatusRequest) Reset() { *x = ReportEndpointStatusRequest{} - mi := &file_openshell_proto_msgTypes[244] + mi := &file_openshell_proto_msgTypes[246] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18932,7 +19057,7 @@ func (x *ReportEndpointStatusRequest) String() string { func (*ReportEndpointStatusRequest) ProtoMessage() {} func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[244] + mi := &file_openshell_proto_msgTypes[246] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18945,7 +19070,7 @@ func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusRequest.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{244} + return file_openshell_proto_rawDescGZIP(), []int{246} } func (x *ReportEndpointStatusRequest) GetSandboxId() string { @@ -19014,7 +19139,7 @@ type TokenGrantStatus struct { func (x *TokenGrantStatus) Reset() { *x = TokenGrantStatus{} - mi := &file_openshell_proto_msgTypes[245] + mi := &file_openshell_proto_msgTypes[247] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19026,7 +19151,7 @@ func (x *TokenGrantStatus) String() string { func (*TokenGrantStatus) ProtoMessage() {} func (x *TokenGrantStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[245] + mi := &file_openshell_proto_msgTypes[247] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19039,7 +19164,7 @@ func (x *TokenGrantStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use TokenGrantStatus.ProtoReflect.Descriptor instead. func (*TokenGrantStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{245} + return file_openshell_proto_rawDescGZIP(), []int{247} } func (x *TokenGrantStatus) GetLastFailure() *TokenGrantFailureObservation { @@ -19066,7 +19191,7 @@ type TokenGrantFailureObservation struct { func (x *TokenGrantFailureObservation) Reset() { *x = TokenGrantFailureObservation{} - mi := &file_openshell_proto_msgTypes[246] + mi := &file_openshell_proto_msgTypes[248] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19078,7 +19203,7 @@ func (x *TokenGrantFailureObservation) String() string { func (*TokenGrantFailureObservation) ProtoMessage() {} func (x *TokenGrantFailureObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[246] + mi := &file_openshell_proto_msgTypes[248] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19091,7 +19216,7 @@ func (x *TokenGrantFailureObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use TokenGrantFailureObservation.ProtoReflect.Descriptor instead. func (*TokenGrantFailureObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{246} + return file_openshell_proto_rawDescGZIP(), []int{248} } func (x *TokenGrantFailureObservation) GetDestinationHost() string { @@ -19124,7 +19249,7 @@ type ReportEndpointStatusResponse struct { func (x *ReportEndpointStatusResponse) Reset() { *x = ReportEndpointStatusResponse{} - mi := &file_openshell_proto_msgTypes[247] + mi := &file_openshell_proto_msgTypes[249] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19136,7 +19261,7 @@ func (x *ReportEndpointStatusResponse) String() string { func (*ReportEndpointStatusResponse) ProtoMessage() {} func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[247] + mi := &file_openshell_proto_msgTypes[249] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19149,7 +19274,7 @@ func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusResponse.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{247} + return file_openshell_proto_rawDescGZIP(), []int{249} } // A configured endpoint and its last accepted network result in one record. @@ -19183,7 +19308,7 @@ type EndpointStatus struct { func (x *EndpointStatus) Reset() { *x = EndpointStatus{} - mi := &file_openshell_proto_msgTypes[248] + mi := &file_openshell_proto_msgTypes[250] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19195,7 +19320,7 @@ func (x *EndpointStatus) String() string { func (*EndpointStatus) ProtoMessage() {} func (x *EndpointStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[248] + mi := &file_openshell_proto_msgTypes[250] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19208,7 +19333,7 @@ func (x *EndpointStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointStatus.ProtoReflect.Descriptor instead. func (*EndpointStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{248} + return file_openshell_proto_rawDescGZIP(), []int{250} } func (x *EndpointStatus) GetEndpointId() string { @@ -19303,7 +19428,7 @@ type SandboxProvisioning struct { func (x *SandboxProvisioning) Reset() { *x = SandboxProvisioning{} - mi := &file_openshell_proto_msgTypes[249] + mi := &file_openshell_proto_msgTypes[251] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19315,7 +19440,7 @@ func (x *SandboxProvisioning) String() string { func (*SandboxProvisioning) ProtoMessage() {} func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[249] + mi := &file_openshell_proto_msgTypes[251] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19328,7 +19453,7 @@ func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxProvisioning.ProtoReflect.Descriptor instead. func (*SandboxProvisioning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{249} + return file_openshell_proto_rawDescGZIP(), []int{251} } func (x *SandboxProvisioning) GetAttemptId() string { @@ -19451,7 +19576,7 @@ type SandboxServiceExposure struct { func (x *SandboxServiceExposure) Reset() { *x = SandboxServiceExposure{} - mi := &file_openshell_proto_msgTypes[250] + mi := &file_openshell_proto_msgTypes[252] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19463,7 +19588,7 @@ func (x *SandboxServiceExposure) String() string { func (*SandboxServiceExposure) ProtoMessage() {} func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[250] + mi := &file_openshell_proto_msgTypes[252] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19476,7 +19601,7 @@ func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxServiceExposure.ProtoReflect.Descriptor instead. func (*SandboxServiceExposure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{250} + return file_openshell_proto_rawDescGZIP(), []int{252} } func (x *SandboxServiceExposure) GetService() string { @@ -19530,7 +19655,7 @@ type EndpointFailure struct { func (x *EndpointFailure) Reset() { *x = EndpointFailure{} - mi := &file_openshell_proto_msgTypes[251] + mi := &file_openshell_proto_msgTypes[253] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19542,7 +19667,7 @@ func (x *EndpointFailure) String() string { func (*EndpointFailure) ProtoMessage() {} func (x *EndpointFailure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[251] + mi := &file_openshell_proto_msgTypes[253] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19555,7 +19680,7 @@ func (x *EndpointFailure) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointFailure.ProtoReflect.Descriptor instead. func (*EndpointFailure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{251} + return file_openshell_proto_rawDescGZIP(), []int{253} } func (x *EndpointFailure) GetDomain() EndpointFailureDomain { @@ -19813,14 +19938,26 @@ const file_openshell_proto_rawDesc = "" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a>\n" + "\x10AnnotationsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xef\x01\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xf8\x03\n" + "\x14UpdateSandboxRequest\x12R\n" + "\x0fworkspace_scope\x18\x01 \x01(\v2).openshell.datamodel.v1.WorkspaceSelectorR\x0eworkspaceScope\x12\x12\n" + - "\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" + - "\x05image\x18\x03 \x01(\tR\x05image\x12:\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x19\n" + + "\x05image\x18\x03 \x01(\tH\x00R\x05image\x88\x01\x01\x12<\n" + + "\acommand\x18\x06 \x01(\v2\".openshell.v1.SandboxCommandUpdateR\acommand\x12@\n" + + "\venvironment\x18\a \x01(\v2\x1e.openshell.v1.SandboxMapUpdateR\venvironment\x126\n" + + "\x06labels\x18\b \x01(\v2\x1e.openshell.v1.SandboxMapUpdateR\x06labels\x12@\n" + + "\vannotations\x18\t \x01(\v2\x1e.openshell.v1.SandboxMapUpdateR\vannotations\x12:\n" + "\x19expected_resource_version\x18\x04 \x01(\x04R\x17expectedResourceVersion\x12\x1d\n" + "\n" + - "request_id\x18\x05 \x01(\tR\trequestId\"\xd4\x01\n" + + "request_id\x18\x05 \x01(\tR\trequestIdB\b\n" + + "\x06_image\"*\n" + + "\x14SandboxCommandUpdate\x12\x12\n" + + "\x04argv\x18\x01 \x03(\tR\x04argv\"\x91\x01\n" + + "\x10SandboxMapUpdate\x12B\n" + + "\x06values\x18\x01 \x03(\v2*.openshell.v1.SandboxMapUpdate.ValuesEntryR\x06values\x1a9\n" + + "\vValuesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xd4\x01\n" + "\x1cCreateSandboxTemplateRequest\x12R\n" + "\x0fworkspace_scope\x18\x02 \x01(\v2).openshell.datamodel.v1.WorkspaceSelectorR\x0eworkspaceScope\x12A\n" + "\btemplate\x18\x01 \x01(\v2%.openshell.v1.SandboxWorkloadTemplateR\btemplate\x12\x1d\n" + @@ -21435,7 +21572,7 @@ func file_openshell_proto_rawDescGZIP() []byte { } var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 22) -var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 278) +var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 281) var file_openshell_proto_goTypes = []any{ (ExtensionKind)(0), // 0: openshell.v1.ExtensionKind (SandboxPhase)(0), // 1: openshell.v1.SandboxPhase @@ -21493,276 +21630,279 @@ var file_openshell_proto_goTypes = []any{ (*PlatformEvent)(nil), // 53: openshell.v1.PlatformEvent (*CreateSandboxRequest)(nil), // 54: openshell.v1.CreateSandboxRequest (*UpdateSandboxRequest)(nil), // 55: openshell.v1.UpdateSandboxRequest - (*CreateSandboxTemplateRequest)(nil), // 56: openshell.v1.CreateSandboxTemplateRequest - (*GetSandboxTemplateRequest)(nil), // 57: openshell.v1.GetSandboxTemplateRequest - (*ListSandboxTemplatesRequest)(nil), // 58: openshell.v1.ListSandboxTemplatesRequest - (*DeleteSandboxTemplateRequest)(nil), // 59: openshell.v1.DeleteSandboxTemplateRequest - (*SandboxTemplateResponse)(nil), // 60: openshell.v1.SandboxTemplateResponse - (*ListSandboxTemplatesResponse)(nil), // 61: openshell.v1.ListSandboxTemplatesResponse - (*DeleteSandboxTemplateResponse)(nil), // 62: openshell.v1.DeleteSandboxTemplateResponse - (*BeginRootfsTarStagingRequest)(nil), // 63: openshell.v1.BeginRootfsTarStagingRequest - (*BeginRootfsTarStagingResponse)(nil), // 64: openshell.v1.BeginRootfsTarStagingResponse - (*GetSandboxRequest)(nil), // 65: openshell.v1.GetSandboxRequest - (*ListSandboxesRequest)(nil), // 66: openshell.v1.ListSandboxesRequest - (*ListSandboxProvidersRequest)(nil), // 67: openshell.v1.ListSandboxProvidersRequest - (*AttachSandboxProviderRequest)(nil), // 68: openshell.v1.AttachSandboxProviderRequest - (*DetachSandboxProviderRequest)(nil), // 69: openshell.v1.DetachSandboxProviderRequest - (*DeleteSandboxRequest)(nil), // 70: openshell.v1.DeleteSandboxRequest - (*StopSandboxRequest)(nil), // 71: openshell.v1.StopSandboxRequest - (*StartSandboxRequest)(nil), // 72: openshell.v1.StartSandboxRequest - (*SuspendSandboxRequest)(nil), // 73: openshell.v1.SuspendSandboxRequest - (*ResumeSandboxRequest)(nil), // 74: openshell.v1.ResumeSandboxRequest - (*SandboxResponse)(nil), // 75: openshell.v1.SandboxResponse - (*ListSandboxesResponse)(nil), // 76: openshell.v1.ListSandboxesResponse - (*ListSandboxProvidersResponse)(nil), // 77: openshell.v1.ListSandboxProvidersResponse - (*AttachSandboxProviderResponse)(nil), // 78: openshell.v1.AttachSandboxProviderResponse - (*DetachSandboxProviderResponse)(nil), // 79: openshell.v1.DetachSandboxProviderResponse - (*ProviderDesiredIdentity)(nil), // 80: openshell.v1.ProviderDesiredIdentity - (*ConfigSnapshotRevision)(nil), // 81: openshell.v1.ConfigSnapshotRevision - (*SandboxConfigRevision)(nil), // 82: openshell.v1.SandboxConfigRevision - (*ConfigUpdateOperation)(nil), // 83: openshell.v1.ConfigUpdateOperation - (*ProviderMutationReceipt)(nil), // 84: openshell.v1.ProviderMutationReceipt - (*ProviderReadinessObservation)(nil), // 85: openshell.v1.ProviderReadinessObservation - (*ProviderReadinessStatus)(nil), // 86: openshell.v1.ProviderReadinessStatus - (*GetSandboxProviderStatusRequest)(nil), // 87: openshell.v1.GetSandboxProviderStatusRequest - (*GetSandboxProviderStatusResponse)(nil), // 88: openshell.v1.GetSandboxProviderStatusResponse - (*ReportProviderReadinessRequest)(nil), // 89: openshell.v1.ReportProviderReadinessRequest - (*ReportProviderReadinessResponse)(nil), // 90: openshell.v1.ReportProviderReadinessResponse - (*DeleteSandboxResponse)(nil), // 91: openshell.v1.DeleteSandboxResponse - (*CreateSshSessionRequest)(nil), // 92: openshell.v1.CreateSshSessionRequest - (*CreateSshSessionResponse)(nil), // 93: openshell.v1.CreateSshSessionResponse - (*ExposeServiceRequest)(nil), // 94: openshell.v1.ExposeServiceRequest - (*GetServiceRequest)(nil), // 95: openshell.v1.GetServiceRequest - (*ListServicesRequest)(nil), // 96: openshell.v1.ListServicesRequest - (*ListServicesResponse)(nil), // 97: openshell.v1.ListServicesResponse - (*DeleteServiceRequest)(nil), // 98: openshell.v1.DeleteServiceRequest - (*DeleteServiceResponse)(nil), // 99: openshell.v1.DeleteServiceResponse - (*ServiceEndpoint)(nil), // 100: openshell.v1.ServiceEndpoint - (*ServiceEndpointResponse)(nil), // 101: openshell.v1.ServiceEndpointResponse - (*RevokeSshSessionRequest)(nil), // 102: openshell.v1.RevokeSshSessionRequest - (*RevokeSshSessionResponse)(nil), // 103: openshell.v1.RevokeSshSessionResponse - (*ExecSandboxRequest)(nil), // 104: openshell.v1.ExecSandboxRequest - (*ExecSandboxStdout)(nil), // 105: openshell.v1.ExecSandboxStdout - (*ExecSandboxStderr)(nil), // 106: openshell.v1.ExecSandboxStderr - (*ExecSandboxExit)(nil), // 107: openshell.v1.ExecSandboxExit - (*ExecSandboxEvent)(nil), // 108: openshell.v1.ExecSandboxEvent - (*TcpForwardInit)(nil), // 109: openshell.v1.TcpForwardInit - (*TcpForwardFrame)(nil), // 110: openshell.v1.TcpForwardFrame - (*ExecSandboxInput)(nil), // 111: openshell.v1.ExecSandboxInput - (*ExecSandboxWindowResize)(nil), // 112: openshell.v1.ExecSandboxWindowResize - (*SshSession)(nil), // 113: openshell.v1.SshSession - (*WatchSandboxRequest)(nil), // 114: openshell.v1.WatchSandboxRequest - (*SandboxStreamEvent)(nil), // 115: openshell.v1.SandboxStreamEvent - (*SandboxLogLine)(nil), // 116: openshell.v1.SandboxLogLine - (*SandboxStreamWarning)(nil), // 117: openshell.v1.SandboxStreamWarning - (*CreateProviderRequest)(nil), // 118: openshell.v1.CreateProviderRequest - (*GetProviderRequest)(nil), // 119: openshell.v1.GetProviderRequest - (*GetProviderCredentialsRequest)(nil), // 120: openshell.v1.GetProviderCredentialsRequest - (*ProviderCredentialValue)(nil), // 121: openshell.v1.ProviderCredentialValue - (*GetProviderCredentialsResponse)(nil), // 122: openshell.v1.GetProviderCredentialsResponse - (*ListProvidersRequest)(nil), // 123: openshell.v1.ListProvidersRequest - (*UpdateProviderRequest)(nil), // 124: openshell.v1.UpdateProviderRequest - (*DeleteProviderRequest)(nil), // 125: openshell.v1.DeleteProviderRequest - (*ProviderResponse)(nil), // 126: openshell.v1.ProviderResponse - (*ListProvidersResponse)(nil), // 127: openshell.v1.ListProvidersResponse - (*ListProviderProfilesRequest)(nil), // 128: openshell.v1.ListProviderProfilesRequest - (*GetProviderProfileRequest)(nil), // 129: openshell.v1.GetProviderProfileRequest - (*ProviderProfileImportItem)(nil), // 130: openshell.v1.ProviderProfileImportItem - (*ProviderProfileDiagnostic)(nil), // 131: openshell.v1.ProviderProfileDiagnostic - (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 132: openshell.v1.ProviderCredentialTokenGrantAudienceOverride - (*ProviderCredentialTokenGrantSubjectToken)(nil), // 133: openshell.v1.ProviderCredentialTokenGrantSubjectToken - (*ProviderCredentialTokenGrant)(nil), // 134: openshell.v1.ProviderCredentialTokenGrant - (*ProviderProfileCredential)(nil), // 135: openshell.v1.ProviderProfileCredential - (*ProviderCredentialRefreshMaterial)(nil), // 136: openshell.v1.ProviderCredentialRefreshMaterial - (*ProviderCredentialRefreshOutput)(nil), // 137: openshell.v1.ProviderCredentialRefreshOutput - (*ProviderCredentialRefresh)(nil), // 138: openshell.v1.ProviderCredentialRefresh - (*ProviderCredentialRefreshStatus)(nil), // 139: openshell.v1.ProviderCredentialRefreshStatus - (*ProviderProfileDiscovery)(nil), // 140: openshell.v1.ProviderProfileDiscovery - (*GetProviderRefreshStatusRequest)(nil), // 141: openshell.v1.GetProviderRefreshStatusRequest - (*GetProviderRefreshStatusResponse)(nil), // 142: openshell.v1.GetProviderRefreshStatusResponse - (*ConfigureProviderRefreshRequest)(nil), // 143: openshell.v1.ConfigureProviderRefreshRequest - (*ConfigureProviderRefreshResponse)(nil), // 144: openshell.v1.ConfigureProviderRefreshResponse - (*RotateProviderCredentialRequest)(nil), // 145: openshell.v1.RotateProviderCredentialRequest - (*RotateProviderCredentialResponse)(nil), // 146: openshell.v1.RotateProviderCredentialResponse - (*DeleteProviderRefreshRequest)(nil), // 147: openshell.v1.DeleteProviderRefreshRequest - (*DeleteProviderRefreshResponse)(nil), // 148: openshell.v1.DeleteProviderRefreshResponse - (*ProviderProfile)(nil), // 149: openshell.v1.ProviderProfile - (*ProviderProfileFile)(nil), // 150: openshell.v1.ProviderProfileFile - (*ProviderProfileResponse)(nil), // 151: openshell.v1.ProviderProfileResponse - (*ListProviderProfilesResponse)(nil), // 152: openshell.v1.ListProviderProfilesResponse - (*ImportProviderProfilesRequest)(nil), // 153: openshell.v1.ImportProviderProfilesRequest - (*ImportProviderProfilesResponse)(nil), // 154: openshell.v1.ImportProviderProfilesResponse - (*UpdateProviderProfilesRequest)(nil), // 155: openshell.v1.UpdateProviderProfilesRequest - (*UpdateProviderProfilesResponse)(nil), // 156: openshell.v1.UpdateProviderProfilesResponse - (*LintProviderProfilesRequest)(nil), // 157: openshell.v1.LintProviderProfilesRequest - (*LintProviderProfilesResponse)(nil), // 158: openshell.v1.LintProviderProfilesResponse - (*DeleteProviderResponse)(nil), // 159: openshell.v1.DeleteProviderResponse - (*DeleteProviderProfileRequest)(nil), // 160: openshell.v1.DeleteProviderProfileRequest - (*DeleteProviderProfileResponse)(nil), // 161: openshell.v1.DeleteProviderProfileResponse - (*GetSandboxProviderEnvironmentRequest)(nil), // 162: openshell.v1.GetSandboxProviderEnvironmentRequest - (*StaticCredentialEndpointBinding)(nil), // 163: openshell.v1.StaticCredentialEndpointBinding - (*StaticCredentialBinding)(nil), // 164: openshell.v1.StaticCredentialBinding - (*GetSandboxProviderEnvironmentResponse)(nil), // 165: openshell.v1.GetSandboxProviderEnvironmentResponse - (*ProviderEnvironmentValue)(nil), // 166: openshell.v1.ProviderEnvironmentValue - (*ProviderEnvironmentSnapshot)(nil), // 167: openshell.v1.ProviderEnvironmentSnapshot - (*ExchangeProviderSubjectTokenRequest)(nil), // 168: openshell.v1.ExchangeProviderSubjectTokenRequest - (*ExchangeProviderSubjectTokenResponse)(nil), // 169: openshell.v1.ExchangeProviderSubjectTokenResponse - (*UpdateConfigRequest)(nil), // 170: openshell.v1.UpdateConfigRequest - (*PolicyMergeOperation)(nil), // 171: openshell.v1.PolicyMergeOperation - (*AddNetworkRule)(nil), // 172: openshell.v1.AddNetworkRule - (*RemoveNetworkEndpoint)(nil), // 173: openshell.v1.RemoveNetworkEndpoint - (*RemoveNetworkRule)(nil), // 174: openshell.v1.RemoveNetworkRule - (*L7RuleTarget)(nil), // 175: openshell.v1.L7RuleTarget - (*AddDenyRules)(nil), // 176: openshell.v1.AddDenyRules - (*AddAllowRules)(nil), // 177: openshell.v1.AddAllowRules - (*RemoveNetworkBinary)(nil), // 178: openshell.v1.RemoveNetworkBinary - (*UpdateConfigResponse)(nil), // 179: openshell.v1.UpdateConfigResponse - (*GetSandboxPolicyStatusRequest)(nil), // 180: openshell.v1.GetSandboxPolicyStatusRequest - (*GetSandboxPolicyStatusResponse)(nil), // 181: openshell.v1.GetSandboxPolicyStatusResponse - (*ListSandboxPoliciesRequest)(nil), // 182: openshell.v1.ListSandboxPoliciesRequest - (*ListSandboxPoliciesResponse)(nil), // 183: openshell.v1.ListSandboxPoliciesResponse - (*ReportPolicyStatusRequest)(nil), // 184: openshell.v1.ReportPolicyStatusRequest - (*ReportPolicyStatusResponse)(nil), // 185: openshell.v1.ReportPolicyStatusResponse - (*SandboxConfigurationAdmission)(nil), // 186: openshell.v1.SandboxConfigurationAdmission - (*ReportSandboxConfigurationRequest)(nil), // 187: openshell.v1.ReportSandboxConfigurationRequest - (*ReportSandboxConfigurationResponse)(nil), // 188: openshell.v1.ReportSandboxConfigurationResponse - (*SandboxPolicyRevision)(nil), // 189: openshell.v1.SandboxPolicyRevision - (*GetSandboxLogsRequest)(nil), // 190: openshell.v1.GetSandboxLogsRequest - (*PushSandboxLogsRequest)(nil), // 191: openshell.v1.PushSandboxLogsRequest - (*PushSandboxLogsResponse)(nil), // 192: openshell.v1.PushSandboxLogsResponse - (*GetSandboxLogsResponse)(nil), // 193: openshell.v1.GetSandboxLogsResponse - (*SupervisorMessage)(nil), // 194: openshell.v1.SupervisorMessage - (*GatewayMessage)(nil), // 195: openshell.v1.GatewayMessage - (*SupervisorHello)(nil), // 196: openshell.v1.SupervisorHello - (*SessionAccepted)(nil), // 197: openshell.v1.SessionAccepted - (*ConfigUpdate)(nil), // 198: openshell.v1.ConfigUpdate - (*ConfigApplyFailure)(nil), // 199: openshell.v1.ConfigApplyFailure - (*ConfigUpdateResult)(nil), // 200: openshell.v1.ConfigUpdateResult - (*PolicyLoadResult)(nil), // 201: openshell.v1.PolicyLoadResult - (*SessionRejected)(nil), // 202: openshell.v1.SessionRejected - (*SessionRedirect)(nil), // 203: openshell.v1.SessionRedirect - (*SupervisorHeartbeat)(nil), // 204: openshell.v1.SupervisorHeartbeat - (*GatewayHeartbeat)(nil), // 205: openshell.v1.GatewayHeartbeat - (*ReportMainProcessExitRequest)(nil), // 206: openshell.v1.ReportMainProcessExitRequest - (*ReportMainProcessExitResponse)(nil), // 207: openshell.v1.ReportMainProcessExitResponse - (*FinalizeMainProcessExitRequest)(nil), // 208: openshell.v1.FinalizeMainProcessExitRequest - (*FinalizeMainProcessExitResponse)(nil), // 209: openshell.v1.FinalizeMainProcessExitResponse - (*RelayOpen)(nil), // 210: openshell.v1.RelayOpen - (*SshRelayTarget)(nil), // 211: openshell.v1.SshRelayTarget - (*TcpRelayTarget)(nil), // 212: openshell.v1.TcpRelayTarget - (*RelayInit)(nil), // 213: openshell.v1.RelayInit - (*RelayFrame)(nil), // 214: openshell.v1.RelayFrame - (*PeerRelayInit)(nil), // 215: openshell.v1.PeerRelayInit - (*PeerRelayFrame)(nil), // 216: openshell.v1.PeerRelayFrame - (*PeerConfigSandboxTarget)(nil), // 217: openshell.v1.PeerConfigSandboxTarget - (*PeerConfigProviderTarget)(nil), // 218: openshell.v1.PeerConfigProviderTarget - (*PeerNotifyConfigUpdateRequest)(nil), // 219: openshell.v1.PeerNotifyConfigUpdateRequest - (*PeerNotifyConfigUpdateResponse)(nil), // 220: openshell.v1.PeerNotifyConfigUpdateResponse - (*RelayOpenResult)(nil), // 221: openshell.v1.RelayOpenResult - (*RelayClose)(nil), // 222: openshell.v1.RelayClose - (*L7RequestSample)(nil), // 223: openshell.v1.L7RequestSample - (*DenialSummary)(nil), // 224: openshell.v1.DenialSummary - (*DenialGroupCount)(nil), // 225: openshell.v1.DenialGroupCount - (*NetworkActivitySummary)(nil), // 226: openshell.v1.NetworkActivitySummary - (*PolicyChunk)(nil), // 227: openshell.v1.PolicyChunk - (*DraftPolicyUpdate)(nil), // 228: openshell.v1.DraftPolicyUpdate - (*SubmitPolicyAnalysisRequest)(nil), // 229: openshell.v1.SubmitPolicyAnalysisRequest - (*SubmitPolicyAnalysisResponse)(nil), // 230: openshell.v1.SubmitPolicyAnalysisResponse - (*GetDraftPolicyRequest)(nil), // 231: openshell.v1.GetDraftPolicyRequest - (*GetDraftPolicyResponse)(nil), // 232: openshell.v1.GetDraftPolicyResponse - (*ApproveDraftChunkRequest)(nil), // 233: openshell.v1.ApproveDraftChunkRequest - (*ApproveDraftChunkResponse)(nil), // 234: openshell.v1.ApproveDraftChunkResponse - (*RejectDraftChunkRequest)(nil), // 235: openshell.v1.RejectDraftChunkRequest - (*RejectDraftChunkResponse)(nil), // 236: openshell.v1.RejectDraftChunkResponse - (*DraftChunkApproval)(nil), // 237: openshell.v1.DraftChunkApproval - (*ApproveAllDraftChunksRequest)(nil), // 238: openshell.v1.ApproveAllDraftChunksRequest - (*ApproveAllDraftChunksResponse)(nil), // 239: openshell.v1.ApproveAllDraftChunksResponse - (*EditDraftChunkRequest)(nil), // 240: openshell.v1.EditDraftChunkRequest - (*EditDraftChunkResponse)(nil), // 241: openshell.v1.EditDraftChunkResponse - (*UndoDraftChunkRequest)(nil), // 242: openshell.v1.UndoDraftChunkRequest - (*UndoDraftChunkResponse)(nil), // 243: openshell.v1.UndoDraftChunkResponse - (*ClearDraftChunksRequest)(nil), // 244: openshell.v1.ClearDraftChunksRequest - (*ClearDraftChunksResponse)(nil), // 245: openshell.v1.ClearDraftChunksResponse - (*GetDraftHistoryRequest)(nil), // 246: openshell.v1.GetDraftHistoryRequest - (*DraftHistoryEntry)(nil), // 247: openshell.v1.DraftHistoryEntry - (*GetDraftHistoryResponse)(nil), // 248: openshell.v1.GetDraftHistoryResponse - (*CreateWorkspaceRequest)(nil), // 249: openshell.v1.CreateWorkspaceRequest - (*CreateWorkspaceResponse)(nil), // 250: openshell.v1.CreateWorkspaceResponse - (*GetWorkspaceRequest)(nil), // 251: openshell.v1.GetWorkspaceRequest - (*GetWorkspaceResponse)(nil), // 252: openshell.v1.GetWorkspaceResponse - (*ListWorkspacesRequest)(nil), // 253: openshell.v1.ListWorkspacesRequest - (*ListWorkspacesResponse)(nil), // 254: openshell.v1.ListWorkspacesResponse - (*DeleteWorkspaceRequest)(nil), // 255: openshell.v1.DeleteWorkspaceRequest - (*DeleteWorkspaceResponse)(nil), // 256: openshell.v1.DeleteWorkspaceResponse - (*WorkspaceMember)(nil), // 257: openshell.v1.WorkspaceMember - (*AddWorkspaceMemberRequest)(nil), // 258: openshell.v1.AddWorkspaceMemberRequest - (*AddWorkspaceMemberResponse)(nil), // 259: openshell.v1.AddWorkspaceMemberResponse - (*RemoveWorkspaceMemberRequest)(nil), // 260: openshell.v1.RemoveWorkspaceMemberRequest - (*RemoveWorkspaceMemberResponse)(nil), // 261: openshell.v1.RemoveWorkspaceMemberResponse - (*ListWorkspaceMembersRequest)(nil), // 262: openshell.v1.ListWorkspaceMembersRequest - (*ListWorkspaceMembersResponse)(nil), // 263: openshell.v1.ListWorkspaceMembersResponse - (*ExtensionServiceCredential)(nil), // 264: openshell.v1.ExtensionServiceCredential - (*EndpointObservation)(nil), // 265: openshell.v1.EndpointObservation - (*ReportEndpointStatusRequest)(nil), // 266: openshell.v1.ReportEndpointStatusRequest - (*TokenGrantStatus)(nil), // 267: openshell.v1.TokenGrantStatus - (*TokenGrantFailureObservation)(nil), // 268: openshell.v1.TokenGrantFailureObservation - (*ReportEndpointStatusResponse)(nil), // 269: openshell.v1.ReportEndpointStatusResponse - (*EndpointStatus)(nil), // 270: openshell.v1.EndpointStatus - (*SandboxProvisioning)(nil), // 271: openshell.v1.SandboxProvisioning - (*SandboxServiceExposure)(nil), // 272: openshell.v1.SandboxServiceExposure - (*EndpointFailure)(nil), // 273: openshell.v1.EndpointFailure - nil, // 274: openshell.v1.SandboxSpec.EnvironmentEntry - nil, // 275: openshell.v1.SandboxTemplate.LabelsEntry - nil, // 276: openshell.v1.SandboxTemplate.AnnotationsEntry - nil, // 277: openshell.v1.SandboxTemplate.EnvironmentEntry - nil, // 278: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - nil, // 279: openshell.v1.PlatformEvent.MetadataEntry - nil, // 280: openshell.v1.CreateSandboxRequest.LabelsEntry - nil, // 281: openshell.v1.CreateSandboxRequest.AnnotationsEntry - nil, // 282: openshell.v1.SandboxResponse.ServiceUrlsEntry - nil, // 283: openshell.v1.ExecSandboxRequest.EnvironmentEntry - nil, // 284: openshell.v1.SandboxLogLine.FieldsEntry - nil, // 285: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry - nil, // 286: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - nil, // 287: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - nil, // 288: openshell.v1.ProviderProfile.AnnotationsEntry - nil, // 289: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - nil, // 290: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - nil, // 291: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - nil, // 292: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - nil, // 293: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - nil, // 294: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry - nil, // 295: openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - nil, // 296: openshell.v1.UpdateConfigRequest.AnnotationsEntry - nil, // 297: openshell.v1.UpdateConfigResponse.AnnotationsEntry - nil, // 298: openshell.v1.SandboxPolicyRevision.ProvenanceEntry - nil, // 299: openshell.v1.CreateWorkspaceRequest.LabelsEntry - (*timestamppb.Timestamp)(nil), // 300: google.protobuf.Timestamp - (*datamodelv1.ObjectMeta)(nil), // 301: openshell.datamodel.v1.ObjectMeta - (*sandboxv1.SandboxPolicy)(nil), // 302: openshell.sandbox.v1.SandboxPolicy - (*structpb.Struct)(nil), // 303: google.protobuf.Struct - (*durationpb.Duration)(nil), // 304: google.protobuf.Duration - (*datamodelv1.WorkspaceSelector)(nil), // 305: openshell.datamodel.v1.WorkspaceSelector - (*datamodelv1.Provider)(nil), // 306: openshell.datamodel.v1.Provider - (sandboxv1.PolicySource)(0), // 307: openshell.sandbox.v1.PolicySource - (*sandboxv1.NetworkEndpoint)(nil), // 308: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 309: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 310: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 311: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 312: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 313: openshell.sandbox.v1.L7Rule - (*sandboxv1.SandboxConfigSnapshot)(nil), // 314: openshell.sandbox.v1.SandboxConfigSnapshot - (*datamodelv1.Workspace)(nil), // 315: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 316: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 317: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 318: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 319: openshell.sandbox.v1.GetGatewayConfigResponse + (*SandboxCommandUpdate)(nil), // 56: openshell.v1.SandboxCommandUpdate + (*SandboxMapUpdate)(nil), // 57: openshell.v1.SandboxMapUpdate + (*CreateSandboxTemplateRequest)(nil), // 58: openshell.v1.CreateSandboxTemplateRequest + (*GetSandboxTemplateRequest)(nil), // 59: openshell.v1.GetSandboxTemplateRequest + (*ListSandboxTemplatesRequest)(nil), // 60: openshell.v1.ListSandboxTemplatesRequest + (*DeleteSandboxTemplateRequest)(nil), // 61: openshell.v1.DeleteSandboxTemplateRequest + (*SandboxTemplateResponse)(nil), // 62: openshell.v1.SandboxTemplateResponse + (*ListSandboxTemplatesResponse)(nil), // 63: openshell.v1.ListSandboxTemplatesResponse + (*DeleteSandboxTemplateResponse)(nil), // 64: openshell.v1.DeleteSandboxTemplateResponse + (*BeginRootfsTarStagingRequest)(nil), // 65: openshell.v1.BeginRootfsTarStagingRequest + (*BeginRootfsTarStagingResponse)(nil), // 66: openshell.v1.BeginRootfsTarStagingResponse + (*GetSandboxRequest)(nil), // 67: openshell.v1.GetSandboxRequest + (*ListSandboxesRequest)(nil), // 68: openshell.v1.ListSandboxesRequest + (*ListSandboxProvidersRequest)(nil), // 69: openshell.v1.ListSandboxProvidersRequest + (*AttachSandboxProviderRequest)(nil), // 70: openshell.v1.AttachSandboxProviderRequest + (*DetachSandboxProviderRequest)(nil), // 71: openshell.v1.DetachSandboxProviderRequest + (*DeleteSandboxRequest)(nil), // 72: openshell.v1.DeleteSandboxRequest + (*StopSandboxRequest)(nil), // 73: openshell.v1.StopSandboxRequest + (*StartSandboxRequest)(nil), // 74: openshell.v1.StartSandboxRequest + (*SuspendSandboxRequest)(nil), // 75: openshell.v1.SuspendSandboxRequest + (*ResumeSandboxRequest)(nil), // 76: openshell.v1.ResumeSandboxRequest + (*SandboxResponse)(nil), // 77: openshell.v1.SandboxResponse + (*ListSandboxesResponse)(nil), // 78: openshell.v1.ListSandboxesResponse + (*ListSandboxProvidersResponse)(nil), // 79: openshell.v1.ListSandboxProvidersResponse + (*AttachSandboxProviderResponse)(nil), // 80: openshell.v1.AttachSandboxProviderResponse + (*DetachSandboxProviderResponse)(nil), // 81: openshell.v1.DetachSandboxProviderResponse + (*ProviderDesiredIdentity)(nil), // 82: openshell.v1.ProviderDesiredIdentity + (*ConfigSnapshotRevision)(nil), // 83: openshell.v1.ConfigSnapshotRevision + (*SandboxConfigRevision)(nil), // 84: openshell.v1.SandboxConfigRevision + (*ConfigUpdateOperation)(nil), // 85: openshell.v1.ConfigUpdateOperation + (*ProviderMutationReceipt)(nil), // 86: openshell.v1.ProviderMutationReceipt + (*ProviderReadinessObservation)(nil), // 87: openshell.v1.ProviderReadinessObservation + (*ProviderReadinessStatus)(nil), // 88: openshell.v1.ProviderReadinessStatus + (*GetSandboxProviderStatusRequest)(nil), // 89: openshell.v1.GetSandboxProviderStatusRequest + (*GetSandboxProviderStatusResponse)(nil), // 90: openshell.v1.GetSandboxProviderStatusResponse + (*ReportProviderReadinessRequest)(nil), // 91: openshell.v1.ReportProviderReadinessRequest + (*ReportProviderReadinessResponse)(nil), // 92: openshell.v1.ReportProviderReadinessResponse + (*DeleteSandboxResponse)(nil), // 93: openshell.v1.DeleteSandboxResponse + (*CreateSshSessionRequest)(nil), // 94: openshell.v1.CreateSshSessionRequest + (*CreateSshSessionResponse)(nil), // 95: openshell.v1.CreateSshSessionResponse + (*ExposeServiceRequest)(nil), // 96: openshell.v1.ExposeServiceRequest + (*GetServiceRequest)(nil), // 97: openshell.v1.GetServiceRequest + (*ListServicesRequest)(nil), // 98: openshell.v1.ListServicesRequest + (*ListServicesResponse)(nil), // 99: openshell.v1.ListServicesResponse + (*DeleteServiceRequest)(nil), // 100: openshell.v1.DeleteServiceRequest + (*DeleteServiceResponse)(nil), // 101: openshell.v1.DeleteServiceResponse + (*ServiceEndpoint)(nil), // 102: openshell.v1.ServiceEndpoint + (*ServiceEndpointResponse)(nil), // 103: openshell.v1.ServiceEndpointResponse + (*RevokeSshSessionRequest)(nil), // 104: openshell.v1.RevokeSshSessionRequest + (*RevokeSshSessionResponse)(nil), // 105: openshell.v1.RevokeSshSessionResponse + (*ExecSandboxRequest)(nil), // 106: openshell.v1.ExecSandboxRequest + (*ExecSandboxStdout)(nil), // 107: openshell.v1.ExecSandboxStdout + (*ExecSandboxStderr)(nil), // 108: openshell.v1.ExecSandboxStderr + (*ExecSandboxExit)(nil), // 109: openshell.v1.ExecSandboxExit + (*ExecSandboxEvent)(nil), // 110: openshell.v1.ExecSandboxEvent + (*TcpForwardInit)(nil), // 111: openshell.v1.TcpForwardInit + (*TcpForwardFrame)(nil), // 112: openshell.v1.TcpForwardFrame + (*ExecSandboxInput)(nil), // 113: openshell.v1.ExecSandboxInput + (*ExecSandboxWindowResize)(nil), // 114: openshell.v1.ExecSandboxWindowResize + (*SshSession)(nil), // 115: openshell.v1.SshSession + (*WatchSandboxRequest)(nil), // 116: openshell.v1.WatchSandboxRequest + (*SandboxStreamEvent)(nil), // 117: openshell.v1.SandboxStreamEvent + (*SandboxLogLine)(nil), // 118: openshell.v1.SandboxLogLine + (*SandboxStreamWarning)(nil), // 119: openshell.v1.SandboxStreamWarning + (*CreateProviderRequest)(nil), // 120: openshell.v1.CreateProviderRequest + (*GetProviderRequest)(nil), // 121: openshell.v1.GetProviderRequest + (*GetProviderCredentialsRequest)(nil), // 122: openshell.v1.GetProviderCredentialsRequest + (*ProviderCredentialValue)(nil), // 123: openshell.v1.ProviderCredentialValue + (*GetProviderCredentialsResponse)(nil), // 124: openshell.v1.GetProviderCredentialsResponse + (*ListProvidersRequest)(nil), // 125: openshell.v1.ListProvidersRequest + (*UpdateProviderRequest)(nil), // 126: openshell.v1.UpdateProviderRequest + (*DeleteProviderRequest)(nil), // 127: openshell.v1.DeleteProviderRequest + (*ProviderResponse)(nil), // 128: openshell.v1.ProviderResponse + (*ListProvidersResponse)(nil), // 129: openshell.v1.ListProvidersResponse + (*ListProviderProfilesRequest)(nil), // 130: openshell.v1.ListProviderProfilesRequest + (*GetProviderProfileRequest)(nil), // 131: openshell.v1.GetProviderProfileRequest + (*ProviderProfileImportItem)(nil), // 132: openshell.v1.ProviderProfileImportItem + (*ProviderProfileDiagnostic)(nil), // 133: openshell.v1.ProviderProfileDiagnostic + (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 134: openshell.v1.ProviderCredentialTokenGrantAudienceOverride + (*ProviderCredentialTokenGrantSubjectToken)(nil), // 135: openshell.v1.ProviderCredentialTokenGrantSubjectToken + (*ProviderCredentialTokenGrant)(nil), // 136: openshell.v1.ProviderCredentialTokenGrant + (*ProviderProfileCredential)(nil), // 137: openshell.v1.ProviderProfileCredential + (*ProviderCredentialRefreshMaterial)(nil), // 138: openshell.v1.ProviderCredentialRefreshMaterial + (*ProviderCredentialRefreshOutput)(nil), // 139: openshell.v1.ProviderCredentialRefreshOutput + (*ProviderCredentialRefresh)(nil), // 140: openshell.v1.ProviderCredentialRefresh + (*ProviderCredentialRefreshStatus)(nil), // 141: openshell.v1.ProviderCredentialRefreshStatus + (*ProviderProfileDiscovery)(nil), // 142: openshell.v1.ProviderProfileDiscovery + (*GetProviderRefreshStatusRequest)(nil), // 143: openshell.v1.GetProviderRefreshStatusRequest + (*GetProviderRefreshStatusResponse)(nil), // 144: openshell.v1.GetProviderRefreshStatusResponse + (*ConfigureProviderRefreshRequest)(nil), // 145: openshell.v1.ConfigureProviderRefreshRequest + (*ConfigureProviderRefreshResponse)(nil), // 146: openshell.v1.ConfigureProviderRefreshResponse + (*RotateProviderCredentialRequest)(nil), // 147: openshell.v1.RotateProviderCredentialRequest + (*RotateProviderCredentialResponse)(nil), // 148: openshell.v1.RotateProviderCredentialResponse + (*DeleteProviderRefreshRequest)(nil), // 149: openshell.v1.DeleteProviderRefreshRequest + (*DeleteProviderRefreshResponse)(nil), // 150: openshell.v1.DeleteProviderRefreshResponse + (*ProviderProfile)(nil), // 151: openshell.v1.ProviderProfile + (*ProviderProfileFile)(nil), // 152: openshell.v1.ProviderProfileFile + (*ProviderProfileResponse)(nil), // 153: openshell.v1.ProviderProfileResponse + (*ListProviderProfilesResponse)(nil), // 154: openshell.v1.ListProviderProfilesResponse + (*ImportProviderProfilesRequest)(nil), // 155: openshell.v1.ImportProviderProfilesRequest + (*ImportProviderProfilesResponse)(nil), // 156: openshell.v1.ImportProviderProfilesResponse + (*UpdateProviderProfilesRequest)(nil), // 157: openshell.v1.UpdateProviderProfilesRequest + (*UpdateProviderProfilesResponse)(nil), // 158: openshell.v1.UpdateProviderProfilesResponse + (*LintProviderProfilesRequest)(nil), // 159: openshell.v1.LintProviderProfilesRequest + (*LintProviderProfilesResponse)(nil), // 160: openshell.v1.LintProviderProfilesResponse + (*DeleteProviderResponse)(nil), // 161: openshell.v1.DeleteProviderResponse + (*DeleteProviderProfileRequest)(nil), // 162: openshell.v1.DeleteProviderProfileRequest + (*DeleteProviderProfileResponse)(nil), // 163: openshell.v1.DeleteProviderProfileResponse + (*GetSandboxProviderEnvironmentRequest)(nil), // 164: openshell.v1.GetSandboxProviderEnvironmentRequest + (*StaticCredentialEndpointBinding)(nil), // 165: openshell.v1.StaticCredentialEndpointBinding + (*StaticCredentialBinding)(nil), // 166: openshell.v1.StaticCredentialBinding + (*GetSandboxProviderEnvironmentResponse)(nil), // 167: openshell.v1.GetSandboxProviderEnvironmentResponse + (*ProviderEnvironmentValue)(nil), // 168: openshell.v1.ProviderEnvironmentValue + (*ProviderEnvironmentSnapshot)(nil), // 169: openshell.v1.ProviderEnvironmentSnapshot + (*ExchangeProviderSubjectTokenRequest)(nil), // 170: openshell.v1.ExchangeProviderSubjectTokenRequest + (*ExchangeProviderSubjectTokenResponse)(nil), // 171: openshell.v1.ExchangeProviderSubjectTokenResponse + (*UpdateConfigRequest)(nil), // 172: openshell.v1.UpdateConfigRequest + (*PolicyMergeOperation)(nil), // 173: openshell.v1.PolicyMergeOperation + (*AddNetworkRule)(nil), // 174: openshell.v1.AddNetworkRule + (*RemoveNetworkEndpoint)(nil), // 175: openshell.v1.RemoveNetworkEndpoint + (*RemoveNetworkRule)(nil), // 176: openshell.v1.RemoveNetworkRule + (*L7RuleTarget)(nil), // 177: openshell.v1.L7RuleTarget + (*AddDenyRules)(nil), // 178: openshell.v1.AddDenyRules + (*AddAllowRules)(nil), // 179: openshell.v1.AddAllowRules + (*RemoveNetworkBinary)(nil), // 180: openshell.v1.RemoveNetworkBinary + (*UpdateConfigResponse)(nil), // 181: openshell.v1.UpdateConfigResponse + (*GetSandboxPolicyStatusRequest)(nil), // 182: openshell.v1.GetSandboxPolicyStatusRequest + (*GetSandboxPolicyStatusResponse)(nil), // 183: openshell.v1.GetSandboxPolicyStatusResponse + (*ListSandboxPoliciesRequest)(nil), // 184: openshell.v1.ListSandboxPoliciesRequest + (*ListSandboxPoliciesResponse)(nil), // 185: openshell.v1.ListSandboxPoliciesResponse + (*ReportPolicyStatusRequest)(nil), // 186: openshell.v1.ReportPolicyStatusRequest + (*ReportPolicyStatusResponse)(nil), // 187: openshell.v1.ReportPolicyStatusResponse + (*SandboxConfigurationAdmission)(nil), // 188: openshell.v1.SandboxConfigurationAdmission + (*ReportSandboxConfigurationRequest)(nil), // 189: openshell.v1.ReportSandboxConfigurationRequest + (*ReportSandboxConfigurationResponse)(nil), // 190: openshell.v1.ReportSandboxConfigurationResponse + (*SandboxPolicyRevision)(nil), // 191: openshell.v1.SandboxPolicyRevision + (*GetSandboxLogsRequest)(nil), // 192: openshell.v1.GetSandboxLogsRequest + (*PushSandboxLogsRequest)(nil), // 193: openshell.v1.PushSandboxLogsRequest + (*PushSandboxLogsResponse)(nil), // 194: openshell.v1.PushSandboxLogsResponse + (*GetSandboxLogsResponse)(nil), // 195: openshell.v1.GetSandboxLogsResponse + (*SupervisorMessage)(nil), // 196: openshell.v1.SupervisorMessage + (*GatewayMessage)(nil), // 197: openshell.v1.GatewayMessage + (*SupervisorHello)(nil), // 198: openshell.v1.SupervisorHello + (*SessionAccepted)(nil), // 199: openshell.v1.SessionAccepted + (*ConfigUpdate)(nil), // 200: openshell.v1.ConfigUpdate + (*ConfigApplyFailure)(nil), // 201: openshell.v1.ConfigApplyFailure + (*ConfigUpdateResult)(nil), // 202: openshell.v1.ConfigUpdateResult + (*PolicyLoadResult)(nil), // 203: openshell.v1.PolicyLoadResult + (*SessionRejected)(nil), // 204: openshell.v1.SessionRejected + (*SessionRedirect)(nil), // 205: openshell.v1.SessionRedirect + (*SupervisorHeartbeat)(nil), // 206: openshell.v1.SupervisorHeartbeat + (*GatewayHeartbeat)(nil), // 207: openshell.v1.GatewayHeartbeat + (*ReportMainProcessExitRequest)(nil), // 208: openshell.v1.ReportMainProcessExitRequest + (*ReportMainProcessExitResponse)(nil), // 209: openshell.v1.ReportMainProcessExitResponse + (*FinalizeMainProcessExitRequest)(nil), // 210: openshell.v1.FinalizeMainProcessExitRequest + (*FinalizeMainProcessExitResponse)(nil), // 211: openshell.v1.FinalizeMainProcessExitResponse + (*RelayOpen)(nil), // 212: openshell.v1.RelayOpen + (*SshRelayTarget)(nil), // 213: openshell.v1.SshRelayTarget + (*TcpRelayTarget)(nil), // 214: openshell.v1.TcpRelayTarget + (*RelayInit)(nil), // 215: openshell.v1.RelayInit + (*RelayFrame)(nil), // 216: openshell.v1.RelayFrame + (*PeerRelayInit)(nil), // 217: openshell.v1.PeerRelayInit + (*PeerRelayFrame)(nil), // 218: openshell.v1.PeerRelayFrame + (*PeerConfigSandboxTarget)(nil), // 219: openshell.v1.PeerConfigSandboxTarget + (*PeerConfigProviderTarget)(nil), // 220: openshell.v1.PeerConfigProviderTarget + (*PeerNotifyConfigUpdateRequest)(nil), // 221: openshell.v1.PeerNotifyConfigUpdateRequest + (*PeerNotifyConfigUpdateResponse)(nil), // 222: openshell.v1.PeerNotifyConfigUpdateResponse + (*RelayOpenResult)(nil), // 223: openshell.v1.RelayOpenResult + (*RelayClose)(nil), // 224: openshell.v1.RelayClose + (*L7RequestSample)(nil), // 225: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 226: openshell.v1.DenialSummary + (*DenialGroupCount)(nil), // 227: openshell.v1.DenialGroupCount + (*NetworkActivitySummary)(nil), // 228: openshell.v1.NetworkActivitySummary + (*PolicyChunk)(nil), // 229: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 230: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 231: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 232: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 233: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 234: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 235: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 236: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 237: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 238: openshell.v1.RejectDraftChunkResponse + (*DraftChunkApproval)(nil), // 239: openshell.v1.DraftChunkApproval + (*ApproveAllDraftChunksRequest)(nil), // 240: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 241: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 242: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 243: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 244: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 245: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 246: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 247: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 248: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 249: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 250: openshell.v1.GetDraftHistoryResponse + (*CreateWorkspaceRequest)(nil), // 251: openshell.v1.CreateWorkspaceRequest + (*CreateWorkspaceResponse)(nil), // 252: openshell.v1.CreateWorkspaceResponse + (*GetWorkspaceRequest)(nil), // 253: openshell.v1.GetWorkspaceRequest + (*GetWorkspaceResponse)(nil), // 254: openshell.v1.GetWorkspaceResponse + (*ListWorkspacesRequest)(nil), // 255: openshell.v1.ListWorkspacesRequest + (*ListWorkspacesResponse)(nil), // 256: openshell.v1.ListWorkspacesResponse + (*DeleteWorkspaceRequest)(nil), // 257: openshell.v1.DeleteWorkspaceRequest + (*DeleteWorkspaceResponse)(nil), // 258: openshell.v1.DeleteWorkspaceResponse + (*WorkspaceMember)(nil), // 259: openshell.v1.WorkspaceMember + (*AddWorkspaceMemberRequest)(nil), // 260: openshell.v1.AddWorkspaceMemberRequest + (*AddWorkspaceMemberResponse)(nil), // 261: openshell.v1.AddWorkspaceMemberResponse + (*RemoveWorkspaceMemberRequest)(nil), // 262: openshell.v1.RemoveWorkspaceMemberRequest + (*RemoveWorkspaceMemberResponse)(nil), // 263: openshell.v1.RemoveWorkspaceMemberResponse + (*ListWorkspaceMembersRequest)(nil), // 264: openshell.v1.ListWorkspaceMembersRequest + (*ListWorkspaceMembersResponse)(nil), // 265: openshell.v1.ListWorkspaceMembersResponse + (*ExtensionServiceCredential)(nil), // 266: openshell.v1.ExtensionServiceCredential + (*EndpointObservation)(nil), // 267: openshell.v1.EndpointObservation + (*ReportEndpointStatusRequest)(nil), // 268: openshell.v1.ReportEndpointStatusRequest + (*TokenGrantStatus)(nil), // 269: openshell.v1.TokenGrantStatus + (*TokenGrantFailureObservation)(nil), // 270: openshell.v1.TokenGrantFailureObservation + (*ReportEndpointStatusResponse)(nil), // 271: openshell.v1.ReportEndpointStatusResponse + (*EndpointStatus)(nil), // 272: openshell.v1.EndpointStatus + (*SandboxProvisioning)(nil), // 273: openshell.v1.SandboxProvisioning + (*SandboxServiceExposure)(nil), // 274: openshell.v1.SandboxServiceExposure + (*EndpointFailure)(nil), // 275: openshell.v1.EndpointFailure + nil, // 276: openshell.v1.SandboxSpec.EnvironmentEntry + nil, // 277: openshell.v1.SandboxTemplate.LabelsEntry + nil, // 278: openshell.v1.SandboxTemplate.AnnotationsEntry + nil, // 279: openshell.v1.SandboxTemplate.EnvironmentEntry + nil, // 280: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + nil, // 281: openshell.v1.PlatformEvent.MetadataEntry + nil, // 282: openshell.v1.CreateSandboxRequest.LabelsEntry + nil, // 283: openshell.v1.CreateSandboxRequest.AnnotationsEntry + nil, // 284: openshell.v1.SandboxMapUpdate.ValuesEntry + nil, // 285: openshell.v1.SandboxResponse.ServiceUrlsEntry + nil, // 286: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 287: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 288: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry + nil, // 289: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + nil, // 290: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + nil, // 291: openshell.v1.ProviderProfile.AnnotationsEntry + nil, // 292: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + nil, // 293: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + nil, // 294: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + nil, // 295: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + nil, // 296: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + nil, // 297: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + nil, // 298: openshell.v1.ProviderEnvironmentSnapshot.FilesEntry + nil, // 299: openshell.v1.UpdateConfigRequest.AnnotationsEntry + nil, // 300: openshell.v1.UpdateConfigResponse.AnnotationsEntry + nil, // 301: openshell.v1.SandboxPolicyRevision.ProvenanceEntry + nil, // 302: openshell.v1.CreateWorkspaceRequest.LabelsEntry + (*timestamppb.Timestamp)(nil), // 303: google.protobuf.Timestamp + (*datamodelv1.ObjectMeta)(nil), // 304: openshell.datamodel.v1.ObjectMeta + (*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 } var file_openshell_proto_depIdxs = []int32{ - 300, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 300, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 264, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential - 300, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp + 303, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 303, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 266, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential + 303, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp 14, // 4: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus 14, // 5: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus 33, // 6: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo @@ -21773,533 +21913,538 @@ var file_openshell_proto_depIdxs = []int32{ 36, // 11: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities 37, // 12: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities 38, // 13: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities - 301, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 304, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 40, // 15: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec 51, // 16: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus 50, // 17: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance - 274, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry + 276, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry 43, // 19: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate - 302, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 305, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy 41, // 21: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements 17, // 22: openshell.v1.SandboxSpec.restart_policy:type_name -> openshell.v1.SandboxRestartPolicy 42, // 23: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements - 275, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry - 276, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry - 277, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry - 303, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct - 303, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct - 301, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 277, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry + 278, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry + 279, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry + 306, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 306, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct + 304, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 45, // 30: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec 46, // 31: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig - 303, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct + 306, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct 48, // 33: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel - 278, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + 280, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry 47, // 35: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources 42, // 36: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements 49, // 37: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup - 304, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 307, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration 52, // 39: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition 1, // 40: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 270, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus - 186, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 271, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning - 300, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp - 300, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp - 268, // 46: openshell.v1.SandboxStatus.last_token_grant_failure:type_name -> openshell.v1.TokenGrantFailureObservation - 300, // 47: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp - 300, // 48: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp - 279, // 49: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 305, // 50: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 272, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus + 188, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 273, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning + 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 - 280, // 52: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 281, // 53: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 272, // 54: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure - 305, // 55: openshell.v1.UpdateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 56: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 44, // 57: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 305, // 58: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 59: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 60: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 44, // 61: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 44, // 62: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate - 18, // 63: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 305, // 64: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 300, // 65: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp - 305, // 66: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 67: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 68: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 69: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 70: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 71: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 72: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 73: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 74: openshell.v1.SuspendSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 75: openshell.v1.ResumeSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 39, // 76: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 282, // 77: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry - 39, // 78: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 306, // 79: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 39, // 80: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 84, // 81: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 39, // 82: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 84, // 83: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 82, // 84: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision - 80, // 85: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity - 307, // 86: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource - 5, // 87: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent - 81, // 88: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision - 7, // 89: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState - 6, // 90: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 300, // 91: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp - 300, // 92: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp - 300, // 93: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp - 2, // 94: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind - 80, // 95: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity - 300, // 96: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp - 4, // 97: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason - 84, // 98: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 3, // 99: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState - 4, // 100: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason - 85, // 101: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation - 300, // 102: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp - 300, // 103: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp - 83, // 104: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation - 305, // 105: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 86, // 106: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus - 85, // 107: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation - 304, // 108: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration - 304, // 109: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration - 18, // 110: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 305, // 111: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 300, // 112: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp - 305, // 113: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 20, // 114: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 305, // 115: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 116: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 101, // 117: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 305, // 118: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 119: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 301, // 120: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 20, // 121: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 100, // 122: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint - 18, // 123: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 305, // 124: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 283, // 125: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 304, // 126: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration - 105, // 127: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout - 106, // 128: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr - 107, // 129: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 211, // 130: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 212, // 131: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget - 109, // 132: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit - 104, // 133: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest - 112, // 134: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 301, // 135: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 300, // 136: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp - 305, // 137: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 300, // 138: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp - 39, // 139: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox - 116, // 140: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine - 53, // 141: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent - 117, // 142: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 228, // 143: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 300, // 144: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp - 284, // 145: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 305, // 146: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 147: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 305, // 148: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 149: openshell.v1.GetProviderCredentialsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 304, // 150: openshell.v1.GetProviderCredentialsRequest.minimum_remaining_lifetime:type_name -> google.protobuf.Duration - 300, // 151: openshell.v1.ProviderCredentialValue.expiration_time:type_name -> google.protobuf.Timestamp - 285, // 152: openshell.v1.GetProviderCredentialsResponse.credentials:type_name -> openshell.v1.GetProviderCredentialsResponse.CredentialsEntry - 305, // 153: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 154: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 155: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 286, // 156: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - 305, // 157: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 306, // 158: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider - 84, // 159: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt - 306, // 160: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 305, // 161: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 162: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 149, // 163: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 304, // 164: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration - 132, // 165: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride - 8, // 166: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType - 133, // 167: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken - 138, // 168: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh - 134, // 169: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant - 9, // 170: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 304, // 171: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration - 304, // 172: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration - 136, // 173: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial - 137, // 174: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput - 9, // 175: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 300, // 176: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp - 300, // 177: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp - 300, // 178: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp - 16, // 179: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 300, // 180: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp - 305, // 181: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 139, // 182: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 305, // 183: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 9, // 184: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 287, // 185: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 300, // 186: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp - 139, // 187: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 305, // 188: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 139, // 189: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 305, // 190: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 191: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 10, // 192: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory - 135, // 193: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 308, // 194: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 309, // 195: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 140, // 196: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 288, // 197: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 150, // 198: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile - 149, // 199: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 149, // 200: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 305, // 201: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 130, // 202: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 131, // 203: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 149, // 204: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 305, // 205: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 130, // 206: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 131, // 207: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 149, // 208: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 305, // 209: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 130, // 210: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 131, // 211: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 18, // 212: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 305, // 213: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 214: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 163, // 215: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 289, // 216: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 290, // 217: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - 291, // 218: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 292, // 219: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 4, // 220: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 293, // 221: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - 11, // 222: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification - 164, // 223: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding - 300, // 224: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp - 166, // 225: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue - 294, // 226: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry - 4, // 227: openshell.v1.ProviderEnvironmentSnapshot.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 295, // 228: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - 304, // 229: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration - 305, // 230: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 231: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 310, // 232: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 171, // 233: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 296, // 234: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 172, // 235: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 173, // 236: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 174, // 237: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 176, // 238: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 177, // 239: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 178, // 240: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 311, // 241: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 309, // 242: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 312, // 243: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 175, // 244: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget - 313, // 245: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 175, // 246: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget - 297, // 247: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 305, // 248: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 189, // 249: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 305, // 250: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 189, // 251: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 13, // 252: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 12, // 253: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState - 186, // 254: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 13, // 255: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 300, // 256: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp - 300, // 257: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp - 302, // 258: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 298, // 259: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 305, // 260: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 300, // 261: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp - 116, // 262: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 116, // 263: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 196, // 264: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 204, // 265: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 221, // 266: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 222, // 267: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 200, // 268: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult - 197, // 269: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 202, // 270: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 205, // 271: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 210, // 272: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 222, // 273: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 203, // 274: openshell.v1.GatewayMessage.session_redirect:type_name -> openshell.v1.SessionRedirect - 198, // 275: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate - 198, // 276: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigUpdate - 304, // 277: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration - 314, // 278: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot - 167, // 279: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot - 6, // 280: openshell.v1.ConfigUpdateResult.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 199, // 281: openshell.v1.ConfigUpdateResult.failure:type_name -> openshell.v1.ConfigApplyFailure - 186, // 282: openshell.v1.ConfigUpdateResult.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 201, // 283: openshell.v1.ConfigUpdateResult.policy_load:type_name -> openshell.v1.PolicyLoadResult - 211, // 284: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 212, // 285: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 213, // 286: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 210, // 287: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen - 215, // 288: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit - 217, // 289: openshell.v1.PeerNotifyConfigUpdateRequest.sandbox:type_name -> openshell.v1.PeerConfigSandboxTarget - 218, // 290: openshell.v1.PeerNotifyConfigUpdateRequest.provider:type_name -> openshell.v1.PeerConfigProviderTarget - 300, // 291: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp - 300, // 292: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp - 223, // 293: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 225, // 294: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 311, // 295: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 300, // 296: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp - 300, // 297: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp - 300, // 298: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp - 300, // 299: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp - 302, // 300: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 302, // 301: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 305, // 302: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 224, // 303: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 227, // 304: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 226, // 305: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 305, // 306: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 227, // 307: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 300, // 308: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp - 305, // 309: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 310: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 311: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 237, // 312: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval - 305, // 313: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 311, // 314: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 305, // 315: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 316: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 305, // 317: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 300, // 318: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp - 247, // 319: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 299, // 320: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 315, // 321: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 315, // 322: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 315, // 323: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 18, // 324: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 301, // 325: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 15, // 326: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 305, // 327: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 15, // 328: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 257, // 329: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 305, // 330: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 331: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 305, // 332: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 257, // 333: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 300, // 334: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp - 19, // 335: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult - 273, // 336: openshell.v1.EndpointObservation.failure:type_name -> openshell.v1.EndpointFailure - 265, // 337: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation - 267, // 338: openshell.v1.ReportEndpointStatusRequest.token_grant_status:type_name -> openshell.v1.TokenGrantStatus - 268, // 339: openshell.v1.TokenGrantStatus.last_failure:type_name -> openshell.v1.TokenGrantFailureObservation - 273, // 340: openshell.v1.TokenGrantFailureObservation.failure:type_name -> openshell.v1.EndpointFailure - 19, // 341: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult - 300, // 342: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp - 273, // 343: openshell.v1.EndpointStatus.last_failure:type_name -> openshell.v1.EndpointFailure - 300, // 344: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp - 300, // 345: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp - 300, // 346: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp - 300, // 347: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp - 300, // 348: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp - 300, // 349: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp - 300, // 350: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp - 300, // 351: openshell.v1.SandboxProvisioning.preparation_deadline:type_name -> google.protobuf.Timestamp - 300, // 352: openshell.v1.SandboxProvisioning.admission_start_time:type_name -> google.protobuf.Timestamp - 20, // 353: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 21, // 354: openshell.v1.EndpointFailure.domain:type_name -> openshell.v1.EndpointFailureDomain - 16, // 355: openshell.v1.EndpointFailure.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 121, // 356: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry.value:type_name -> openshell.v1.ProviderCredentialValue - 300, // 357: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 300, // 358: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 135, // 359: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 164, // 360: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 135, // 361: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 26, // 362: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 28, // 363: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 30, // 364: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 54, // 365: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 63, // 366: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest - 65, // 367: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 66, // 368: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 56, // 369: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 57, // 370: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 58, // 371: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 59, // 372: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 67, // 373: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 68, // 374: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 69, // 375: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 87, // 376: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 70, // 377: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 71, // 378: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 72, // 379: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 73, // 380: openshell.v1.OpenShell.SuspendSandbox:input_type -> openshell.v1.SuspendSandboxRequest - 74, // 381: openshell.v1.OpenShell.ResumeSandbox:input_type -> openshell.v1.ResumeSandboxRequest - 92, // 382: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 94, // 383: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 95, // 384: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 96, // 385: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 98, // 386: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 102, // 387: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 104, // 388: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 110, // 389: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 111, // 390: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 118, // 391: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 119, // 392: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 120, // 393: openshell.v1.OpenShell.GetProviderCredentials:input_type -> openshell.v1.GetProviderCredentialsRequest - 123, // 394: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 128, // 395: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 129, // 396: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 153, // 397: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 155, // 398: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 157, // 399: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 124, // 400: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 141, // 401: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 143, // 402: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 145, // 403: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 147, // 404: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 125, // 405: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 160, // 406: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 316, // 407: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 317, // 408: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 170, // 409: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 180, // 410: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 182, // 411: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 184, // 412: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 266, // 413: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 89, // 414: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 187, // 415: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest - 162, // 416: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 168, // 417: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest - 190, // 418: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 191, // 419: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 194, // 420: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 206, // 421: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest - 208, // 422: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest - 214, // 423: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 216, // 424: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame - 89, // 425: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 266, // 426: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 87, // 427: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 219, // 428: openshell.v1.OpenShell.PeerNotifyConfigUpdate:input_type -> openshell.v1.PeerNotifyConfigUpdateRequest - 114, // 429: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 229, // 430: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 231, // 431: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 233, // 432: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 235, // 433: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 238, // 434: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 240, // 435: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 242, // 436: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 244, // 437: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 246, // 438: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 22, // 439: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 24, // 440: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 249, // 441: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 251, // 442: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 253, // 443: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 255, // 444: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 258, // 445: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 260, // 446: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 262, // 447: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 55, // 448: openshell.v1.SandboxUpdates.UpdateSandbox:input_type -> openshell.v1.UpdateSandboxRequest - 27, // 449: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 29, // 450: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 31, // 451: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 75, // 452: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 64, // 453: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse - 75, // 454: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 76, // 455: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 60, // 456: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 60, // 457: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 61, // 458: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 62, // 459: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 77, // 460: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 78, // 461: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 79, // 462: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 88, // 463: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 91, // 464: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 75, // 465: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 75, // 466: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 75, // 467: openshell.v1.OpenShell.SuspendSandbox:output_type -> openshell.v1.SandboxResponse - 75, // 468: openshell.v1.OpenShell.ResumeSandbox:output_type -> openshell.v1.SandboxResponse - 93, // 469: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 101, // 470: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 101, // 471: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 97, // 472: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 99, // 473: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 103, // 474: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 108, // 475: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 110, // 476: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 108, // 477: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 126, // 478: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 126, // 479: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 122, // 480: openshell.v1.OpenShell.GetProviderCredentials:output_type -> openshell.v1.GetProviderCredentialsResponse - 127, // 481: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 152, // 482: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 151, // 483: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 154, // 484: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 156, // 485: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 158, // 486: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 126, // 487: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 142, // 488: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 144, // 489: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 146, // 490: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 148, // 491: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 159, // 492: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 161, // 493: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 318, // 494: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 319, // 495: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 179, // 496: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 181, // 497: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 183, // 498: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 185, // 499: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 269, // 500: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 90, // 501: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 188, // 502: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse - 165, // 503: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 169, // 504: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse - 193, // 505: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 192, // 506: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 195, // 507: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 207, // 508: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse - 209, // 509: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse - 214, // 510: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 216, // 511: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame - 90, // 512: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 269, // 513: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 88, // 514: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 220, // 515: openshell.v1.OpenShell.PeerNotifyConfigUpdate:output_type -> openshell.v1.PeerNotifyConfigUpdateResponse - 115, // 516: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 230, // 517: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 232, // 518: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 234, // 519: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 236, // 520: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 239, // 521: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 241, // 522: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 243, // 523: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 245, // 524: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 248, // 525: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 23, // 526: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 25, // 527: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 250, // 528: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 252, // 529: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 254, // 530: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 256, // 531: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 259, // 532: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 261, // 533: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 263, // 534: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 75, // 535: openshell.v1.SandboxUpdates.UpdateSandbox:output_type -> openshell.v1.SandboxResponse - 449, // [449:536] is the sub-list for method output_type - 362, // [362:449] is the sub-list for method input_type - 362, // [362:362] is the sub-list for extension type_name - 362, // [362:362] is the sub-list for extension extendee - 0, // [0:362] is the sub-list for field type_name + 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 } func init() { file_openshell_proto_init() } @@ -22310,37 +22455,38 @@ func file_openshell_proto_init() { file_openshell_proto_msgTypes[20].OneofWrappers = []any{} file_openshell_proto_msgTypes[21].OneofWrappers = []any{} file_openshell_proto_msgTypes[29].OneofWrappers = []any{} - file_openshell_proto_msgTypes[59].OneofWrappers = []any{ + file_openshell_proto_msgTypes[33].OneofWrappers = []any{} + file_openshell_proto_msgTypes[61].OneofWrappers = []any{ (*ConfigSnapshotRevision_SandboxConfig)(nil), (*ConfigSnapshotRevision_ProviderEnvironment)(nil), (*ConfigSnapshotRevision_ProviderTarget)(nil), } - file_openshell_proto_msgTypes[86].OneofWrappers = []any{ + file_openshell_proto_msgTypes[88].OneofWrappers = []any{ (*ExecSandboxEvent_Stdout)(nil), (*ExecSandboxEvent_Stderr)(nil), (*ExecSandboxEvent_Exit)(nil), } - file_openshell_proto_msgTypes[87].OneofWrappers = []any{ + file_openshell_proto_msgTypes[89].OneofWrappers = []any{ (*TcpForwardInit_Ssh)(nil), (*TcpForwardInit_Tcp)(nil), } - file_openshell_proto_msgTypes[88].OneofWrappers = []any{ + file_openshell_proto_msgTypes[90].OneofWrappers = []any{ (*TcpForwardFrame_Init)(nil), (*TcpForwardFrame_Data)(nil), } - file_openshell_proto_msgTypes[89].OneofWrappers = []any{ + file_openshell_proto_msgTypes[91].OneofWrappers = []any{ (*ExecSandboxInput_Start)(nil), (*ExecSandboxInput_Stdin)(nil), (*ExecSandboxInput_Resize)(nil), } - file_openshell_proto_msgTypes[93].OneofWrappers = []any{ + file_openshell_proto_msgTypes[95].OneofWrappers = []any{ (*SandboxStreamEvent_Sandbox)(nil), (*SandboxStreamEvent_Log)(nil), (*SandboxStreamEvent_Event)(nil), (*SandboxStreamEvent_Warning)(nil), (*SandboxStreamEvent_DraftPolicyUpdate)(nil), } - file_openshell_proto_msgTypes[149].OneofWrappers = []any{ + file_openshell_proto_msgTypes[151].OneofWrappers = []any{ (*PolicyMergeOperation_AddRule)(nil), (*PolicyMergeOperation_RemoveEndpoint)(nil), (*PolicyMergeOperation_RemoveRule)(nil), @@ -22348,15 +22494,15 @@ func file_openshell_proto_init() { (*PolicyMergeOperation_AddAllowRules)(nil), (*PolicyMergeOperation_RemoveBinary)(nil), } - file_openshell_proto_msgTypes[153].OneofWrappers = []any{} - file_openshell_proto_msgTypes[172].OneofWrappers = []any{ + file_openshell_proto_msgTypes[155].OneofWrappers = []any{} + file_openshell_proto_msgTypes[174].OneofWrappers = []any{ (*SupervisorMessage_Hello)(nil), (*SupervisorMessage_Heartbeat)(nil), (*SupervisorMessage_RelayOpenResult)(nil), (*SupervisorMessage_RelayClose)(nil), (*SupervisorMessage_ConfigUpdateResult)(nil), } - file_openshell_proto_msgTypes[173].OneofWrappers = []any{ + file_openshell_proto_msgTypes[175].OneofWrappers = []any{ (*GatewayMessage_SessionAccepted)(nil), (*GatewayMessage_SessionRejected)(nil), (*GatewayMessage_Heartbeat)(nil), @@ -22365,32 +22511,32 @@ func file_openshell_proto_init() { (*GatewayMessage_SessionRedirect)(nil), (*GatewayMessage_ConfigUpdate)(nil), } - file_openshell_proto_msgTypes[188].OneofWrappers = []any{ + file_openshell_proto_msgTypes[190].OneofWrappers = []any{ (*RelayOpen_Ssh)(nil), (*RelayOpen_Tcp)(nil), } - file_openshell_proto_msgTypes[192].OneofWrappers = []any{ + file_openshell_proto_msgTypes[194].OneofWrappers = []any{ (*RelayFrame_Init)(nil), (*RelayFrame_Data)(nil), } - file_openshell_proto_msgTypes[194].OneofWrappers = []any{ + file_openshell_proto_msgTypes[196].OneofWrappers = []any{ (*PeerRelayFrame_Init)(nil), (*PeerRelayFrame_Data)(nil), } - file_openshell_proto_msgTypes[197].OneofWrappers = []any{ + file_openshell_proto_msgTypes[199].OneofWrappers = []any{ (*PeerNotifyConfigUpdateRequest_Sandbox)(nil), (*PeerNotifyConfigUpdateRequest_Workspace)(nil), (*PeerNotifyConfigUpdateRequest_AllConnected)(nil), (*PeerNotifyConfigUpdateRequest_Provider)(nil), } - file_openshell_proto_msgTypes[251].OneofWrappers = []any{} + file_openshell_proto_msgTypes[253].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_openshell_proto_rawDesc), len(file_openshell_proto_rawDesc)), NumEnums: 22, - NumMessages: 278, + NumMessages: 281, NumExtensions: 0, NumServices: 2, }, diff --git a/sdk/go/proto/openshellv1/openshell_grpc.pb.go b/sdk/go/proto/openshellv1/openshell_grpc.pb.go index 823a41fc36..fbba50b84c 100644 --- a/sdk/go/proto/openshellv1/openshell_grpc.pb.go +++ b/sdk/go/proto/openshellv1/openshell_grpc.pb.go @@ -3647,9 +3647,10 @@ const ( // Optional sandbox mutations are separate from OpenShell so existing generated // OpenShell server implementations remain source-compatible. type SandboxUpdatesClient interface { - // Update only the workload image of a stopped sandbox without deleting its - // identity or retained storage. Requires compute-driver image-update support - // and explicit gateway activation of sandbox image updates. + // Update the workload image, command, environment, labels, or annotations of a + // stopped sandbox while preserving its identity and retained storage. Requires + // compute-driver support for the selected changes and explicit gateway activation + // of sandbox updates. UpdateSandbox(ctx context.Context, in *UpdateSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) } @@ -3678,9 +3679,10 @@ func (c *sandboxUpdatesClient) UpdateSandbox(ctx context.Context, in *UpdateSand // Optional sandbox mutations are separate from OpenShell so existing generated // OpenShell server implementations remain source-compatible. type SandboxUpdatesServer interface { - // Update only the workload image of a stopped sandbox without deleting its - // identity or retained storage. Requires compute-driver image-update support - // and explicit gateway activation of sandbox image updates. + // Update the workload image, command, environment, labels, or annotations of a + // stopped sandbox while preserving its identity and retained storage. Requires + // compute-driver support for the selected changes and explicit gateway activation + // of sandbox updates. UpdateSandbox(context.Context, *UpdateSandboxRequest) (*SandboxResponse, error) mustEmbedUnimplementedSandboxUpdatesServer() } diff --git a/sdk/go/tests/compatibility/sandbox_updates_test.go b/sdk/go/tests/compatibility/sandbox_updates_test.go index 2181a87b88..44bc7b023f 100644 --- a/sdk/go/tests/compatibility/sandbox_updates_test.go +++ b/sdk/go/tests/compatibility/sandbox_updates_test.go @@ -67,7 +67,7 @@ func (s *imageUpdateServer) UpdateSandbox(_ context.Context, request *pb.UpdateS s.request = proto.Clone(request).(*pb.UpdateSandboxRequest) return &pb.SandboxResponse{Sandbox: &pb.Sandbox{ Metadata: &dm.ObjectMeta{Id: "stable-id", Name: request.Name, Workspace: request.WorkspaceScope.GetWorkspace()}, - Spec: &pb.SandboxSpec{Template: &pb.SandboxTemplate{Image: request.Image}}, + Spec: &pb.SandboxSpec{Template: &pb.SandboxTemplate{Image: request.GetImage()}}, }}, nil } @@ -101,7 +101,7 @@ func TestSeparateSandboxUpdatesTransportCoexistsWithLegacyOpenShell(t *testing.T request := &pb.UpdateSandboxRequest{ WorkspaceScope: &dm.WorkspaceSelector{Selection: &dm.WorkspaceSelector_Workspace{Workspace: "team"}}, Name: "sandbox", - Image: "example/workload:new", + Image: proto.String("example/workload:new"), ExpectedResourceVersion: 42, RequestId: "550e8400-e29b-41d4-a716-446655440000", } @@ -114,7 +114,7 @@ func TestSeparateSandboxUpdatesTransportCoexistsWithLegacyOpenShell(t *testing.T require.True(t, proto.Equal(request, updatesServer.request)) require.Equal(t, "stable-id", response.Sandbox.Metadata.Id) require.Equal(t, "team", response.Sandbox.Metadata.Workspace) - require.Equal(t, request.Image, response.Sandbox.Spec.Template.Image) + require.Equal(t, request.GetImage(), response.Sandbox.Spec.Template.Image) // The old service has no accidental update endpoint. err = conn.Invoke(ctx, "/openshell.v1.OpenShell/UpdateSandbox", request, &pb.SandboxResponse{}) require.Equal(t, codes.Unimplemented, status.Code(err)) diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index b73e8efe1a..a6909b8155 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -1439,14 +1439,14 @@ kubectl -n logs pod/ --tail=200 | grep -Ei ' `openshell.v1.SandboxUpdates/UpdateSandbox` uses the existing authenticated gateway listener and defaults to disabled. Check the effective -`[openshell.gateway] enable_sandbox_image_updates` value and its overrides, -`--enable-sandbox-image-updates true` or -`OPENSHELL_ENABLE_SANDBOX_IMAGE_UPDATES=true`. Canonical Helm values use: +`[openshell.gateway] enable_sandbox_updates` value and its overrides, +`--enable-sandbox-updates true` or +`OPENSHELL_ENABLE_SANDBOX_UPDATES=true`. Canonical Helm values use: ```yaml gatewayConfig: "openshell.gateway": - enable_sandbox_image_updates: true + enable_sandbox_updates: true ``` Do not enable the flag to work around an error. It attests that all incompatible @@ -1457,17 +1457,17 @@ a rolling upgrade. SQLite supports one gateway process, not shared-file HA. On PostgreSQL, an unmarked client backend in the same database blocks updates, including an administrative session. The new binary sets every pool -connection's `application_name` to `openshell-image-update-v1`; close unmarked +connection's `application_name` to `openshell-image-update-v2`; close unmarked sessions or use a dedicated database, rather than relabeling old clients. Live -gateway membership must advertise image-update protocol 1; malformed or +gateway membership must advertise image-update protocol 2; malformed or truncated membership reads fail closed. Neither these observations nor an expired membership TTL proves old gateways and their work have stopped. Follow the published -[activation checklist](https://docs.nvidia.com/openshell/latest/kubernetes/high-availability#activate-sandbox-image-updates), +[activation checklist](https://docs.nvidia.com/openshell/latest/kubernetes/high-availability#activate-sandbox-updates), and do not downgrade while updates are pending or retained sandboxes require the private revision protocol. -For an operation-pending error, use the original requested image and a fresh +For an operation-pending error, use the original selected fields and target values and a fresh sandbox resource version to reconcile through `SandboxUpdates`. Intent and revision are private, not new public status fields. Start, stop, provisioning retry, and delete do not bypass the barrier. Preserve request-admission semantics: diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index 075cfbec7e..647f0b999f 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -557,23 +557,28 @@ retained memory state. ### Change a stopped sandbox's workload image Do not invent a `sandbox update` command or use delete/create to change an -existing sandbox's image. The separate +existing sandbox's configuration. The separate `openshell.v1.SandboxUpdates/UpdateSandbox` RPC uses the same gateway listener and authentication as `OpenShell`. It defaults to disabled; the operator must complete the published -[activation checklist](https://docs.nvidia.com/openshell/latest/kubernetes/high-availability#activate-sandbox-image-updates) -before enabling `enable_sandbox_image_updates`. Keep it false during a rolling +[activation checklist](https://docs.nvidia.com/openshell/latest/kubernetes/high-availability#activate-sandbox-updates) +before enabling `enable_sandbox_updates`. Keep it false during a rolling upgrade and never enable it merely to bypass a failed compatibility check. After activation, the RPC initially supports only stopped Kubernetes sandboxes; other drivers return `UNIMPLEMENTED`. Stop and wait for `Stopped`, read the sandbox's current resource version through `GetSandbox`, call raw `UpdateSandbox` with the named workspace, sandbox name, -OCI image, and required nonzero `expected_resource_version`, then start after +selected image, command, environment overrides, labels or annotations, and required nonzero `expected_resource_version`, then start after success. Rust SDK callers use `client.raw_sandbox_updates_fresh()`; generated clients use `SandboxUpdates`, not the unchanged `OpenShell` service. There is no curated SDK update method. The sandbox identity, Kubernetes custom resource, and persistent volume claim remain; the existing workspace is -not reseeded and trusted runtime images do not change. +not reseeded and trusted runtime images do not change. Omitted update fields are +unchanged; supplied lists and maps replace their user-owned values, including +explicitly empty values. Template environment defaults still apply. System metadata +is protected; top-level labels and annotations do not update pod metadata. +Combined configuration changes require the configuration-update driver capability +and a uniformly upgraded protocol-2 gateway deployment. For an image that fails to start and reaches a provisioning timeout, wait for cleanup completion and settlement of the original driver operation, then run @@ -582,7 +587,7 @@ timeout diagnostic and storage and does not bypass pending cleanup. An operation-pending error after a failure blocks start, stop, provisioning retry, and delete. Image intent and revision are private; the public `SandboxStatus` -shape is unchanged. Read a fresh version and retry the same image originally +shape is unchanged. Read a fresh version and retry the same selected fields and target values originally requested, even if the spec already names it. An optional `request_id` with an unresolved admission does not execute again; inspect and reconcile state before submitting a new conditional request with a fresh From 8c5030d7813aaa7509e52aa6f41279a8b98ad005 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Tue, 27 Oct 2026 12:35:46 +0000 Subject: [PATCH 10/23] fix(sandbox): recover pending updates and address review feedback Signed-off-by: Gordon Sim --- .agents/skills/helm-dev-environment/SKILL.md | 10 + .github/workflows/e2e-kubernetes-test.yml | 2 + crates/openshell-core/README.md | 27 +- crates/openshell-core/src/compute.rs | 22 +- .../openshell-core/src/extension_protocol.rs | 6 +- crates/openshell-core/src/sandbox_update.rs | 42 +- .../tests/compute_driver_compat.rs | 46 +- crates/openshell-driver-kubernetes/README.md | 43 +- .../openshell-driver-kubernetes/src/driver.rs | 1 - .../openshell-driver-kubernetes/src/grpc.rs | 32 +- .../src/image_update.rs | 28 +- .../src/image_update_tests.rs | 41 +- .../openshell-driver-kubernetes/src/main.rs | 4 - crates/openshell-gateway/src/lib.rs | 6 +- crates/openshell-otel/src/grpc.rs | 10 +- crates/openshell-server/README.md | 42 +- .../proto/sandbox_image.proto | 4 +- .../src/compute/image_update.rs | 698 ++++++++++++--- crates/openshell-server/src/compute/mod.rs | 140 +-- .../src/compute_factory_compatibility.rs | 45 +- .../openshell-server/src/gateway_members.rs | 7 +- crates/openshell-server/src/grpc/sandbox.rs | 23 +- .../src/grpc/sandbox/image_update_tests.rs | 32 +- .../openshell-server/src/grpc/validation.rs | 21 + crates/openshell-server/src/lib.rs | 12 +- .../src/persistence/image_activation.rs | 208 ++--- .../src/persistence/postgres.rs | 13 +- .../src/persistence/sandbox_image.rs | 55 +- crates/openshell-server/src/storage_proto.rs | 4 +- crates/openshell-server/src/test_support.rs | 66 +- .../openshell-workspace/templates/role.yaml | 13 + .../tests/workspace_test.yaml | 22 + docs/how-it-works/gateways/configuration.mdx | 10 +- docs/how-it-works/sandboxes/overview.mdx | 47 +- docs/kubernetes/high-availability.mdx | 12 +- docs/kubernetes/setup.mdx | 9 +- docs/sdk/api-errors.mdx | 26 +- e2e/rust/Cargo.lock | 792 ++--------------- e2e/rust/Cargo.toml | 9 +- e2e/rust/e2e-kubernetes.sh | 10 + e2e/with-kube-gateway.sh | 14 + proto/compute_driver.proto | 22 +- proto/openshell.proto | 3 +- sdk/go/proto/openshellv1/openshell.pb.go | 3 +- skills/debug-openshell-cluster/SKILL.md | 36 +- skills/openshell-cli/SKILL.md | 22 +- tasks/test.toml | 8 + tests/suites/features/Cargo.lock | 799 +++++++++++++++++- tests/suites/features/Cargo.toml | 2 +- .../features/kubernetes-updates/Cargo.toml | 15 + .../kubernetes-updates/tests/update.rs | 424 +++++++--- 51 files changed, 2407 insertions(+), 1581 deletions(-) create mode 100644 tests/suites/features/kubernetes-updates/Cargo.toml rename e2e/rust/tests/kubernetes_image_update.rs => tests/suites/features/kubernetes-updates/tests/update.rs (50%) diff --git a/.agents/skills/helm-dev-environment/SKILL.md b/.agents/skills/helm-dev-environment/SKILL.md index 1fb2ea6e3b..ee01e683a7 100644 --- a/.agents/skills/helm-dev-environment/SKILL.md +++ b/.agents/skills/helm-dev-environment/SKILL.md @@ -634,3 +634,13 @@ for dependencies still declared in `Chart.yaml`. | `deploy/kube/manifests/envoy-gateway-openshell.yaml` | GatewayClass and BackendTrafficPolicy for Envoy Gateway (`mise run helm:gateway:apply`) | | `tasks/scripts/helm-k3s-local.sh` | k3d cluster create/delete/start/stop/status | | `tasks/scripts/keycloak-k8s-setup.sh` | Keycloak deploy, realm import, and development TLS trust anchor | + +## Sandbox update regression lane + +Run `mise run e2e:kubernetes:updates` for the testkit update suite against both +supported Agent Sandbox APIs with `workspaceResources.enabled=false` and the +separate workspace chart. It verifies stopped-only updates, retained CR/PVC +identity and contents, command/environment changes, and request replay. +`OPENSHELL_E2E_UPDATE_ORIGINAL_IMAGE` and `OPENSHELL_E2E_UPDATE_TARGET_IMAGE` can +select mirrored Alpine 3.21 and 3.22 manifests. Defaults use the public registry +cache; keep immutable digests when overriding them. diff --git a/.github/workflows/e2e-kubernetes-test.yml b/.github/workflows/e2e-kubernetes-test.yml index cf6eb07b2d..706feb050c 100644 --- a/.github/workflows/e2e-kubernetes-test.yml +++ b/.github/workflows/e2e-kubernetes-test.yml @@ -137,6 +137,8 @@ jobs: OPENSHELL_E2E_KUBE_EXTRA_VALUES: ${{ inputs.extra-helm-values }} OPENSHELL_E2E_KUBE_EXTERNAL_POSTGRES_SECRET: ${{ inputs.external-postgres-secret }} OPENSHELL_E2E_KUBE_TEST: ${{ inputs.test-name }} + # Default shared-mode runs exercise the independently installed workspace Role. + OPENSHELL_E2E_KUBE_SPLIT_WORKSPACE: ${{ inputs.e2e-task == 'e2e:kubernetes' && inputs.test-name == '' && inputs.extra-helm-values == '' && '1' || '0' }} OPENSHELL_E2E_KUBERNETES_FEATURES: ${{ inputs.kubernetes-features }} OPENSHELL_E2E_KUBE_USE_ENVOY: ${{ inputs.use-envoy-gateway && '1' || '0' }} IMAGE_TAG: ${{ inputs.image-tag }} diff --git a/crates/openshell-core/README.md b/crates/openshell-core/README.md index a7bd283572..d1ce03d653 100644 --- a/crates/openshell-core/README.md +++ b/crates/openshell-core/README.md @@ -68,23 +68,16 @@ dependency from the policy crate to the supervisor implementation. ## Optional Compute Updates The generated `proto::compute::v1::compute_driver_server::ComputeDriver` trait -retains its baseline methods and streaming associated type. External drivers -that support image updates additionally serve `ComputeDriverImageUpdates` on -the same endpoint and advertise `openshell.compute.update-sandbox-image`. -Drivers without that capability need no new generated-trait method. - -Drivers supporting command and environment replacement additionally serve -`ComputeDriverConfigurationUpdates` and advertise -`openshell.compute.update-sandbox-configuration`. Its separate typed request -retains image-update lifecycle preconditions. Both optional in-process methods -have `UNIMPLEMENTED` defaults, so image-only implementations remain valid. - -Existing linked in-process drivers and factories need no new trait or hook. -Only drivers opting into image updates implement -`openshell_core::compute::ComputeDriver` and register that implementation through -`ComputeDriverFactory::build_with_image_updates`. The default factory hook calls -the existing `build` method without an updater. The gateway requires both this -separate registration and the negotiated capability before invoking updates. +retains its baseline methods and streaming associated type. Supporting external +drivers additionally serve `ComputeDriverConfigurationUpdates` on the same +endpoint and advertise `openshell.compute.update-sandbox-configuration`. +The request carries image and lifecycle preconditions plus optional command and +environment replacements. Drivers without the capability need no new method. + +Linked drivers opt in through `openshell_core::compute::ComputeDriver` and +`ComputeDriverFactory::build_with_configuration_updates`. The default factory +hook calls `build` without an updater. Registration and capability negotiation +are both required. Metadata-only updates are handled by the gateway. ## Protobuf Struct Conversion diff --git a/crates/openshell-core/src/compute.rs b/crates/openshell-core/src/compute.rs index 7e3f7046b0..3e2a9118cf 100644 --- a/crates/openshell-core/src/compute.rs +++ b/crates/openshell-core/src/compute.rs @@ -3,17 +3,14 @@ //! Opt-in in-process sandbox updates, separate from the baseline driver contract. -use crate::proto::compute::v1::{ - UpdateSandboxImageRequest, UpdateSandboxImageResponse, compute_driver_server, -}; +use crate::proto::compute::v1::compute_driver_server; -/// Optional in-process image updater, registered separately by a driver factory. +/// Optional in-process configuration updater, registered separately by a driver factory. /// /// Existing drivers need only the generated baseline trait, not this extension. -/// Supporting factories opt in through `ComputeDriverFactory::build_with_image_updates` -/// and advertise the image-update capability. External servers use the separate -/// generated `ComputeDriverImageUpdates` or `ComputeDriverConfigurationUpdates` -/// service on the same endpoint instead. Each operation requires its own capability. +/// Supporting factories opt in through `ComputeDriverFactory::build_with_configuration_updates` +/// and advertise the configuration-update capability. External servers use the +/// separate generated `ComputeDriverConfigurationUpdates` service on the same endpoint. #[tonic::async_trait] pub trait ComputeDriver: compute_driver_server::ComputeDriver { async fn update_sandbox_configuration( @@ -27,13 +24,4 @@ pub trait ComputeDriver: compute_driver_server::ComputeDriver { "sandbox configuration updates are not supported by this driver", )) } - - async fn update_sandbox_image( - &self, - _request: tonic::Request, - ) -> Result, tonic::Status> { - Err(tonic::Status::unimplemented( - "storage-preserving image updates are not supported by this driver", - )) - } } diff --git a/crates/openshell-core/src/extension_protocol.rs b/crates/openshell-core/src/extension_protocol.rs index fca1da3b46..d6d93418d8 100644 --- a/crates/openshell-core/src/extension_protocol.rs +++ b/crates/openshell-core/src/extension_protocol.rs @@ -25,10 +25,9 @@ pub const COMPUTE_ISOLATION_BACKEND: &str = "openshell.compute.isolation-backend /// Driver implements `SuspendSandbox` and resuming through `StartSandbox`. pub const COMPUTE_SUSPEND_RESUME: &str = "openshell.compute.suspend-resume"; -/// Optional stopped-state image updates retaining the resource and its storage. +/// Optional stopped-state workload configuration updates retaining the resource and storage. pub const COMPUTE_UPDATE_SANDBOX_CONFIGURATION: &str = "openshell.compute.update-sandbox-configuration"; -pub const COMPUTE_UPDATE_SANDBOX_IMAGE: &str = "openshell.compute.update-sandbox-image"; const MAX_IMPLEMENTATION_NAME_BYTES: usize = 128; const MAX_IMPLEMENTATION_VERSION_BYTES: usize = 128; @@ -133,7 +132,6 @@ pub fn gateway_metadata(family: ExtensionFamily) -> PeerMetadata { if family == ExtensionFamily::Compute { supported_capabilities.push(COMPUTE_LAUNCH_AUTHENTICATION.to_string()); supported_capabilities.push(COMPUTE_ISOLATION_BACKEND.to_string()); - supported_capabilities.push(COMPUTE_UPDATE_SANDBOX_IMAGE.to_string()); supported_capabilities.push(COMPUTE_UPDATE_SANDBOX_CONFIGURATION.to_string()); } PeerMetadata { @@ -419,7 +417,7 @@ mod tests { gateway .supported_capabilities .iter() - .any(|c| c == COMPUTE_UPDATE_SANDBOX_IMAGE) + .any(|c| c == COMPUTE_UPDATE_SANDBOX_CONFIGURATION) ); } diff --git a/crates/openshell-core/src/sandbox_update.rs b/crates/openshell-core/src/sandbox_update.rs index 8654c391e8..2b9557c829 100644 --- a/crates/openshell-core/src/sandbox_update.rs +++ b/crates/openshell-core/src/sandbox_update.rs @@ -5,15 +5,23 @@ use crate::proto::{Sandbox, SandboxCommandUpdate, SandboxMapUpdate}; use std::collections::HashMap; -/// System metadata is never caller-replaceable, including subdomains. +/// Gateway-owned identity and lifecycle metadata is never caller-replaceable. +/// Other keys, including user keys under `OpenShell` domains, remain editable. #[must_use] pub fn is_system_metadata_key(key: &str) -> bool { - key.split_once('/').is_some_and(|(domain, _)| { - domain == "openshell.ai" - || domain.ends_with(".openshell.ai") - || domain == "agents.x-k8s.io" - || domain.ends_with(".agents.x-k8s.io") - }) + key.starts_with("internal.openshell.ai/") + || matches!( + key, + "openshell.nvidia.com/retention" + | "openshell.ai/managed-by" + | "openshell.ai/sandbox-id" + | "openshell.ai/sandbox-name" + | "openshell.ai/sandbox-namespace" + | "openshell.ai/sandbox-workspace" + | "openshell.ai/gateway-id" + | "openshell.ai/caller-driver-config-used" + | "openshell.ai/resource-admission-identities" + ) } fn replace_user_metadata(current: &mut HashMap, update: &SandboxMapUpdate) { @@ -46,3 +54,23 @@ pub fn apply_configuration( } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn replacement_preserves_owned_keys_without_freezing_user_domains() { + let mut metadata = HashMap::from([ + ("internal.openshell.ai/auth-epoch".into(), "trusted".into()), + ("openshell.nvidia.com/retention".into(), "ephemeral".into()), + ("openshell.ai/user-note".into(), "old".into()), + ("agents.x-k8s.io/user-note".into(), "old".into()), + ]); + replace_user_metadata(&mut metadata, &SandboxMapUpdate::default()); + assert_eq!(metadata.len(), 2); + assert_eq!(metadata["openshell.nvidia.com/retention"], "ephemeral"); + assert!(!is_system_metadata_key("openshell.ai/user-note")); + assert!(!is_system_metadata_key("agents.x-k8s.io/user-note")); + } +} diff --git a/crates/openshell-core/tests/compute_driver_compat.rs b/crates/openshell-core/tests/compute_driver_compat.rs index 81643cd4b1..01baa27a45 100644 --- a/crates/openshell-core/tests/compute_driver_compat.rs +++ b/crates/openshell-core/tests/compute_driver_compat.rs @@ -13,12 +13,13 @@ use openshell_core::proto::compute::v1::{ GetCapabilitiesRequest, GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse, ListSandboxesRequest, ListSandboxesResponse, StartSandboxRequest, StartSandboxResponse, StopSandboxRequest, StopSandboxResponse, SuspendSandboxRequest, SuspendSandboxResponse, - UpdateSandboxImageRequest, UpdateSandboxImageResponse, ValidateSandboxCreateRequest, - ValidateSandboxCreateResponse, WatchSandboxesEvent, WatchSandboxesRequest, + UpdateSandboxConfigurationRequest, UpdateSandboxConfigurationResponse, + ValidateSandboxCreateRequest, ValidateSandboxCreateResponse, WatchSandboxesEvent, + WatchSandboxesRequest, compute_driver_client::ComputeDriverClient, - compute_driver_image_updates_client::ComputeDriverImageUpdatesClient, - compute_driver_image_updates_server::{ - ComputeDriverImageUpdates, ComputeDriverImageUpdatesServer, + compute_driver_configuration_updates_client::ComputeDriverConfigurationUpdatesClient, + compute_driver_configuration_updates_server::{ + ComputeDriverConfigurationUpdates, ComputeDriverConfigurationUpdatesServer, }, compute_driver_server::{ComputeDriver, ComputeDriverServer}, }; @@ -134,17 +135,17 @@ impl ComputeDriver for BaselineDriver { #[derive(Debug, Clone, Default)] struct ImageUpdates { - calls: Arc>>, + calls: Arc>>, } #[tonic::async_trait] -impl ComputeDriverImageUpdates for ImageUpdates { - async fn update_sandbox_image( +impl ComputeDriverConfigurationUpdates for ImageUpdates { + async fn update_sandbox_configuration( &self, - request: Request, - ) -> Result, Status> { + request: Request, + ) -> Result, Status> { self.calls.lock().unwrap().push(request.into_inner()); - Ok(Response::new(UpdateSandboxImageResponse {})) + Ok(Response::new(UpdateSandboxConfigurationResponse {})) } } @@ -167,8 +168,8 @@ async fn roundtrip(serve_image_updates: bool) { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); let address = listener.local_addr().unwrap(); let extension = ImageUpdates::default(); - let optional_service = - serve_image_updates.then(|| ComputeDriverImageUpdatesServer::new(extension.clone())); + let optional_service = serve_image_updates + .then(|| ComputeDriverConfigurationUpdatesServer::new(extension.clone())); let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel(); let server = tokio::spawn(async move { tonic::transport::Server::builder() @@ -216,13 +217,18 @@ async fn roundtrip(serve_image_updates: bool) { .is_none() ); - let request = UpdateSandboxImageRequest { - sandbox_id: "sandbox-id".into(), - image: "example/workload:v2".into(), + let request = UpdateSandboxConfigurationRequest { + preconditions: Some( + openshell_core::proto::compute::v1::SandboxUpdatePreconditions { + sandbox_id: "sandbox-id".into(), + image: "example/workload:v2".into(), + ..Default::default() + }, + ), ..Default::default() }; - let result = ComputeDriverImageUpdatesClient::new(channel) - .update_sandbox_image(request.clone()) + let result = ComputeDriverConfigurationUpdatesClient::new(channel) + .update_sandbox_configuration(request.clone()) .await; if serve_image_updates { result.unwrap(); @@ -290,11 +296,11 @@ fn baseline_compute_service_methods_are_frozen() { let image_updates = compute .service .iter() - .find(|service| service.name.as_deref() == Some("ComputeDriverImageUpdates")) + .find(|service| service.name.as_deref() == Some("ComputeDriverConfigurationUpdates")) .unwrap(); assert_eq!(image_updates.method.len(), 1); assert_eq!( image_updates.method[0].name.as_deref(), - Some("UpdateSandboxImage") + Some("UpdateSandboxConfiguration") ); } diff --git a/crates/openshell-driver-kubernetes/README.md b/crates/openshell-driver-kubernetes/README.md index 47fca1aca6..2808e242c3 100644 --- a/crates/openshell-driver-kubernetes/README.md +++ b/crates/openshell-driver-kubernetes/README.md @@ -302,30 +302,25 @@ storage. The driver confirms the stop from both the published `Suspended` condition and deletion of the backing pod. Legacy `v1alpha1` controllers omit a usable stopped condition, so pod deletion alone confirms their stop. -The optional `openshell.compute.update-sandbox-image` capability supports -image-only updates while the sandbox is stopped. External drivers serve it as -the separate `ComputeDriverImageUpdates` service on the baseline `ComputeDriver` -endpoint, preserving the baseline generated server trait. The linked gateway -factory opts in through `ComputeDriverFactory::build_with_image_updates` without -changing the baseline driver object. `UpdateSandboxImage` requires -the persisted Kubernetes runtime identity, current image, sandbox name, and a -stable operation ID with a monotonic image revision. The driver verifies that -the same Sandbox resource is suspended, runtime bootstrap has completed, and -no workload or supervisor Pods -remain, then revalidates stored external-resource admission. It patches only -the agent image, the workspace seed image, and dedicated operation evidence, -using the resource UID and `resourceVersion` as concurrency guards. A repeat of -the same completed operation succeeds without a second patch; a different -current image, stale revision, or reused operation ID with different parameters -fails closed. A stale operation cannot reapply an image after a later update -returns to an earlier tag. Image updates do not delete or recreate the Sandbox resource, PVCs, mounts, -trusted runtime images, or bootstrap annotations. They leave the sandbox -stopped. Existing workspace contents and the seed sentinel remain unchanged, -so an image update does not replace files already stored under `/sandbox`. - -The additional `openshell.compute.update-sandbox-configuration` capability and -`ComputeDriverConfigurationUpdates` service reconcile workload argv and effective -user environment with the image in one UID/resource-version-fenced patch. The +The optional `openshell.compute.update-sandbox-configuration` capability supports +image, command, and environment updates while stopped. External drivers serve +`ComputeDriverConfigurationUpdates` separately from the baseline driver service; +linked factories opt in through `build_with_configuration_updates`. +The request identifies the sandbox, original resource UID, expected image, +operation ID, and monotonic revision. The driver checks the suspended state, +completed bootstrap, current resource UID, and absence of workload and supervisor +Pods, including Pods found only by owner UID or recorded name. It revalidates +external-resource admission before patching the existing resource with a +`resourceVersion` condition. The patch includes the verified UID; Kubernetes +immutable-UID validation also rejects a same-name replacement. No resource or +PVC is recreated. Existing workspace contents are not reseeded. + +A retry verifies durable operation evidence and the live selected targets before +returning success without another patch. Different parameters or older revisions +fail closed, including when later operations return to an earlier image. + +The service reconciles workload argv and effective user environment with the image +in the same conditional patch. The main-process annotation and agent environment supply the next runtime generation; the trusted container launcher and runtime environment remain intact. Retry records identify selected fields and verify their live target values without diff --git a/crates/openshell-driver-kubernetes/src/driver.rs b/crates/openshell-driver-kubernetes/src/driver.rs index 6ebae66273..b893632f3f 100644 --- a/crates/openshell-driver-kubernetes/src/driver.rs +++ b/crates/openshell-driver-kubernetes/src/driver.rs @@ -1345,7 +1345,6 @@ impl KubernetesComputeDriver { "openshell/kubernetes", openshell_core::VERSION, [ - openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.to_string(), openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION .to_string(), ], diff --git a/crates/openshell-driver-kubernetes/src/grpc.rs b/crates/openshell-driver-kubernetes/src/grpc.rs index ac972db536..c9adffcbf5 100644 --- a/crates/openshell-driver-kubernetes/src/grpc.rs +++ b/crates/openshell-driver-kubernetes/src/grpc.rs @@ -346,48 +346,22 @@ impl openshell_core::compute::ComputeDriver for ComputeDriverService { Response, Status, > { - self.driver - .update_sandbox_configuration(&request.into_inner()) - .await - .map_err(|error| Status::from(openshell_core::ComputeDriverError::from(error)))?; - Ok(Response::new( - openshell_core::proto::compute::v1::UpdateSandboxConfigurationResponse {}, - )) - } - - async fn update_sandbox_image( - &self, - request: Request, - ) -> Result, Status> - { self.rpc_tracer - .trace(openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, async { + .trace(openshell_otel::rpc::UPDATE_SANDBOX_CONFIGURATION, async { self.driver - .update_sandbox_image(&request.into_inner()) + .update_sandbox_configuration(&request.into_inner()) .await .map_err(|error| { Status::from(openshell_core::ComputeDriverError::from(error)) })?; Ok(Response::new( - openshell_core::proto::compute::v1::UpdateSandboxImageResponse {}, + openshell_core::proto::compute::v1::UpdateSandboxConfigurationResponse {}, )) }) .await } } -#[tonic::async_trait] -impl openshell_core::proto::compute::v1::compute_driver_image_updates_server::ComputeDriverImageUpdates - for ComputeDriverService -{ - async fn update_sandbox_image( - &self, - request: Request, - ) -> Result, Status> { - openshell_core::compute::ComputeDriver::update_sandbox_image(self, request).await - } -} - #[tonic::async_trait] impl openshell_core::proto::compute::v1::compute_driver_configuration_updates_server::ComputeDriverConfigurationUpdates for ComputeDriverService { async fn update_sandbox_configuration(&self, request: Request) -> Result, Status> { diff --git a/crates/openshell-driver-kubernetes/src/image_update.rs b/crates/openshell-driver-kubernetes/src/image_update.rs index 293bc45a39..314d529727 100644 --- a/crates/openshell-driver-kubernetes/src/image_update.rs +++ b/crates/openshell-driver-kubernetes/src/image_update.rs @@ -13,7 +13,7 @@ use super::{ use k8s_openapi::api::core::v1::Pod; use kube::Api; use kube::api::{DynamicObject, ListParams, Patch, PatchParams}; -use openshell_core::proto::compute::v1::UpdateSandboxImageRequest; +use openshell_core::proto::compute::v1::SandboxUpdatePreconditions; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::sync::LazyLock; @@ -29,8 +29,6 @@ struct ImageUpdateRecord { image: String, revision: u64, #[serde(default, skip_serializing_if = "std::ops::Not::not")] - configuration: bool, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] command_updated: bool, #[serde(default, skip_serializing_if = "std::ops::Not::not")] environment_updated: bool, @@ -50,19 +48,26 @@ impl KubernetesComputeDriver { sandbox.id = %request.sandbox_id, ) )] + #[cfg(test)] pub async fn update_sandbox_image( &self, - request: &UpdateSandboxImageRequest, + request: &SandboxUpdatePreconditions, ) -> Result<(), KubernetesDriverError> { - self.update_workload(request, None).await + self.update_sandbox_configuration( + &openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest { + preconditions: Some(request.clone()), + ..Default::default() + }, + ) + .await } pub async fn update_sandbox_configuration( &self, request: &openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest, ) -> Result<(), KubernetesDriverError> { - let image = request.image_update.as_ref().ok_or_else(|| { - KubernetesDriverError::InvalidArgument("image_update is required".into()) + let image = request.preconditions.as_ref().ok_or_else(|| { + KubernetesDriverError::InvalidArgument("preconditions are required".into()) })?; validate_configuration(request)?; self.update_workload(image, Some(request)).await @@ -70,7 +75,7 @@ impl KubernetesComputeDriver { async fn update_workload( &self, - request: &UpdateSandboxImageRequest, + request: &SandboxUpdatePreconditions, configuration: Option< &openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest, >, @@ -98,7 +103,7 @@ impl KubernetesComputeDriver { async fn update_sandbox_image_inner( &self, - request: &UpdateSandboxImageRequest, + request: &SandboxUpdatePreconditions, configuration: Option< &openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest, >, @@ -262,7 +267,7 @@ impl KubernetesComputeDriver { } fn validate_image_update_request( - request: &UpdateSandboxImageRequest, + request: &SandboxUpdatePreconditions, ) -> Result<(), KubernetesDriverError> { for (field, value) in [ ("sandbox_id", request.sandbox_id.as_str()), @@ -370,7 +375,7 @@ fn require_stopped_for_image_update( /// Apply the image-only mutation in memory; return true for an exact retry. fn prepare_update( object: &mut DynamicObject, - request: &UpdateSandboxImageRequest, + request: &SandboxUpdatePreconditions, configuration: Option<&openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest>, ) -> Result { let evidence = object @@ -388,7 +393,6 @@ fn prepare_update( expected_image: request.expected_image.clone(), image: request.image.clone(), revision: request.revision, - configuration: configuration.is_some(), command_updated: configuration.is_some_and(|value| value.main_process.is_some()), environment_updated: configuration.is_some_and(|value| value.environment.is_some()), }; diff --git a/crates/openshell-driver-kubernetes/src/image_update_tests.rs b/crates/openshell-driver-kubernetes/src/image_update_tests.rs index 3ef3884e73..c2c4ce48eb 100644 --- a/crates/openshell-driver-kubernetes/src/image_update_tests.rs +++ b/crates/openshell-driver-kubernetes/src/image_update_tests.rs @@ -223,8 +223,8 @@ fn fixture( (driver, state) } -fn request() -> UpdateSandboxImageRequest { - UpdateSandboxImageRequest { +fn request() -> SandboxUpdatePreconditions { + SandboxUpdatePreconditions { sandbox_id: "sandbox-1".into(), name: "sandbox-name".into(), image: "registry.example/agent:v2".into(), @@ -273,7 +273,7 @@ async fn image_update_preflight_validates_without_writes_and_apply_rechecks() { async fn image_update_capability_is_optional() { let (driver, _) = fixture(SANDBOX_VERSION_V1BETA1, false); let metadata = driver.capabilities().unwrap().extension.unwrap(); - let capability = openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE; + let capability = openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION; assert!( metadata .supported_capabilities @@ -310,7 +310,6 @@ async fn image_update_preserves_resource_storage_and_operator_bootstrap_annotati expected["metadata"]["generation"] = serde_json::json!(8); expected["metadata"]["annotations"][IMAGE_UPDATE_ANNOTATION] = serde_json::json!( serde_json::to_string(&ImageUpdateRecord { - configuration: false, command_updated: false, environment_updated: false, operation_id: request().operation_id, @@ -565,13 +564,18 @@ async fn image_update_conflict_does_not_blindly_retry_or_recreate() { #[tokio::test] async fn image_update_grpc_maps_validation_and_precondition_errors() { - use openshell_core::proto::compute::v1::compute_driver_image_updates_server::ComputeDriverImageUpdates; + use openshell_core::proto::compute::v1::compute_driver_configuration_updates_server::ComputeDriverConfigurationUpdates; let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); let service = crate::ComputeDriverService::new(driver); let mut invalid = request(); invalid.image = "https://registry.example/image:v2".into(); let error = service - .update_sandbox_image(tonic::Request::new(invalid)) + .update_sandbox_configuration(tonic::Request::new( + openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest { + preconditions: Some(invalid), + ..Default::default() + }, + )) .await .unwrap_err(); assert_eq!(error.code(), tonic::Code::InvalidArgument); @@ -579,7 +583,12 @@ async fn image_update_grpc_maps_validation_and_precondition_errors() { let mut conflict = request(); conflict.expected_image = "other:v1".into(); let error = service - .update_sandbox_image(tonic::Request::new(conflict)) + .update_sandbox_configuration(tonic::Request::new( + openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest { + preconditions: Some(conflict), + ..Default::default() + }, + )) .await .unwrap_err(); assert_eq!(error.code(), tonic::Code::FailedPrecondition); @@ -681,7 +690,7 @@ async fn configuration_update_atomically_changes_restart_inputs_and_retries_with } let before = state.lock().unwrap().sandbox.clone(); let mut update = UpdateSandboxConfigurationRequest { - image_update: Some(request()), + preconditions: Some(request()), main_process: Some(SandboxMainProcessUpdate { command: vec!["/usr/local/bin/start-agent".into(), "--new".into()], ..Default::default() @@ -693,10 +702,10 @@ async fn configuration_update_atomically_changes_restart_inputs_and_retries_with )]), }), }; - update.image_update.as_mut().unwrap().validate_only = true; + update.preconditions.as_mut().unwrap().validate_only = true; driver.update_sandbox_configuration(&update).await.unwrap(); assert_eq!(state.lock().unwrap().sandbox, before); - update.image_update.as_mut().unwrap().validate_only = false; + update.preconditions.as_mut().unwrap().validate_only = false; driver.update_sandbox_configuration(&update).await.unwrap(); { let state = state.lock().unwrap(); @@ -710,7 +719,7 @@ async fn configuration_update_atomically_changes_restart_inputs_and_retries_with agent["command"], before["spec"]["podTemplate"]["spec"]["containers"][0]["command"] ); - assert_eq!(agent["image"], update.image_update.as_ref().unwrap().image); + assert_eq!(agent["image"], update.preconditions.as_ref().unwrap().image); let env = agent["env"].as_array().unwrap(); assert!(env.iter().any(|entry| entry["name"] == "AGENT_MODE" && entry["value"] == "sensitive-environment-value")); @@ -756,10 +765,10 @@ async fn configuration_update_atomically_changes_restart_inputs_and_retries_with .command .push("--different".into()); assert!(driver.update_sandbox_configuration(&changed).await.is_err()); - update.image_update.as_mut().unwrap().expected_image = - update.image_update.as_ref().unwrap().image.clone(); - update.image_update.as_mut().unwrap().revision += 1; - update.image_update.as_mut().unwrap().operation_id = "clear-configuration".into(); + update.preconditions.as_mut().unwrap().expected_image = + update.preconditions.as_ref().unwrap().image.clone(); + update.preconditions.as_mut().unwrap().revision += 1; + update.preconditions.as_mut().unwrap().operation_id = "clear-configuration".into(); update.main_process.as_mut().unwrap().command.clear(); update.environment.as_mut().unwrap().values.clear(); driver.update_sandbox_configuration(&update).await.unwrap(); @@ -787,7 +796,7 @@ async fn configuration_update_rejects_reserved_environment_without_writes() { }; let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); let update = UpdateSandboxConfigurationRequest { - image_update: Some(request()), + preconditions: Some(request()), main_process: None, environment: Some(SandboxEnvironmentUpdate { values: std::collections::HashMap::from([( diff --git a/crates/openshell-driver-kubernetes/src/main.rs b/crates/openshell-driver-kubernetes/src/main.rs index 84ad0884ea..e7b9722e17 100644 --- a/crates/openshell-driver-kubernetes/src/main.rs +++ b/crates/openshell-driver-kubernetes/src/main.rs @@ -9,7 +9,6 @@ use std::path::PathBuf; use tracing::info; use openshell_core::VERSION; -use openshell_core::proto::compute::v1::compute_driver_image_updates_server::ComputeDriverImageUpdatesServer; use openshell_core::proto::compute::v1::compute_driver_server::ComputeDriverServer; use openshell_driver_kubernetes::{ ComputeDriverService, DEFAULT_GATEWAY_ID, DEFAULT_SANDBOX_SERVICE_ACCOUNT_NAME, @@ -343,7 +342,6 @@ async fn main() -> Result<()> { let driver_service = ComputeDriverService::new(driver); let configuration_updates_service = openshell_core::proto::compute::v1::compute_driver_configuration_updates_server::ComputeDriverConfigurationUpdatesServer::new(driver_service.clone()); - let image_updates_service = ComputeDriverImageUpdatesServer::new(driver_service.clone()); let service = ComputeDriverServer::new(driver_service); let shutdown = async move { shutdown_signal().await; @@ -358,7 +356,6 @@ async fn main() -> Result<()> { tonic::transport::Server::builder() .layer(openshell_otel::compute_driver_rpc_layer()) .add_service(service) - .add_service(image_updates_service) .add_service(configuration_updates_service) .serve_with_incoming_shutdown( openshell_core::external_driver_socket::SameUidUnixIncoming::new(listener), @@ -371,7 +368,6 @@ async fn main() -> Result<()> { tonic::transport::Server::builder() .layer(openshell_otel::compute_driver_rpc_layer()) .add_service(service) - .add_service(image_updates_service) .add_service(configuration_updates_service) .serve_with_shutdown(args.bind_address, shutdown) .await diff --git a/crates/openshell-gateway/src/lib.rs b/crates/openshell-gateway/src/lib.rs index 280a3d16e0..eda99c9b33 100644 --- a/crates/openshell-gateway/src/lib.rs +++ b/crates/openshell-gateway/src/lib.rs @@ -289,17 +289,17 @@ impl openshell_server::ComputeDriverFactory for KubernetesFactory { &self, context: openshell_server::ComputeDriverBuildContext<'_>, ) -> openshell_core::Result { - self.build_with_image_updates(context) + self.build_with_configuration_updates(context) .await .map(|(instance, _)| instance) } - async fn build_with_image_updates( + async fn build_with_configuration_updates( &self, context: openshell_server::ComputeDriverBuildContext<'_>, ) -> openshell_core::Result<( openshell_server::ComputeDriverInstance, - Option, + Option, )> { let mut config = kubernetes_config(context.config_context())?; config.supervisor_otlp_endpoint = context diff --git a/crates/openshell-otel/src/grpc.rs b/crates/openshell-otel/src/grpc.rs index 0492b3c0a2..9edb630318 100644 --- a/crates/openshell-otel/src/grpc.rs +++ b/crates/openshell-otel/src/grpc.rs @@ -63,8 +63,6 @@ where } pub const COMPUTE_DRIVER_RPC_SERVICE: &str = "openshell.compute.v1.ComputeDriver"; -pub const COMPUTE_DRIVER_IMAGE_UPDATES_RPC_SERVICE: &str = - "openshell.compute.v1.ComputeDriverImageUpdates"; /// Low-cardinality semantic-convention identity for a compute-driver RPC. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -109,11 +107,6 @@ pub mod rpc { method: "UpdateSandboxConfiguration", operation: "openshell.compute.v1.ComputeDriverConfigurationUpdates/UpdateSandboxConfiguration", }; - pub const UPDATE_SANDBOX_IMAGE: ComputeDriverRpc = ComputeDriverRpc { - service: super::COMPUTE_DRIVER_IMAGE_UPDATES_RPC_SERVICE, - method: "UpdateSandboxImage", - operation: "openshell.compute.v1.ComputeDriverImageUpdates/UpdateSandboxImage", - }; pub const GET_SANDBOX: ComputeDriverRpc = ComputeDriverRpc::new( "GetSandbox", "openshell.compute.v1.ComputeDriver/GetSandbox", @@ -207,7 +200,6 @@ pub fn compute_driver_rpc_operation(path: &str) -> Option { Some("ValidateSandboxCreate") => Some(rpc::VALIDATE_SANDBOX_CREATE), Some("CreateSandbox") => Some(rpc::CREATE_SANDBOX), Some("UpdateSandboxConfiguration") => Some(rpc::UPDATE_SANDBOX_CONFIGURATION), - Some("UpdateSandboxImage") => Some(rpc::UPDATE_SANDBOX_IMAGE), Some("GetSandbox") => Some(rpc::GET_SANDBOX), Some("ListSandboxes") => Some(rpc::LIST_SANDBOXES), Some("StopSandbox") => Some(rpc::STOP_SANDBOX), @@ -331,7 +323,7 @@ mod tests { rpc::GET_CAPABILITIES, rpc::VALIDATE_SANDBOX_CREATE, rpc::CREATE_SANDBOX, - rpc::UPDATE_SANDBOX_IMAGE, + rpc::UPDATE_SANDBOX_CONFIGURATION, rpc::GET_SANDBOX, rpc::LIST_SANDBOXES, rpc::STOP_SANDBOX, diff --git a/crates/openshell-server/README.md b/crates/openshell-server/README.md index 05dd0efc5d..cc5dc3d10b 100644 --- a/crates/openshell-server/README.md +++ b/crates/openshell-server/README.md @@ -129,22 +129,32 @@ member identity is asserted by its hello rather than bound to its Pod. `ComputeDriverInstance` retains its existing variants. Existing compiled drivers and factories need no new trait implementation or registration method. -A supporting factory overrides `ComputeDriverFactory::build_with_image_updates` -to return its ordinary instance plus a separately registered image updater. The -default calls the existing `build` method and returns no updater. The gateway -requires both this opt-in and the negotiated capability before recording image -intent. Remote drivers register the separate `ComputeDriverImageUpdates` service -on their existing endpoint instead. - -Command, environment, label, and annotation selections use the same stopped-only -transaction and durable interlock. Extended requests require the separate -configuration-update driver capability and RPC; unsupported combinations fail -before admission. User metadata replacement preserves system domains, and labels -are indexed in the same SQL transaction as the payload. The existing activation -flag now requires deployment protocol 2. Old private image-only intents remain -readable, and completion verifies the selected workload targets and labels before -clearing the fence. Annotation replacement commits at acceptance; completion -preserves later annotation writes accepted through `UpdateConfig`. +A supporting factory overrides `ComputeDriverFactory::build_with_configuration_updates` +to return its ordinary instance plus a separately registered updater. The default +calls `build` and returns no updater. External drivers serve +`ComputeDriverConfigurationUpdates` on their existing endpoint. Workload updates +require `openshell.compute.update-sandbox-configuration` for image, command, or +environment changes. Metadata-only replacements use one database CAS and update +the label index without invoking a driver. + +New updates require operator activation and compatible gateway membership. +Accepted updates recover from private durable intent at startup and in periodic +reconciliation, including when activation is subsequently disabled. An authorized +`UpdateSandbox` with no selected fields and the current resource version resumes +the stored intent without reconstructing its selections. Completion retains the +exact operation receipt for idempotent completion across replicas; a newer update +invalidates it. Ambiguous results retain the baseline provisioning interlock. +Explicit deletion can supersede a pending update: the driver only patches the +original immutable resource and never creates a replacement. The Deleting CAS +prevents delayed completion, and successful deletion reclaims private intent. + +Metadata replacement preserves gateway-owned keys, including retention, while +other user keys under OpenShell domains remain editable. Completion preserves +later annotation merges accepted through `UpdateConfig`. + +A provisioning timeout can be repaired by Stop after its original driver work +settles and cleanup completes. Stop exposes Stopped without discarding the timeout +diagnosis or storage. This lifecycle behavior also applies when updates are disabled. ## Operator credential export diff --git a/crates/openshell-server/proto/sandbox_image.proto b/crates/openshell-server/proto/sandbox_image.proto index 1ed4a2167f..a8b012e293 100644 --- a/crates/openshell-server/proto/sandbox_image.proto +++ b/crates/openshell-server/proto/sandbox_image.proto @@ -13,7 +13,7 @@ message StoredSandboxImageUpdate { string previous_image = 2; string image = 3; uint64 revision = 4; - // Absent for legacy image-only operations. Presence retains selection semantics. + // Presence retains selection semantics. openshell.v1.SandboxCommandUpdate command = 5; openshell.v1.SandboxMapUpdate environment = 6; openshell.v1.SandboxMapUpdate labels = 7; @@ -27,4 +27,6 @@ message StoredSandboxImageState { // Original presence and attempt identity while the interlock is held. // Completion preserves newer diagnostics and clock edits on the live record. openshell.v1.SandboxProvisioning previous_provisioning = 4; + // Exact last successful intent, for idempotent completion across replicas. + StoredSandboxImageUpdate completed = 5; } diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs index 54e2166a08..6a7dc83b33 100644 --- a/crates/openshell-server/src/compute/image_update.rs +++ b/crates/openshell-server/src/compute/image_update.rs @@ -6,8 +6,8 @@ use super::{ComputeRuntime, provisioning_operation, sandbox_compute_runtime_identity}; use crate::storage_proto::StoredSandboxImageUpdate as SandboxImageUpdate; -use openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE; -use openshell_core::proto::compute::v1::UpdateSandboxImageRequest; +use openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION; +use openshell_core::proto::compute::v1::SandboxUpdatePreconditions; use openshell_core::proto::{Sandbox, SandboxPhase}; use openshell_core::{GetResourceVersion, ObjectId, ObjectName}; use tonic::{Request, Status}; @@ -43,50 +43,8 @@ impl ComputeRuntime { update: &openshell_core::proto::UpdateSandboxRequest, ) -> Result { let expected_resource_version = update.expected_resource_version; - let extended = update.command.is_some() - || update.environment.is_some() - || update.labels.is_some() - || update.annotations.is_some(); - let capability_required = if extended { - openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION - } else { - COMPUTE_UPDATE_SANDBOX_IMAGE - }; - // Explicit operator activation follows retirement of incompatible - // gateways and their outstanding driver work. Refuse before preflight - // or durable effects; a cached placement ring is not a version proof. - if !self.sandbox_updates_enabled { - return Err(Status::failed_precondition( - "sandbox updates are disabled; complete the compatible deployment rollout before activating them", - )); - } - self.store - .ensure_image_update_deployment_compatible() - .await - .map_err(|error| match error { - crate::persistence::PersistenceError::Config(message) => { - Status::failed_precondition(message) - } - _ => Status::unavailable("cannot verify image-update deployment compatibility"), - })?; - if !self - .driver_info - .negotiated_extension - .supported_capabilities - .iter() - .any(|capability| capability == capability_required) - { - return Err(Status::unimplemented( - "compute driver does not support storage-preserving sandbox image updates", - )); - } - if self.image_update_driver.is_none() { - return Err(Status::unimplemented( - "compute driver has no registered image updater", - )); - } let lifecycle_guard = self.lifecycle_gates.lock_for(sandbox_id).await; - let sandbox_guard = self.lock_sandbox_for_lifecycle(&lifecycle_guard).await; + let mut sandbox_guard = self.lock_sandbox_for_lifecycle(&lifecycle_guard).await; let current = self .store .get_message::(sandbox_id) @@ -108,6 +66,73 @@ impl ComputeRuntime { .await .map_err(|_| Status::internal("fetch private sandbox image state failed"))?; let pending = state.as_ref().and_then(|state| state.pending.clone()); + let resume = update.image.is_none() + && update.command.is_none() + && update.environment.is_none() + && update.labels.is_none() + && update.annotations.is_none(); + if pending.is_none() { + if resume { + return Err(Status::failed_precondition( + "sandbox has no pending update to resume", + )); + } + if !self.sandbox_updates_enabled { + return Err(Status::failed_precondition( + "sandbox updates are disabled; complete the compatible deployment rollout before activating them", + )); + } + provisioning_operation::ensure_operation_settled(¤t)?; + // Metadata lives only in the gateway. CAS fences lifecycle changes + // and writes the label index in the same transaction as the object. + if update.image.is_none() && update.command.is_none() && update.environment.is_none() { + let mut candidate = current.clone(); + openshell_core::sandbox_update::apply_configuration( + &mut candidate, + None, + None, + update.labels.as_ref(), + update.annotations.as_ref(), + ); + if candidate == current { + return Ok(current); + } + let updated = self + .store + .update_message_cas::( + sandbox_id, + expected_resource_version, + |sandbox| { + openshell_core::sandbox_update::apply_configuration( + sandbox, + None, + None, + update.labels.as_ref(), + update.annotations.as_ref(), + ); + }, + ) + .await + .map_err(|error| { + crate::grpc::persistence_error_to_status(error, "update sandbox metadata") + })?; + self.sandbox_index.update_from_sandbox(&updated); + self.sandbox_watch_bus.notify(sandbox_id); + return Ok(updated); + } + self.store + .ensure_image_update_deployment_compatible() + .await + .map_err(|error| match error { + crate::persistence::PersistenceError::Config(message) => { + Status::failed_precondition(message) + } + _ => { + Status::unavailable("cannot verify sandbox-update deployment compatibility") + } + })?; + } + self.ensure_configuration_update_supported()?; let image = update .image .clone() @@ -121,14 +146,15 @@ impl ComputeRuntime { .ok_or_else(|| Status::failed_precondition("sandbox has no workload image"))?; if let Some(intent) = &pending { ensure_image_update_interlock(¤t, intent)?; - if intent.image != image - || intent.command != update.command - || intent.environment != update.environment - || intent.labels != update.labels - || intent.annotations != update.annotations + if !resume + && (intent.image != image + || intent.command != update.command + || intent.environment != update.environment + || intent.labels != update.labels + || intent.annotations != update.annotations) { return Err(Status::failed_precondition( - "another sandbox update is pending; retry the same selected fields and target values", + "another sandbox update is pending; resume with the current resource version and no selected fields", )); } } else { @@ -171,8 +197,13 @@ impl ComputeRuntime { let accepted = if pending.is_some() { current } else { + // Keep lifecycle operations serialized, but let driver watch events + // and reconciliation progress while preflight waits on the driver. + // The acceptance CAS below rejects any intervening record changes. + drop(sandbox_guard); self.reconcile_sandbox_update(¤t, &intent, true) .await?; + sandbox_guard = self.lock_sandbox_for_lifecycle(&lifecycle_guard).await; // The private intent, selected configuration, and OLD-understood pending // operation flag commit in one version-fenced transaction. self.store @@ -233,14 +264,6 @@ impl ComputeRuntime { validate_only: bool, ) -> Result<(), Status> { let image_update = image_update_driver_request(sandbox, intent, validate_only); - if intent.command.is_none() - && intent.environment.is_none() - && intent.labels.is_none() - && intent.annotations.is_none() - { - self.call_image_update_driver(image_update).await?; - return Ok(()); - } let mut candidate = sandbox.clone(); openshell_core::sandbox_update::apply_configuration( &mut candidate, @@ -268,7 +291,7 @@ impl ComputeRuntime { openshell_core::proto::compute::v1::SandboxEnvironmentUpdate { values } }); let request = openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest { - image_update: Some(image_update), + preconditions: Some(image_update), main_process, environment, }; @@ -289,26 +312,89 @@ impl ComputeRuntime { Ok(()) } - async fn call_image_update_driver( - &self, - request: UpdateSandboxImageRequest, - ) -> Result< - tonic::Response, - Status, - > { - let driver = self.image_update_driver.clone().ok_or_else(|| { - Status::unimplemented("compute driver has no registered image updater") - })?; - let sandbox_id = request.sandbox_id.clone(); - self.driver - .call_owned( - openshell_otel::rpc::UPDATE_SANDBOX_IMAGE, - Some(&sandbox_id), - move |_baseline| async move { - driver.update_sandbox_image(Request::new(request)).await - }, - ) + fn ensure_configuration_update_supported(&self) -> Result<(), Status> { + let capability = COMPUTE_UPDATE_SANDBOX_CONFIGURATION; + if self.image_update_driver.is_none() + || !self + .driver_info + .negotiated_extension + .supported_capabilities + .iter() + .any(|value| value == capability) + { + return Err(Status::unimplemented(format!( + "compute driver does not support {capability}; restore a compatible driver to resume pending updates" + ))); + } + Ok(()) + } + + /// Recover from private durable intent, independent of new-update activation. + pub(super) async fn recover_sandbox_update(&self, sandbox: &Sandbox) -> Result { + let state = self + .store + .get_sandbox_image_state(sandbox.object_id()) .await + .map_err(|_| Status::unavailable("cannot read pending sandbox update"))?; + let Some(intent) = state.and_then(|state| state.pending) else { + return Ok(false); + }; + if sandbox.phase() == SandboxPhase::Deleting as i32 { + return Ok(false); + } + ensure_image_update_stopped(sandbox)?; + self.ensure_configuration_update_supported()?; + self.complete_image_update(sandbox.clone(), intent).await?; + Ok(true) + } + + pub(super) async fn recover_pending_sandbox_updates(&self) -> Result<(), String> { + use futures::StreamExt as _; + let Ok(permit) = self.update_recovery_sweep.clone().try_acquire_owned() else { + return Ok(()); + }; + let ids = self + .list_persisted_sandbox_ids("sandbox update recovery") + .await?; + let runtime = self.clone(); + // Recovery must not hold readiness or unrelated reconciliation hostage + // to a slow remote driver. One bounded sweep per runtime, at most eight + // operations in flight, with the normal per-sandbox lifecycle gate. + tokio::spawn(async move { + let _permit = permit; + futures::stream::iter(ids) + .for_each_concurrent(8, |id| { + let runtime = runtime.clone(); + async move { + if let Err(error) = runtime.recover_one_sandbox_update(&id).await { + tracing::warn!(sandbox_id = %id, %error, + "Sandbox update remains pending; recovery will retry"); + } + } + }) + .await; + }); + Ok(()) + } + + async fn recover_one_sandbox_update(&self, id: &str) -> Result<(), Status> { + let Some(_gate) = self.lifecycle_gates.try_lock_for(id) else { + return Ok(()); + }; + let recover = async { + let sandbox = self + .store + .get_message::(id) + .await + .map_err(|_| Status::unavailable("cannot read sandbox for update recovery"))?; + if let Some(sandbox) = sandbox { + self.recover_sandbox_update(&sandbox).await?; + } + Ok(()) + }; + tokio::time::timeout(std::time::Duration::from_mins(1), recover) + .await + .map_err(|_| Status::deadline_exceeded("sandbox update recovery timed out"))? } pub(super) async fn ensure_no_pending_image_update( @@ -322,14 +408,14 @@ impl ComputeRuntime { .map_err(|_| Status::unavailable("cannot read private sandbox image state"))?; if state.as_ref().is_some_and(|state| state.pending.is_some()) { return Err(Status::failed_precondition( - "sandbox update is pending; read the current resource version and retry UpdateSandbox with the same selected fields and target values before starting", + "sandbox update is pending; recovery will retry automatically, or resume UpdateSandbox with the current resource version and no selected fields", )); } Ok(()) } } -fn ensure_image_update_interlock( +pub(super) fn ensure_image_update_interlock( sandbox: &Sandbox, intent: &SandboxImageUpdate, ) -> Result<(), Status> { @@ -352,8 +438,8 @@ fn image_update_driver_request( sandbox: &Sandbox, intent: &SandboxImageUpdate, validate_only: bool, -) -> UpdateSandboxImageRequest { - UpdateSandboxImageRequest { +) -> SandboxUpdatePreconditions { + SandboxUpdatePreconditions { sandbox_id: sandbox.object_id().to_string(), name: sandbox.object_name().to_string(), image: intent.image.clone(), @@ -373,7 +459,7 @@ fn ensure_image_update_stopped(sandbox: &Sandbox) -> Result<(), Status> { .is_some_and(|metadata| metadata.deletion_time.is_some()) { return Err(Status::failed_precondition( - "sandbox must be Stopped before updating its image", + "sandbox must be Stopped before updating its configuration", )); } Ok(()) @@ -420,10 +506,7 @@ mod tests { .driver_info .negotiated_extension .supported_capabilities - .extend([ - COMPUTE_UPDATE_SANDBOX_IMAGE.into(), - openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION.into(), - ]); + .extend([COMPUTE_UPDATE_SANDBOX_CONFIGURATION.into()]); } let mut sandbox = Sandbox { metadata: Some(ObjectMeta { @@ -465,7 +548,7 @@ mod tests { (runtime, driver, sandbox) } - fn image_calls(driver: &FakeComputeDriver) -> Vec { + fn image_calls(driver: &FakeComputeDriver) -> Vec { driver .calls() .into_iter() @@ -478,6 +561,267 @@ mod tests { .collect() } + #[tokio::test] + async fn startup_does_not_wait_for_a_blocked_update_driver() { + use std::time::Duration; + for manages_lifecycle in [false, true] { + let (mut runtime, driver, original) = fixture(true).await; + runtime.driver_info.gateway_manages_lifecycle = manages_lifecycle; + driver.set_image_update_error(Some(Code::Unavailable)); + runtime + .update_sandbox_image( + original.object_id(), + "new-image".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + driver.set_image_update_error(None); + let (entered, release) = driver.pause_image_updates(); + tokio::time::timeout(Duration::from_secs(2), runtime.start_persisted_sandboxes()) + .await + .expect("startup must not wait on update recovery") + .unwrap(); + tokio::time::timeout(Duration::from_secs(2), entered.notified()) + .await + .expect("startup must schedule update recovery"); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap() + .pending + .is_some() + ); + release.add_permits(1); + drop(runtime.update_recovery_sweep.acquire().await.unwrap()); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap() + .pending + .is_none() + ); + } + } + + #[tokio::test] + async fn recovery_uses_stored_selection_even_when_admission_is_disabled() { + use openshell_core::proto::{SandboxCommandUpdate, SandboxMapUpdate, UpdateSandboxRequest}; + for automatic in [false, true] { + let (mut runtime, driver, original) = fixture(true).await; + driver.set_image_update_error(Some(Code::Unavailable)); + let update = UpdateSandboxRequest { + command: Some(SandboxCommandUpdate { + argv: vec!["sleep".into(), "infinity".into()], + }), + environment: Some(SandboxMapUpdate::default()), + expected_resource_version: original.get_resource_version(), + ..Default::default() + }; + runtime + .update_sandbox_configuration(original.object_id(), &update) + .await + .unwrap_err(); + runtime.sandbox_updates_enabled = false; + // Missing driver support keeps the intent; restoring it is enough + // for recovery, without re-enabling admission or reconstructing fields. + let updater = runtime.image_update_driver.take(); + runtime.recover_pending_sandbox_updates().await.unwrap(); + drop(runtime.update_recovery_sweep.acquire().await.unwrap()); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap() + .pending + .is_some() + ); + runtime.image_update_driver = updater; + driver.set_image_update_error(None); + let pending = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + if automatic { + runtime.recover_pending_sandbox_updates().await.unwrap(); + drop(runtime.update_recovery_sweep.acquire().await.unwrap()); + } else { + runtime + .update_sandbox_configuration( + original.object_id(), + &UpdateSandboxRequest { + expected_resource_version: pending.get_resource_version(), + ..Default::default() + }, + ) + .await + .unwrap(); + } + let complete = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + assert_eq!(complete.spec, pending.spec); + assert!(provisioning_operation::ensure_operation_settled(&complete).is_ok()); + let calls = image_calls(&driver); + assert_eq!(calls.len(), 2); + assert_eq!(calls[0], calls[1]); + } + } + + #[tokio::test] + async fn metadata_only_update_preserves_retention_and_needs_no_driver_capability() { + use openshell_core::proto::{SandboxMapUpdate, UpdateSandboxRequest}; + let (runtime, driver, mut original) = fixture(false).await; + original.metadata.as_mut().unwrap().annotations.extend([ + ("openshell.nvidia.com/retention".into(), "ephemeral".into()), + ("openshell.ai/user-note".into(), "old".into()), + ]); + runtime.store.put_message(&original).await.unwrap(); + let original = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + let updated = runtime + .update_sandbox_configuration( + original.object_id(), + &UpdateSandboxRequest { + labels: Some(SandboxMapUpdate { + values: HashMap::from([("team".into(), "new".into())]), + }), + annotations: Some(SandboxMapUpdate { + values: HashMap::from([("openshell.ai/user-note".into(), "new".into())]), + }), + expected_resource_version: original.get_resource_version(), + ..Default::default() + }, + ) + .await + .unwrap(); + assert_eq!( + updated.metadata.as_ref().unwrap().annotations["openshell.nvidia.com/retention"], + "ephemeral" + ); + assert_eq!( + updated.metadata.as_ref().unwrap().annotations["openshell.ai/user-note"], + "new" + ); + let noop = runtime + .update_sandbox_configuration( + original.object_id(), + &UpdateSandboxRequest { + labels: Some(SandboxMapUpdate { + values: updated.metadata.as_ref().unwrap().labels.clone(), + }), + expected_resource_version: updated.get_resource_version(), + ..Default::default() + }, + ) + .await + .unwrap(); + assert_eq!(noop, updated); + assert_eq!(updated.spec, original.spec); + assert_eq!(updated.status, original.status); + assert!(image_calls(&driver).is_empty()); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_none() + ); + let record = runtime + .store + .get("sandbox", original.object_id()) + .await + .unwrap() + .unwrap(); + let labels: serde_json::Value = + serde_json::from_str(record.labels.as_ref().unwrap()).unwrap(); + assert_eq!(labels["team"], "new"); + assert_eq!( + runtime + .update_sandbox_configuration( + original.object_id(), + &UpdateSandboxRequest { + labels: Some(SandboxMapUpdate::default()), + expected_resource_version: original.get_resource_version(), + ..Default::default() + } + ) + .await + .unwrap_err() + .code(), + Code::Aborted + ); + } + + #[tokio::test] + async fn explicit_delete_supersedes_pending_update_without_restoring_the_driver() { + let (mut runtime, driver, original) = fixture(true).await; + driver.set_image_update_error(Some(Code::Unavailable)); + runtime + .update_sandbox_image( + original.object_id(), + "new-image".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + let intent = runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap() + .pending + .unwrap(); + runtime.image_update_driver = None; + runtime.sandbox_updates_enabled = false; + runtime + .delete_sandbox("default", original.object_name()) + .await + .unwrap(); + assert!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .is_none() + ); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_none() + ); + assert!( + runtime + .store + .complete_sandbox_image_update(original.object_id(), &intent) + .await + .is_err() + ); + } + #[tokio::test] async fn configuration_update_reconciles_all_fields_and_recovers_exact_pending_target() { use openshell_core::proto::{SandboxCommandUpdate, SandboxMapUpdate, UpdateSandboxRequest}; @@ -609,10 +953,7 @@ mod tests { .driver_info .negotiated_extension .supported_capabilities - .retain(|capability| { - capability - != openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION - }); + .retain(|capability| capability != COMPUTE_UPDATE_SANDBOX_CONFIGURATION); let update = openshell_core::proto::UpdateSandboxRequest { command: Some(SandboxCommandUpdate::default()), expected_resource_version: original.get_resource_version(), @@ -919,6 +1260,95 @@ mod tests { ); } + #[tokio::test] + async fn image_preflight_allows_watch_progress_and_rejects_intervening_changes() { + use openshell_core::proto::compute::v1::{ + WatchSandboxesEvent, WatchSandboxesSandboxEvent, watch_sandboxes_event, + }; + use std::time::Duration; + + let (runtime, driver, original) = fixture(true).await; + let mut unrelated = original.clone(); + let metadata = unrelated.metadata.as_mut().unwrap(); + metadata.id = "unrelated-sandbox-id".into(); + metadata.name = "unrelated-sandbox".into(); + runtime.store.put_message(&unrelated).await.unwrap(); + let unrelated = runtime + .store + .get_message::(unrelated.object_id()) + .await + .unwrap() + .unwrap(); + let (entered, release) = driver.pause_image_updates(); + let update = { + let runtime = runtime.clone(); + let original = original.clone(); + tokio::spawn(async move { + runtime + .update_sandbox_image( + original.object_id(), + "example/workload:new".into(), + original.get_resource_version(), + ) + .await + }) + }; + tokio::time::timeout(Duration::from_secs(2), entered.notified()) + .await + .expect("update must reach preflight"); + + // Process snapshots in watch-loop order. The event for the sandbox + // being validated must not hold up the following unrelated event. + tokio::time::timeout(Duration::from_secs(2), async { + for sandbox in [&original, &unrelated] { + runtime + .apply_watch_event(WatchSandboxesEvent { + payload: Some(watch_sandboxes_event::Payload::Sandbox( + WatchSandboxesSandboxEvent { + sandbox: Some(DriverSandbox { + id: sandbox.object_id().into(), + name: sandbox.object_name().into(), + ..Default::default() + }), + }, + )), + }) + .await + .unwrap(); + } + }) + .await + .expect("watch events must progress while preflight is paused"); + for sandbox in [&original, &unrelated] { + let observed = runtime + .store + .get_message::(sandbox.object_id()) + .await + .unwrap() + .unwrap(); + assert!(observed.get_resource_version() > sandbox.get_resource_version()); + assert_eq!(observed.spec, sandbox.spec); + } + + // The original conditional request is now stale. Preflight success + // must not commit intent or issue a mutating driver call. + release.add_permits(1); + let result = tokio::time::timeout(Duration::from_secs(2), update) + .await + .expect("stale update must finish without applying") + .unwrap(); + assert_eq!(result.unwrap_err().code(), Code::Aborted); + assert!(image_calls(&driver).is_empty()); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_none() + ); + } + #[tokio::test] async fn concurrent_image_updates_cannot_overwrite_each_other() { let (runtime, driver, original) = fixture(true).await; @@ -984,6 +1414,80 @@ mod tests { } } + #[tokio::test] + async fn terminal_workload_can_stop_update_command_and_start() { + use openshell_core::proto::{SandboxCommandUpdate, UpdateSandboxRequest}; + + for exit_code in [0, 1, 137] { + let (runtime, driver, mut original) = fixture(true).await; + crate::auth::sandbox_session::PersistedSandboxIdentity::new() + .unwrap() + .write(&mut original.metadata.as_mut().unwrap().annotations); + original.spec.as_mut().unwrap().command = + vec!["/bin/sh".into(), "-c".into(), format!("exit {exit_code}")]; + super::super::apply_main_process_exit(&mut original, "exited-instance", exit_code); + runtime.store.put_message(&original).await.unwrap(); + + let stopped = runtime + .stop_sandbox("default", original.object_name()) + .await + .unwrap(); + assert_eq!(stopped.phase(), SandboxPhase::Stopped as i32); + assert_eq!(stopped.status.as_ref().unwrap().exit_code, Some(exit_code)); + assert_eq!( + stopped.status.as_ref().unwrap().main_process_instance_id, + "exited-instance" + ); + assert_eq!(stopped.spec, original.spec); + assert_eq!(stopped.object_id(), original.object_id()); + assert_eq!(stopped.host_key_fingerprint, original.host_key_fingerprint); + let repeated = runtime + .stop_sandbox("default", original.object_name()) + .await + .unwrap(); + assert_eq!(repeated, stopped); + + let command = vec!["sleep".into(), "infinity".into()]; + let updated = runtime + .update_sandbox_configuration( + original.object_id(), + &UpdateSandboxRequest { + command: Some(SandboxCommandUpdate { + argv: command.clone(), + }), + expected_resource_version: stopped.get_resource_version(), + ..Default::default() + }, + ) + .await + .unwrap(); + assert_eq!(updated.phase(), SandboxPhase::Stopped as i32); + assert_eq!(updated.spec.as_ref().unwrap().command, command); + assert_eq!(updated.status.as_ref().unwrap().exit_code, Some(exit_code)); + let starting = runtime + .start_sandbox("default", original.object_name()) + .await + .unwrap(); + assert_eq!(starting.phase(), SandboxPhase::Starting as i32); + assert_eq!(starting.spec, updated.spec); + assert_eq!(starting.status.as_ref().unwrap().exit_code, None); + let calls = driver.calls(); + assert_eq!( + calls + .iter() + .filter(|call| matches!(call, FakeComputeDriverCall::StopSandbox { .. })) + .count(), + 1, + "terminal compute must be stopped once before updating" + ); + assert!(!calls.iter().any(|call| matches!( + call, + FakeComputeDriverCall::DeleteSandbox { .. } + | FakeComputeDriverCall::CreateSandbox { .. } + ))); + } + } + #[tokio::test] async fn image_update_can_roll_back_after_start_timeout_cleanup() { let (runtime, driver, mut original) = fixture(true).await; @@ -1424,14 +1928,6 @@ mod tests { .code(), Code::FailedPrecondition ); - assert_eq!( - runtime - .delete_sandbox("default", original.object_name()) - .await - .unwrap_err() - .code(), - Code::FailedPrecondition - ); runtime .recover_persisted_lifecycle_transitions() .await diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index 5fbb083382..4cfafa3b63 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -43,7 +43,6 @@ use openshell_core::proto::compute::v1::{ ResourceRequirements as DriverSandboxResourceRequirements, StartSandboxRequest, StopSandboxRequest, SuspendSandboxRequest, ValidateSandboxCreateRequest, WatchSandboxesEvent, WatchSandboxesRequest, WorkloadIdentityRequest, compute_driver_client::ComputeDriverClient, - compute_driver_image_updates_client::ComputeDriverImageUpdatesClient, compute_driver_server::ComputeDriver, watch_sandboxes_event, }; use openshell_core::proto::{ @@ -88,8 +87,8 @@ pub type DriverWatchStream = pub type SharedComputeDriver = Arc + Send + Sync>; -/// Optional image-update registration, independent of the baseline driver object. -pub type SharedComputeDriverImageUpdates = Arc< +/// Optional configuration-update registration, independent of the baseline driver object. +pub type SharedComputeDriverConfigurationUpdates = Arc< dyn openshell_core::compute::ComputeDriver + Send + Sync, @@ -438,9 +437,7 @@ impl QuiesceOperation { let phase = SandboxPhase::try_from(sandbox.phase()).unwrap_or(SandboxPhase::Unknown); match self { Self::Stop => { - if matches!(phase, SandboxPhase::Stopped | SandboxPhase::Completed) - || is_failed_main_process_result(sandbox) - { + if phase == SandboxPhase::Stopped { return Ok(QuiesceAdmission::Settled); } // Timeout cleanup owns reclamation until it completes. Once @@ -458,7 +455,8 @@ impl QuiesceOperation { "sandbox provisioning timed out; wait for timeout cleanup before stop or start", )); } - // Error does not prove compute has stopped. Use the normal + // Neither a main-process exit nor an infrastructure Error + // proves compute has stopped. Use the normal // driver stop and session cleanup before a subsequent start // renews authentication and repeats configuration admission // for the retained sandbox. Stopping a suspended sandbox @@ -467,6 +465,7 @@ impl QuiesceOperation { if !matches!( phase, SandboxPhase::Ready + | SandboxPhase::Completed | SandboxPhase::Stopping | SandboxPhase::Error | SandboxPhase::Suspending @@ -474,7 +473,7 @@ impl QuiesceOperation { ) && !is_automatic_restart_transition(sandbox) { return Err(Status::failed_precondition(format!( - "sandbox must be Ready, Suspended, Error, or in an automatic restart to stop (current phase: {phase:?})" + "sandbox must be Ready, Completed, Suspended, Error, or in an automatic restart to stop (current phase: {phase:?})" ))); } Ok(if phase == SandboxPhase::Stopping { @@ -686,9 +685,6 @@ impl AcquiredRemoteDriverEndpoint { struct RemoteComputeDriver { client: RemoteComputeDriverClient, configuration_updates_client: openshell_core::proto::compute::v1::compute_driver_configuration_updates_client::ComputeDriverConfigurationUpdatesClient>, - image_updates_client: ComputeDriverImageUpdatesClient< - tonic::service::interceptor::InterceptedService, - >, admission_acknowledgement: Arc>>, } @@ -700,11 +696,7 @@ impl RemoteComputeDriver { fn new(channel: Channel) -> Self { 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.clone(), TraceContextInterceptor), - image_updates_client: ComputeDriverImageUpdatesClient::with_interceptor( - channel, - 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)), } } @@ -760,21 +752,6 @@ impl openshell_core::compute::ComputeDriver for RemoteComputeDriver { .update_sandbox_configuration(request) .await } - - async fn update_sandbox_image( - &self, - request: Request, - ) -> Result< - tonic::Response, - Status, - > { - // An image-only update does not install an external isolation route. - self.verify_admission_policy(false).await?; - self.image_updates_client - .clone() - .update_sandbox_image(request) - .await - } } #[tonic::async_trait] @@ -933,13 +910,14 @@ pub struct ComputeRuntime { admission: openshell_core::resource_admission::DriverAdmissionConfig, admission_acknowledgement: String, driver: TracedDriver, - image_update_driver: Option, + image_update_driver: Option, driver_info: ComputeDriverInfoSnapshot, telemetry_compute_driver: TelemetryComputeDriver, driver_process: Option>, default_image: String, image_preparation_timeout_seconds: u32, sandbox_updates_enabled: bool, + update_recovery_sweep: Arc, store: Arc, sandbox_index: SandboxIndex, sandbox_watch_bus: SandboxWatchBus, @@ -1058,6 +1036,7 @@ impl ComputeRuntime { default_image, image_preparation_timeout_seconds: 1800, sandbox_updates_enabled: false, + update_recovery_sweep: Arc::new(tokio::sync::Semaphore::new(1)), store, sandbox_index, sandbox_watch_bus, @@ -1206,7 +1185,7 @@ impl ComputeRuntime { pub(crate) fn with_image_update_driver( mut self, - driver: Option, + driver: Option, ) -> Self { self.image_update_driver = driver; self @@ -3496,7 +3475,23 @@ impl ComputeRuntime { .map_err(|e| Status::internal(format!("fetch sandbox failed: {e}")))? .ok_or_else(|| Status::not_found("sandbox not found"))?, }; - provisioning_operation::ensure_operation_settled(&sandbox)?; + // Explicit deletion can supersede a configuration update: the + // driver only patches an existing immutable resource and cannot + // recreate it after deletion. Keep the interlock until removal so + // a failed delete can safely restore the pending update. + let pending_update = self + .store + .get_sandbox_image_state(sandbox_id) + .await + .map_err(|_| Status::unavailable("cannot read pending sandbox update"))? + .and_then(|state| state.pending); + if failed_create.is_none() + && let Some(intent) = pending_update + { + image_update::ensure_image_update_interlock(&sandbox, &intent)?; + } else { + provisioning_operation::ensure_operation_settled(&sandbox)?; + } // Failed-create compensation owns only its original attempt. // Preserve its timeout diagnosis and any replacement attempt on @@ -3652,7 +3647,9 @@ impl ComputeRuntime { let mut delete_resource_version = record.resource_version; let mut sandbox = decode_sandbox_record(&record)?; - if provisioning_deadline::driver_operation_pending(&sandbox) { + if provisioning_deadline::driver_operation_pending(&sandbox) + && sandbox.phase() != SandboxPhase::Deleting as i32 + { return Ok(false); } if sandbox.phase() != SandboxPhase::Deleting as i32 { @@ -4167,7 +4164,7 @@ impl ComputeRuntime { { Box::pin(self.recover_persisted_lifecycle_transitions()).await?; if !self.driver_info.gateway_manages_lifecycle { - return Ok(()); + return self.recover_pending_sandbox_updates().await; } let sandbox_ids = self.list_persisted_sandbox_ids("gateway startup").await?; @@ -4427,7 +4424,7 @@ impl ComputeRuntime { "Sandbox start sweep complete" ); } - Ok(()) + self.recover_pending_sandbox_updates().await } async fn recover_persisted_lifecycle_transitions(&self) -> Result<(), String> { @@ -4448,7 +4445,9 @@ impl ComputeRuntime { continue; } }; - if provisioning_deadline::driver_operation_pending(&sandbox) { + if provisioning_deadline::driver_operation_pending(&sandbox) + && sandbox.phase() != SandboxPhase::Deleting as i32 + { warn!( sandbox_id, "Retaining pending driver operation during gateway recovery" @@ -4857,6 +4856,9 @@ impl ComputeRuntime { async fn reconcile_loop(self: Arc, mut cancel: watch::Receiver) { loop { + if let Err(error) = self.recover_pending_sandbox_updates().await { + warn!(%error, "Sandbox update recovery sweep failed"); + } if let Err(err) = self.reconcile_store_with_backend(ORPHAN_GRACE_PERIOD).await { warn!(error = %err, "Store reconciliation sweep failed"); } @@ -6176,7 +6178,8 @@ impl ComputeRuntime { // Timeout cleanup can emit Deleted before an explicit stop exposes // Stopped for repair. A delayed (or repeated) event must retain that // recovery record too; explicit deletion still transitions to Deleting. - if provisioning_deadline::driver_operation_pending(sandbox) + if (provisioning_deadline::driver_operation_pending(sandbox) + && sandbox.phase() != SandboxPhase::Deleting as i32) || (provisioning_deadline::timed_out(sandbox) && matches!( SandboxPhase::try_from(sandbox.phase()), @@ -6217,7 +6220,9 @@ impl ComputeRuntime { sandbox: &Sandbox, expected_resource_version: u64, ) -> Result<(), String> { - if provisioning_deadline::driver_operation_pending(sandbox) { + if provisioning_deadline::driver_operation_pending(sandbox) + && sandbox.phase() != SandboxPhase::Deleting as i32 + { return Ok(()); } let sandbox_id = sandbox.object_id(); @@ -6546,7 +6551,9 @@ impl ComputeRuntime { } let sandbox = decode_sandbox_record(¤t_record)?; - if provisioning_deadline::driver_operation_pending(&sandbox) { + if provisioning_deadline::driver_operation_pending(&sandbox) + && sandbox.phase() != SandboxPhase::Deleting as i32 + { return Ok(()); } let age_ms = openshell_core::time::now_ms() @@ -8051,6 +8058,9 @@ fn apply_lifecycle_phase( message: &str, image_preparation_timeout_seconds: u32, ) { + let preserve_exit_code = phase == SandboxPhase::Stopping + && (sandbox.phase() == SandboxPhase::Completed as i32 + || is_failed_main_process_result(sandbox)); sandbox.set_phase(phase as i32); // Every explicit lifecycle write ends the previous transition's resume // intent. A resuming start records a new one after this write. @@ -8066,7 +8076,11 @@ fn apply_lifecycle_phase( let status = sandbox.status.get_or_insert_with(Default::default); // Retain the previous instance id as a tombstone until the restarted // supervisor registers its new id. - status.exit_code = None; + // Explicit stop preserves an already-recorded terminal result for + // diagnosis while the sandbox is repaired. A fresh start clears it. + if !preserve_exit_code { + status.exit_code = None; + } status.restart_count = 0; set_next_restart_at_ms(status, 0); set_main_process_started_at_ms(status, 0); @@ -8505,6 +8519,7 @@ pub fn new_test_runtime_with_driver( default_image: "openshell/sandbox:test".to_string(), image_preparation_timeout_seconds: 1800, sandbox_updates_enabled: false, + update_recovery_sweep: Arc::new(tokio::sync::Semaphore::new(1)), store, sandbox_index: SandboxIndex::new(), sandbox_watch_bus: SandboxWatchBus::new(), @@ -9706,6 +9721,7 @@ mod tests { default_image: "openshell/sandbox:test".to_string(), image_preparation_timeout_seconds: 1800, sandbox_updates_enabled: false, + update_recovery_sweep: Arc::new(Semaphore::new(1)), store, sandbox_index: SandboxIndex::new(), sandbox_watch_bus: SandboxWatchBus::new(), @@ -17707,10 +17723,15 @@ mod tests { .await .unwrap(); remote - .update_sandbox_image(Request::new( - openshell_core::proto::compute::v1::UpdateSandboxImageRequest { - sandbox_id: sandbox.id.clone(), - image: "example/workload:v2".into(), + .update_sandbox_configuration(Request::new( + openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest { + preconditions: Some( + openshell_core::proto::compute::v1::SandboxUpdatePreconditions { + sandbox_id: sandbox.id.clone(), + image: "example/workload:v2".into(), + ..Default::default() + }, + ), ..Default::default() }, )) @@ -18344,9 +18365,11 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" .await .is_err() ); - let status = openshell_core::compute::ComputeDriver::update_sandbox_image( + let status = openshell_core::compute::ComputeDriver::update_sandbox_configuration( &remote, - Request::new(openshell_core::proto::compute::v1::UpdateSandboxImageRequest::default()), + Request::new( + openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest::default(), + ), ) .await .unwrap_err(); @@ -18362,7 +18385,7 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" async fn remote_compute_driver_negotiates_optional_image_service() { use crate::test_support::{FakeComputeDriver, FakeComputeDriverCall}; use openshell_core::GetResourceVersion as _; - use openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE; + use openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION; for supported in [false, true] { let dir = tempfile::tempdir().unwrap(); @@ -18406,7 +18429,7 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" .negotiated_extension .supported_capabilities .iter() - .any(|capability| capability == COMPUTE_UPDATE_SANDBOX_IMAGE), + .any(|capability| capability == COMPUTE_UPDATE_SANDBOX_CONFIGURATION), supported, ); let mut sandbox = sandbox_record("sb-image", "image-sandbox", SandboxPhase::Stopped); @@ -18489,9 +18512,22 @@ endpoint = { kind = "unix", socket_path = "/run/agent-substrate/isolation.sock" .driver_info .negotiated_extension .supported_capabilities - .push(openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.into()); + .push(openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION.into()); + let mut sandbox = sandbox_record( + "unsupported-update", + "unsupported-update", + SandboxPhase::Stopped, + ); + sandbox.spec = Some(SandboxSpec { + template: Some(SandboxTemplate { + image: "example/workload:v1".into(), + ..Default::default() + }), + ..Default::default() + }); + runtime.store.put_message(&sandbox).await.unwrap(); let error = runtime - .update_sandbox_image("not-created", "example/workload:v2".into(), 1) + .update_sandbox_image("unsupported-update", "example/workload:v2".into(), 1) .await .unwrap_err(); assert_eq!(error.code(), Code::Unimplemented); diff --git a/crates/openshell-server/src/compute_factory_compatibility.rs b/crates/openshell-server/src/compute_factory_compatibility.rs index 3ce003dd97..57552446de 100644 --- a/crates/openshell-server/src/compute_factory_compatibility.rs +++ b/crates/openshell-server/src/compute_factory_compatibility.rs @@ -13,7 +13,7 @@ use crate::test_support::FakeComputeDriver; use crate::{ ComputeDriverBuildContext, ComputeDriverFactory, ComputeDriverInstance, ComputeDriverRegistration, ComputeDriverRegistry, DriverWatchStream, SharedComputeDriver, - SharedComputeDriverImageUpdates, + SharedComputeDriverConfigurationUpdates, }; // Written using only the baseline generated trait, not the new optional trait. @@ -53,12 +53,12 @@ impl ComputeDriverFactory for OptInFactory { Ok(ComputeDriverInstance::InProcess(self.driver.clone())) } - async fn build_with_image_updates( + async fn build_with_configuration_updates( &self, _context: ComputeDriverBuildContext<'_>, ) -> openshell_core::Result<( ComputeDriverInstance, - Option, + Option, )> { self.opt_in_calls.fetch_add(1, Ordering::SeqCst); Ok(( @@ -79,11 +79,33 @@ async fn registered_runtime(factory: impl ComputeDriverFactory + 'static) -> cra let startup = crate::compute::driver_config::DriverStartupContext { file: None, guest_tls: None, + network_trust: None, + network_trust_configured: false, gateway_port: 8080, gateway_tls_enabled: false, endpoint_overrides: &overrides, }; let store = Arc::new(crate::persistence::test_store().await); + crate::ensure_default_workspace(&store).await.unwrap(); + let mut sandbox = openshell_core::proto::Sandbox { + metadata: Some(openshell_core::proto::ObjectMeta { + id: "fixture-sandbox".into(), + name: "fixture-sandbox".into(), + workspace: "default".into(), + ..Default::default() + }), + spec: Some(openshell_core::proto::SandboxSpec { + template: Some(openshell_core::proto::SandboxTemplate { + image: "example/workload:v1".into(), + ..Default::default() + }), + ..Default::default() + }), + ..Default::default() + }; + sandbox.set_phase(openshell_core::proto::SandboxPhase::Stopped as i32); + store.put_message(&sandbox).await.unwrap(); + crate::build_compute_runtime( ®istry, &selection, @@ -120,7 +142,7 @@ async fn baseline_factory_and_trait_object_still_build_without_opt_in() { assert_eq!(calls.load(Ordering::SeqCst), 1); assert_eq!( runtime - .update_sandbox_image("not-created", "example/workload:v2".into(), 1) + .update_sandbox_image("fixture-sandbox", "example/workload:v2".into(), 1) .await .unwrap_err() .code(), @@ -139,7 +161,7 @@ async fn capability_alone_does_not_register_an_in_process_image_updater() { driver.clear_calls(); assert_eq!( runtime - .update_sandbox_image("not-created", "example/workload:v2".into(), 1) + .update_sandbox_image("fixture-sandbox", "example/workload:v2".into(), 1) .await .unwrap_err() .code(), @@ -160,13 +182,12 @@ async fn registered_opt_in_hook_supplies_the_optional_updater() { .await; assert_eq!(legacy_calls.load(Ordering::SeqCst), 0); assert_eq!(opt_in_calls.load(Ordering::SeqCst), 1); - // Passing capability/registration admission reaches the sandbox lookup. + let updated = runtime + .update_sandbox_image("fixture-sandbox", "example/workload:v2".into(), 1) + .await + .unwrap(); assert_eq!( - runtime - .update_sandbox_image("not-created", "example/workload:v2".into(), 1) - .await - .unwrap_err() - .code(), - tonic::Code::NotFound + updated.spec.unwrap().template.unwrap().image, + "example/workload:v2" ); } diff --git a/crates/openshell-server/src/gateway_members.rs b/crates/openshell-server/src/gateway_members.rs index a61df4b509..b70bf5f82f 100644 --- a/crates/openshell-server/src/gateway_members.rs +++ b/crates/openshell-server/src/gateway_members.rs @@ -16,6 +16,9 @@ use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; +/// Initial stopped-sandbox configuration update protocol advertised by gateways. +pub const SANDBOX_UPDATE_PROTOCOL: u32 = 1; + const MEMBER_OBJECT_TYPE: &str = "gateway_member"; /// How long a membership record stays valid without a refresh. @@ -45,7 +48,7 @@ struct MemberPayload { peer_endpoint: String, /// Binary capability, not feature activation. Missing denotes old replicas. #[serde(default)] - image_update_protocol: u32, + sandbox_update_protocol: u32, } /// A gateway replica that was alive as of its last refresh. @@ -74,7 +77,7 @@ impl GatewayMemberIndex { let payload = MemberPayload { replica_id: replica_id.to_string(), peer_endpoint: peer_endpoint.to_string(), - image_update_protocol: 2, + sandbox_update_protocol: SANDBOX_UPDATE_PROTOCOL, }; let bytes = serde_json::to_vec(&payload) .map_err(|err| PersistenceError::Encode(err.to_string()))?; diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index a80d7df2a7..4b5011c623 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -379,16 +379,6 @@ fn validate_image_update_request( "expected_resource_version must be nonzero", )); } - if request.image.is_none() - && request.command.is_none() - && request.environment.is_none() - && request.labels.is_none() - && request.annotations.is_none() - { - return Err(Status::invalid_argument( - "at least one update field is required", - )); - } if let Some(image) = &request.image && (image.is_empty() || image.len() > super::MAX_TEMPLATE_STRING_LEN @@ -402,7 +392,6 @@ fn validate_image_update_request( .into_iter() .flatten() { - super::validation::validate_annotations(&map.values, "metadata")?; if map .values .keys() @@ -414,9 +403,10 @@ fn validate_image_update_request( } } if let Some(labels) = &request.labels { - for value in labels.values.values() { - super::validation::validate_label_value(value)?; - } + super::validation::validate_labels(&labels.values)?; + } + if let Some(annotations) = &request.annotations { + super::validation::validate_annotations(&annotations.values, "annotations")?; } Ok(()) } @@ -892,10 +882,7 @@ fn validate_create_sandbox_request_pre_io( workload_template_name: &str, ) -> Result<(), Status> { // Validate labels (keys and values must meet Kubernetes requirements). - for (key, value) in &request.labels { - crate::grpc::validation::validate_label_key(key)?; - crate::grpc::validation::validate_label_value(value)?; - } + 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 { 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 50b1a9a96e..e8c7b764ab 100644 --- a/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs +++ b/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs @@ -135,10 +135,7 @@ async fn state() -> (Arc, Arc, Sandbox) { openshell_core::extension_protocol::ExtensionFamily::Compute, "openshell/image-test", "test", - [ - openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.into(), - openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION.into(), - ], + [openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION.into()], )), ..Default::default() }), @@ -287,7 +284,7 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re let replay = client.update_sandbox(req.clone()).await.unwrap(); assert_eq!(replay.metadata().get("openshell-replayed").unwrap(), "true"); assert_eq!(replay.get_ref().sandbox.as_ref().unwrap(), &updated); - assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxConfiguration { request } if !request.image_update.as_ref().unwrap().validate_only)).count(), 1); + assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxConfiguration { request } if !request.preconditions.as_ref().unwrap().validate_only)).count(), 1); let changed = UpdateSandboxRequest { image: Some("example/workload:other".into()), ..req.clone() @@ -317,20 +314,29 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re .unwrap() .unwrap(); assert_eq!(replacement.spec, sandbox.spec); - assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxConfiguration { request } if !request.image_update.as_ref().unwrap().validate_only)).count(), 1); + assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxConfiguration { request } if !request.preconditions.as_ref().unwrap().validate_only)).count(), 1); } #[test] fn configuration_update_presence_and_reserved_metadata() { let mut update = request(); update.image = None; - assert!(validate_image_update_request(&update).is_err()); + assert!(validate_image_update_request(&update).is_ok()); update.command = Some(SandboxCommandUpdate::default()); validate_image_update_request(&update).unwrap(); + // User metadata under these domains was accepted at creation and remains + // editable; only explicit gateway identity and lifecycle keys are reserved. + for key in ["openshell.ai/user-note", "agents.x-k8s.io/user-note"] { + update.annotations = Some(openshell_core::proto::SandboxMapUpdate { + values: HashMap::from([(key.into(), "new".into())]), + }); + validate_image_update_request(&update).unwrap(); + } + update.annotations = None; for key in [ "internal.openshell.ai/auth-epoch", - "openshell.ai/identity", - "agents.x-k8s.io/name", + "openshell.ai/sandbox-id", + "openshell.nvidia.com/retention", ] { update.annotations = Some(openshell_core::proto::SandboxMapUpdate { values: HashMap::from([(key.into(), "forged".into())]), @@ -399,7 +405,13 @@ async fn pending_update_retry_preserves_later_update_config_annotations() { .await .unwrap() .unwrap(); - update.expected_resource_version = current.get_resource_version(); + // Resume from stored intent, without knowing the original selection mask. + update = UpdateSandboxRequest { + workspace_scope: update.workspace_scope, + name: update.name, + expected_resource_version: current.get_resource_version(), + ..Default::default() + }; driver.set_image_update_error(None); let completed = handle_update_sandbox(&state, authed_request(update)) .await diff --git a/crates/openshell-server/src/grpc/validation.rs b/crates/openshell-server/src/grpc/validation.rs index 8dd62c5c57..a5152bc80b 100644 --- a/crates/openshell-server/src/grpc/validation.rs +++ b/crates/openshell-server/src/grpc/validation.rs @@ -459,6 +459,27 @@ pub(super) fn validate_string_map( Ok(()) } +/// Labels share a bounded metadata budget but use Kubernetes value syntax. +pub(super) fn validate_labels( + labels: &std::collections::HashMap, +) -> Result<(), Status> { + const MAX_METADATA_LABELS_ENTRIES: usize = 128; + if labels.len() > MAX_METADATA_LABELS_ENTRIES { + return Err(invalid_argument( + "labels", + format!( + "labels exceeds maximum entries ({} > {MAX_METADATA_LABELS_ENTRIES})", + labels.len() + ), + )); + } + for (key, value) in labels { + validate_label_key(key)?; + validate_label_value(value)?; + } + Ok(()) +} + /// Validate object annotations. /// /// Annotation keys use the same qualified-key shape as labels. Annotation diff --git a/crates/openshell-server/src/lib.rs b/crates/openshell-server/src/lib.rs index 0d9c1d85a1..12ca9223ea 100644 --- a/crates/openshell-server/src/lib.rs +++ b/crates/openshell-server/src/lib.rs @@ -1389,7 +1389,7 @@ async fn terminate_signal() { pub use compute::{ AcquiredRemoteDriverEndpoint, DriverWatchStream, ManagedDriverProcess, SharedComputeDriver, - SharedComputeDriverImageUpdates, + SharedComputeDriverConfigurationUpdates, }; /// Driver instance returned by a compiled compute-driver factory. @@ -1469,16 +1469,16 @@ pub trait ComputeDriverFactory: Send + Sync { /// Build with a separately registered, optional in-process image updater. /// /// Existing factories only implement `build`; their baseline driver object - /// remains sufficient and this hook defaults to no image-update support. + /// remains sufficient and this hook defaults to no configuration-update support. /// Supporting factories return the same driver instance in both slots and - /// advertise the negotiated image-update capability. Remote drivers expose + /// advertise the negotiated configuration-update capability. Remote drivers expose /// their extension over the existing endpoint instead of using this hook. - async fn build_with_image_updates( + async fn build_with_configuration_updates( &self, context: ComputeDriverBuildContext<'_>, ) -> Result<( ComputeDriverInstance, - Option, + Option, )> { self.build(context).await.map(|instance| (instance, None)) } @@ -1934,7 +1934,7 @@ async fn build_compute_runtime( }; let (instance, image_updates) = registration .factory - .build_with_image_updates(build_context) + .build_with_configuration_updates(build_context) .await?; let supervisor_host = shared_supervision .into_inner() diff --git a/crates/openshell-server/src/persistence/image_activation.rs b/crates/openshell-server/src/persistence/image_activation.rs index 22acb430a6..e7024319b0 100644 --- a/crates/openshell-server/src/persistence/image_activation.rs +++ b/crates/openshell-server/src/persistence/image_activation.rs @@ -10,16 +10,10 @@ //! old-understood pending-operation interlock, not these observations, protects //! an accepted image mutation from a subsequent legacy Start. -use super::{ObjectRecord, PersistenceError, PersistenceResult, Store, map_db_error}; -use crate::gateway_members::MEMBER_TTL; +use super::{ObjectRecord, PersistenceError, PersistenceResult, Store}; +use crate::gateway_members::{MEMBER_TTL, SANDBOX_UPDATE_PROTOCOL}; use openshell_core::time::now_ms; -/// Compatibility marker advertised by both gateway `PostgreSQL` connection pools. -/// -/// This marker describes a protocol, not an exact build version. It is neither -/// authentication nor a security boundary: database clients can set it too. -pub(super) const IMAGE_UPDATE_APPLICATION_NAME: &str = "openshell-image-update-v2"; - const MEMBER_OBJECT_TYPE: &str = "gateway_member"; const MEMBER_LIMIT: u32 = 1024; @@ -29,37 +23,15 @@ impl Store { /// The caller separately enforces the default-off operator activation flag. /// `SQLite` returns success under its supported single-gateway deployment /// contract; this does not enforce process exclusion for a shared file. - /// `PostgreSQL` checks every client backend in this database, not merely - /// registered peers, and then strictly checks all fresh membership records. - /// Administrative clients without the marker also prevent activation. Any - /// database read failure propagates rather than granting compatibility. + /// `PostgreSQL` checks fresh gateway membership records. Administrative, + /// monitoring, and backup sessions are not gateway participants. Operator + /// activation attests that unregistered legacy processes have been retired. + /// Recovery of accepted operations does not use this admission check. pub async fn ensure_image_update_deployment_compatible(&self) -> PersistenceResult<()> { - let Self::Postgres(store) = self else { + let Self::Postgres(_) = self else { return Ok(()); }; - let incompatible_backend: bool = sqlx::query_scalar( - r" -SELECT EXISTS ( - SELECT 1 FROM pg_stat_activity - WHERE datname = current_database() - AND (backend_type = 'client backend' OR backend_type IS NULL) - AND application_name IS DISTINCT FROM $1 -) -", - ) - .bind(IMAGE_UPDATE_APPLICATION_NAME) - .fetch_one(&store.pool) - .await - .map_err(|error| map_db_error(&error))?; - if incompatible_backend { - return Err(PersistenceError::Config( - "sandbox image updates require a uniformly compatible gateway deployment; \ - a PostgreSQL client backend has an unknown or legacy image-update protocol" - .into(), - )); - } - // One extra row distinguishes a complete bounded snapshot from a // truncated listing. Never silently treat uninspected rows as compatible. let records = self @@ -93,13 +65,14 @@ fn ensure_live_members_compatible(records: &[ObjectRecord], now: i64) -> Persist })?; let replica_id = member.get("replica_id").and_then(serde_json::Value::as_str); let protocol = member - .get("image_update_protocol") + .get("sandbox_update_protocol") .and_then(serde_json::Value::as_u64); - if replica_id.is_none_or(|id| id.trim().is_empty()) || protocol != Some(2) { - return Err(PersistenceError::Config( - "sandbox image updates require every live gateway membership record to advertise image-update protocol 2 and a nonempty replica id" - .into(), - )); + if replica_id.is_none_or(|id| id.trim().is_empty()) + || protocol != Some(u64::from(SANDBOX_UPDATE_PROTOCOL)) + { + return Err(PersistenceError::Config(format!( + "sandbox updates require every live gateway membership record to advertise sandbox-update protocol {SANDBOX_UPDATE_PROTOCOL} and a nonempty replica id" + ))); } } Ok(()) @@ -133,83 +106,40 @@ mod tests { } #[tokio::test] - #[ignore = "requires a disposable PostgreSQL database and CREATEDB privileges in OPENSHELL_TEST_POSTGRES_URL; run mise run test:rust:postgres"] - async fn postgres_image_activation_checks_client_backends_and_live_members() { - use super::super::test_postgres::TEST_POSTGRES_URL_ENV; - use super::super::{MutationLockSet, WriteCondition}; - use sqlx::postgres::{PgConnectOptions, PgPoolOptions}; - use std::time::Duration; - - // This check intentionally includes every backend in a database. A - // disposable schema would share unmarked test-control/other-test - // sessions and make its positive assertions dependent on test order. - // Keep the unmarked control pool in the original database instead. - let base = std::env::var(TEST_POSTGRES_URL_ENV) - .expect("OPENSHELL_TEST_POSTGRES_URL must name a disposable PostgreSQL database"); - let admin = PgPoolOptions::new() - .max_connections(1) - .connect(&base) + #[ignore = "requires OPENSHELL_TEST_POSTGRES_URL; run mise run test:rust:postgres"] + async fn postgres_activation_ignores_administrative_sessions_and_preserves_application_name() { + use super::super::test_postgres::TestSchema; + let schema = TestSchema::create("sandbox_update_activation").await; + let mut url = url::Url::parse(schema.url()).unwrap(); + url.query_pairs_mut() + .append_pair("application_name", "operator-custom-name"); + let store = Store::connect(url.as_str()).await.unwrap(); + let Store::Postgres(pg) = &store else { + unreachable!() + }; + let name: String = sqlx::query_scalar("SHOW application_name") + .fetch_one(&pg.pool) .await - .expect("connect to the test-control database"); - let database = format!("image_activation_{}", uuid::Uuid::new_v4().simple()); - sqlx::query(sqlx::AssertSqlSafe(format!("CREATE DATABASE {database}"))) - .execute(&admin) + .unwrap(); + assert_eq!(name, "operator-custom-name"); + // TestSchema's unmarked admin connection remains open in this database. + store + .ensure_image_update_deployment_compatible() .await - .expect("create a dedicated activation-test database (requires CREATEDB)"); - let mut url = url::Url::parse(&base).expect("parse the test PostgreSQL URL"); - url.set_path(&format!("/{database}")); - let first = Store::connect(url.as_str()).await.unwrap(); - let second = Store::connect(url.as_str()).await.unwrap(); - - // Exercise both data pools and a lazily opened mutation-lock pool. - let guard = second - .acquire_distributed_mutation_guard( - &MutationLockSet::sandbox_lifecycle("activation-test-sandbox"), - tokio::time::Instant::now() + Duration::from_secs(10), - ) + .unwrap(); + let index = crate::gateway_members::GatewayMemberIndex::new( + std::sync::Arc::new(store.clone()), + MEMBER_TTL, + ); + index + .register("compatible", "https://gateway:8443") .await .unwrap(); - first + store .ensure_image_update_deployment_compatible() .await - .expect("compatible data and lock pools must pass despite the other database's control pool"); - drop(guard); - - // No membership record is needed to detect an old or administrative - // client. Do not weaken the production filter to exempt this session. - let legacy_options = url - .as_str() - .parse::() - .unwrap() - .application_name("legacy-image-activation-test"); - let legacy = PgPoolOptions::new() - .max_connections(1) - .connect_with(legacy_options) - .await .unwrap(); - assert!(matches!( - first.ensure_image_update_deployment_compatible().await, - Err(PersistenceError::Config(_)) - )); - legacy.close().await; - - // SQLx closing its socket can precede the server removing the backend. - // Bound this wait instead of depending on a fixed scheduling delay. - tokio::time::timeout(Duration::from_secs(5), async { - loop { - match first.ensure_image_update_deployment_compatible().await { - Ok(()) => break, - Err(PersistenceError::Config(_)) => { - tokio::time::sleep(Duration::from_millis(20)).await; - } - Err(error) => panic!("compatibility read failed: {error}"), - } - } - }) - .await - .expect("closed legacy backend must disappear from pg_stat_activity"); - - let member = first + store .put_if( MEMBER_OBJECT_TYPE, "gateway-member:legacy", @@ -217,51 +147,23 @@ mod tests { "", br#"{"replica_id":"legacy"}"#, None, - WriteCondition::MustCreate, + super::super::WriteCondition::MustCreate, ) .await .unwrap(); assert!(matches!( - first.ensure_image_update_deployment_compatible().await, + store.ensure_image_update_deployment_compatible().await, Err(PersistenceError::Config(_)) )); - first - .put_if( - MEMBER_OBJECT_TYPE, - "gateway-member:legacy", - "legacy", - "", - br#"{"replica_id":"legacy","image_update_protocol":2}"#, - None, - WriteCondition::MatchResourceVersion(member.resource_version), - ) - .await - .unwrap(); - first - .ensure_image_update_deployment_compatible() - .await - .unwrap(); - - first.close().await; - assert!(matches!( - first.ensure_image_update_deployment_compatible().await, - Err(PersistenceError::Database(_)) - )); - second.close().await; - sqlx::query(sqlx::AssertSqlSafe(format!( - "DROP DATABASE {database} WITH (FORCE)" - ))) - .execute(&admin) - .await - .expect("drop the isolated activation-test database"); - admin.close().await; + store.close().await; + schema.drop_schema().await; } #[test] fn compatible_live_members_and_empty_snapshot_pass() { assert!(ensure_live_members_compatible(&[], 100).is_ok()); let member = record( - br#"{"replica_id":"gw-0","peer_endpoint":"https://gw-0:8443","image_update_protocol":2}"#, + br#"{"replica_id":"gw-0","peer_endpoint":"https://gw-0:8443","sandbox_update_protocol":1}"#, 100, ); assert!(ensure_live_members_compatible(&[member], 100).is_ok()); @@ -275,14 +177,14 @@ mod tests { br#"["gw-0",1]"#, br"null", br#"{"replica_id":"gw-0"}"#, - br#"{"replica_id":"gw-0","image_update_protocol":0}"#, - br#"{"replica_id":"gw-0","image_update_protocol":1}"#, - br#"{"replica_id":"gw-0","image_update_protocol":"1"}"#, - br#"{"replica_id":"gw-0","image_update_protocol":true}"#, - br#"{"replica_id":"gw-0","image_update_protocol":2.0}"#, - br#"{"image_update_protocol":1}"#, - br#"{"replica_id":"","image_update_protocol":1}"#, - br#"{"replica_id":" ","image_update_protocol":1}"#, + br#"{"replica_id":"gw-0","sandbox_update_protocol":0}"#, + br#"{"replica_id":"gw-0","sandbox_update_protocol":2}"#, + br#"{"replica_id":"gw-0","sandbox_update_protocol":"1"}"#, + br#"{"replica_id":"gw-0","sandbox_update_protocol":true}"#, + br#"{"replica_id":"gw-0","sandbox_update_protocol":1.0}"#, + br#"{"sandbox_update_protocol":1}"#, + br#"{"replica_id":"","sandbox_update_protocol":1}"#, + br#"{"replica_id":" ","sandbox_update_protocol":1}"#, ]; for payload in invalid { assert!(ensure_live_members_compatible(&[record(payload, 100)], 100).is_err()); @@ -301,7 +203,7 @@ mod tests { #[test] fn any_incompatible_live_member_rejects_the_snapshot() { - let compatible = record(br#"{"replica_id":"gw-0","image_update_protocol":2}"#, 100); + let compatible = record(br#"{"replica_id":"gw-0","sandbox_update_protocol":1}"#, 100); let legacy = record(br#"{"replica_id":"gw-1"}"#, 100); assert!(ensure_live_members_compatible(&[compatible, legacy], 100).is_err()); } diff --git a/crates/openshell-server/src/persistence/postgres.rs b/crates/openshell-server/src/persistence/postgres.rs index 9fdb08d42e..ca070bedd6 100644 --- a/crates/openshell-server/src/persistence/postgres.rs +++ b/crates/openshell-server/src/persistence/postgres.rs @@ -20,7 +20,7 @@ use openshell_core::SetResourceVersion; use openshell_core::proto::Sandbox; use prost::Message; use sqlx::pool::PoolConnection; -use sqlx::postgres::{PgConnection, PgPoolOptions}; +use sqlx::postgres::PgPoolOptions; use sqlx::{Connection, PgPool, Postgres, QueryBuilder, Row}; use std::sync::Arc; use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; @@ -28,15 +28,6 @@ use std::time::Duration; static POSTGRES_MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate!("./migrations/postgres"); -/// A protocol capability, not an exact build version or an authorization -/// credential. Identify every pool connection, including after reconnect. -async fn identify_image_update_writer(connection: &mut PgConnection) -> Result<(), sqlx::Error> { - sqlx::query("SELECT set_config('application_name', 'openshell-image-update-v2', false)") - .execute(connection) - .await?; - Ok(()) -} - #[cfg(test)] pub(super) fn embedded_migration_sql(version: i64) -> Option<&'static str> { POSTGRES_MIGRATOR @@ -313,7 +304,6 @@ impl PostgresStore { ); let pool = PgPoolOptions::new() .max_connections(max_connections) - .after_connect(|connection, _| Box::pin(identify_image_update_writer(connection))) .connect(url) .await .map_err(|e| map_db_error(&e))?; @@ -330,7 +320,6 @@ impl PostgresStore { .bind(MUTATION_LOCK_TIMEOUT_SETTING) .execute(&mut *connection) .await?; - identify_image_update_writer(connection).await?; Ok(()) }) }) diff --git a/crates/openshell-server/src/persistence/sandbox_image.rs b/crates/openshell-server/src/persistence/sandbox_image.rs index 11ed0294f5..9e3ef32fb1 100644 --- a/crates/openshell-server/src/persistence/sandbox_image.rs +++ b/crates/openshell-server/src/persistence/sandbox_image.rs @@ -156,6 +156,7 @@ fn project_begin( revision: 0, pending: None, previous_provisioning: None, + completed: None, }); if state.revision != expected_revision || state.pending.is_some() { return Err(conflict(Some(current_version))); @@ -194,6 +195,7 @@ fn project_begin( ); state.revision = next_revision; state.pending = Some(intent.clone()); + state.completed = None; state.previous_provisioning = previous_provisioning; let status = sandbox .status @@ -222,9 +224,17 @@ fn project_complete( intent: &StoredSandboxImageUpdate, ) -> PersistenceResult<(Sandbox, StoredSandboxImageState)> { let current_version = resource_version(&sandbox); - require_stopped(&sandbox)?; validate_intent(intent)?; let mut state = state.ok_or_else(|| conflict(Some(current_version)))?; + // The exact receipt proves completion even if a subsequent Start changed + // the phase. A newer update clears this receipt, preventing ABA matches. + if state.pending.is_none() + && state.revision == intent.revision + && state.completed.as_ref() == Some(intent) + { + return Ok((sandbox, state)); + } + require_stopped(&sandbox)?; if state.revision != intent.revision || state.pending.as_ref() != Some(intent) { return Err(conflict(Some(current_version))); } @@ -287,6 +297,7 @@ fn project_complete( } state.previous_provisioning = None; state.pending = None; + state.completed = Some(intent.clone()); // Completing an intent invalidates any Start CAS based on pending state. bump_resource_version(&mut sandbox)?; Ok((sandbox, state)) @@ -370,6 +381,10 @@ impl Store { let state = tx.lock_state(sandbox_id).await?; let previous_version = resource_version(&sandbox); let (sandbox, state) = project_complete(sandbox, state, intent)?; + if resource_version(&sandbox) == previous_version { + tx.commit().await?; + return Ok(sandbox); + } tx.write_projection(sandbox_id, previous_version, &sandbox, &state) .await?; tx.commit().await?; @@ -605,6 +620,27 @@ mod tests { .image } + #[test] + fn exact_completion_is_idempotent_but_another_operation_is_not() { + let (accepted, state) = project_begin(sandbox(), None, 5, 0, &intent()).unwrap(); + let (completed, receipt) = project_complete(accepted, Some(state), &intent()).unwrap(); + assert_eq!( + project_complete(completed.clone(), Some(receipt.clone()), &intent()).unwrap(), + (completed.clone(), receipt.clone()) + ); + let mut other = intent(); + other.operation_id = "another-operation".into(); + assert!(project_complete(completed.clone(), Some(receipt.clone()), &other).is_err()); + let mut started = completed; + started.set_phase(SandboxPhase::Starting as i32); + assert_eq!( + project_complete(started.clone(), Some(receipt), &intent()) + .unwrap() + .0, + started + ); + } + #[test] fn begin_and_complete_project_image_and_baseline_known_interlock() { let original = sandbox(); @@ -1068,12 +1104,14 @@ mod tests { .await, Err(PersistenceError::Conflict { .. }) )); - // Neither a completed operation nor an older generation can be replayed. - assert!( + // Concurrent completion of the same intent returns the current object + // without a second version bump. A newer generation invalidates it. + assert_eq!( store .complete_sandbox_image_update("sandbox-id", &intent()) .await - .is_err() + .unwrap(), + completed ); let next = StoredSandboxImageUpdate { operation_id: "next-operation".into(), @@ -1418,6 +1456,15 @@ updated_at_ms = $3 WHERE object_type = 'sandbox' AND id = $1 AND resource_versio resource_version(&rewritten) + 1 ); assert!(completed.status.as_ref().unwrap().provisioning.is_none()); + // A second replica finishing the same reconciliation gets the current + // object without a conflict or a second resource-version increment. + assert_eq!( + second + .complete_sandbox_image_update("sandbox-id", &winning_intent) + .await + .unwrap(), + completed + ); let retained = second .get_sandbox_image_state("sandbox-id") .await diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index bdeb6cece7..08a2141884 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -180,7 +180,7 @@ mod tests { const PUBLIC_RPC_SCHEMA_SHA256: &str = "be99bb3fcc7894eb85d774f54b642173e70dd37bc8e5fcaf3fdff2454ae689e1"; const DURABLE_SCHEMA_SHA256: &str = - "a20f41356b6cee4b543091c3533b0d4fd409d040fcfb2e17ecf1b6c4a3460794"; + "cb15f8f79a855064a43fe8c6cd908bf07eca6604e2bf8ab7d2de0ef33e97da4e"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = "c0c3ea17f105aaa6d843c466fd4240451c2105dce7675384935d4aaecdac8abf"; // Encoded with the schema that omitted stable_placeholder. Keep these @@ -652,7 +652,7 @@ mod tests { } assert_eq!( compiled_method_count, - 109 + PROVIDER_READINESS_RPC_SIGNATURES.len() + 108 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len() + PEER_CONFIG_RPC_SIGNATURES.len() + isolation_methods.len() diff --git a/crates/openshell-server/src/test_support.rs b/crates/openshell-server/src/test_support.rs index 85615e178a..e12bd617a9 100644 --- a/crates/openshell-server/src/test_support.rs +++ b/crates/openshell-server/src/test_support.rs @@ -15,8 +15,6 @@ use crate::tracing_bus::TracingLogBus; use futures::{Stream, stream}; use openshell_core::Config; #[cfg(unix)] -use openshell_core::proto::compute::v1::compute_driver_image_updates_server::ComputeDriverImageUpdatesServer; -#[cfg(unix)] use openshell_core::proto::compute::v1::compute_driver_server::ComputeDriverServer; use openshell_core::proto::compute::v1::{ CreateSandboxRequest, CreateSandboxResponse, DeleteSandboxRequest, DeleteSandboxResponse, @@ -111,7 +109,7 @@ pub enum FakeComputeDriverCall { request: openshell_core::proto::compute::v1::UpdateSandboxConfigurationRequest, }, UpdateSandboxImage { - request: openshell_core::proto::compute::v1::UpdateSandboxImageRequest, + request: openshell_core::proto::compute::v1::SandboxUpdatePreconditions, }, StopSandbox { sandbox_id: String, @@ -150,6 +148,7 @@ struct FakeComputeDriverState { traceparents: Vec, image_update_error: Option, image_validation_error: Option, + image_update_pause: Option<(Arc, Arc)>, } impl Default for FakeComputeDriver { @@ -195,6 +194,7 @@ impl FakeComputeDriver { traceparents: Vec::new(), image_update_error: None, image_validation_error: None, + image_update_pause: None, })), } } @@ -246,7 +246,9 @@ impl FakeComputeDriver { .as_mut() .unwrap() .supported_capabilities - .push(openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_IMAGE.into()); + .push( + openshell_core::extension_protocol::COMPUTE_UPDATE_SANDBOX_CONFIGURATION.into(), + ); }); self } @@ -281,13 +283,21 @@ impl FakeComputeDriver { tonic::transport::Server::builder() .add_service(ComputeDriverServer::new(driver.clone())) .add_service(openshell_core::proto::compute::v1::compute_driver_configuration_updates_server::ComputeDriverConfigurationUpdatesServer::new(driver.clone())) - .add_service(ComputeDriverImageUpdatesServer::new(driver)) .serve_with_incoming(UnixIncoming { listener }) .await }); Ok(FakeComputeDriverServerHandle { socket_path, task }) } + pub fn pause_image_updates(&self) -> (Arc, Arc) { + let entered = Arc::new(tokio::sync::Notify::new()); + let release = Arc::new(tokio::sync::Semaphore::new(0)); + self.with_state(|state| { + state.image_update_pause = Some((entered.clone(), release.clone())); + }); + (entered, release) + } + pub fn set_image_update_error(&self, code: Option) { self.with_state(|state| state.image_update_error = code); } @@ -355,10 +365,18 @@ impl openshell_core::compute::ComputeDriver for FakeComputeDriver { Response, Status, > { + let pause = self.with_state(|state| state.image_update_pause.clone()); + if let Some((entered, release)) = pause { + entered.notify_one(); + release.acquire().await.unwrap().forget(); + } self.record_traceparent(request.metadata()); self.with_state(|state| { let request = request.into_inner(); - let validate_only = request.image_update.as_ref().unwrap().validate_only; + let validate_only = request.preconditions.as_ref().unwrap().validate_only; + state.calls.push(FakeComputeDriverCall::UpdateSandboxImage { + request: request.preconditions.clone().unwrap(), + }); state .calls .push(FakeComputeDriverCall::UpdateSandboxConfiguration { request }); @@ -373,42 +391,6 @@ impl openshell_core::compute::ComputeDriver for FakeComputeDriver { )) }) } - - async fn update_sandbox_image( - &self, - request: Request, - ) -> Result, Status> - { - self.record_traceparent(request.metadata()); - self.with_state(|state| { - let request = request.into_inner(); - let validate_only = request.validate_only; - state - .calls - .push(FakeComputeDriverCall::UpdateSandboxImage { request }); - if let Some(code) = state.image_validation_error.filter(|_| validate_only) { - return Err(Status::new(code, "injected image validation error")); - } - if let Some(code) = state.image_update_error.filter(|_| !validate_only) { - return Err(Status::new(code, "injected image update error")); - } - Ok(Response::new( - openshell_core::proto::compute::v1::UpdateSandboxImageResponse {}, - )) - }) - } -} - -#[tonic::async_trait] -impl openshell_core::proto::compute::v1::compute_driver_image_updates_server::ComputeDriverImageUpdates - for FakeComputeDriver -{ - async fn update_sandbox_image( - &self, - request: Request, - ) -> Result, Status> { - openshell_core::compute::ComputeDriver::update_sandbox_image(self, request).await - } } #[tonic::async_trait] diff --git a/deploy/helm/openshell-workspace/templates/role.yaml b/deploy/helm/openshell-workspace/templates/role.yaml index 25d7b4f72e..0d80ecccde 100644 --- a/deploy/helm/openshell-workspace/templates/role.yaml +++ b/deploy/helm/openshell-workspace/templates/role.yaml @@ -42,7 +42,20 @@ rules: resources: - pods verbs: + - create + - delete - get + # Updates must rule out every remaining workload Pod, including Pods + # identified only by owner UID or the controller's recorded name. + - list + - patch + - watch + - apiGroups: [""] + resources: ["services"] + verbs: ["create", "get"] + - apiGroups: ["networking.k8s.io"] + resources: ["networkpolicies"] + verbs: ["create", "get"] # Generation-scoped sandbox bootstrap Secrets. - apiGroups: - "" diff --git a/deploy/helm/openshell-workspace/tests/workspace_test.yaml b/deploy/helm/openshell-workspace/tests/workspace_test.yaml index d4d3489f01..d3270cea27 100644 --- a/deploy/helm/openshell-workspace/tests/workspace_test.yaml +++ b/deploy/helm/openshell-workspace/tests/workspace_test.yaml @@ -12,6 +12,28 @@ release: namespace: app-a tests: + - it: grants supervisor lifecycle and complete stopped-update pod inspection + template: templates/role.yaml + asserts: + - contains: + path: rules + content: + apiGroups: [""] + resources: ["pods"] + verbs: ["create", "delete", "get", "list", "patch", "watch"] + - contains: + path: rules + content: + apiGroups: [""] + resources: ["services"] + verbs: ["create", "get"] + - contains: + path: rules + content: + apiGroups: ["networking.k8s.io"] + resources: ["networkpolicies"] + verbs: ["create", "get"] + - it: creates the workspace role in the release namespace template: templates/role.yaml asserts: diff --git a/docs/how-it-works/gateways/configuration.mdx b/docs/how-it-works/gateways/configuration.mdx index ce172ec393..a58f5552da 100644 --- a/docs/how-it-works/gateways/configuration.mdx +++ b/docs/how-it-works/gateways/configuration.mdx @@ -507,8 +507,8 @@ until callers request a fresh URL. `[openshell.gateway] enable_sandbox_updates` defaults to `false`. It gates the separate `openshell.v1.SandboxUpdates/UpdateSandbox` RPC on the existing gateway listener. It gates image, command, environment, label, and annotation -updates for stopped sandboxes. Protocol 2 requires upgrading all -gateways, including gateways that previously supported image-only updates. +updates for stopped sandboxes. Upgrade every gateway before activation. +Disabling the flag stops new updates; accepted updates still recover automatically. The equivalent gateway process flag and environment variable are `--enable-sandbox-updates true` and `OPENSHELL_ENABLE_SANDBOX_UPDATES=true`. @@ -518,7 +518,9 @@ Enable it only after completing the Setting it to `true` attests that every gateway that can write the database is compatible and incompatible gateways cannot return. Keep it false throughout a rolling upgrade, including while outstanding operations from retired gateways -settle. Database and membership checks fail closed but do not prove retirement. +settle. Gateway membership checks fail closed but do not prove retirement. PostgreSQL +administrative and monitoring sessions do not block updates; connection +`application_name` settings are preserved. For a schema-v2 file, set: @@ -1689,7 +1691,7 @@ compute_driver = "kyma" socket_path = "/run/openshell/kyma-compute-driver.sock" ``` -

Preflight package configuration

+## Preflight package configuration {#gateway-config-preflight} Before starting a package-managed gateway, validate the selected file without changing it: diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index 18227567fc..4a6aeb12c0 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -1006,6 +1006,10 @@ command. Starting a fresh instance invalidates SSH sessions issued for the previous runtime generation. Delete an inactive sandbox normally when you no longer need its retained state. +To change the configuration of a retained `Completed` or `Error/MainProcessFailed` +sandbox, run `sandbox stop` first. Stop cleans up compute and moves the sandbox +to `Stopped`, preserving its exit code until the next start. + If an infrastructure failure leaves a sandbox in `Error`, fix the reported cause, then run `sandbox stop` followed by `sandbox start`. Wait for stop to succeed before starting. This retains the sandbox and its persistent workspace on backends that support restarting stopped sandboxes; it cannot recover deleted resources or storage. For a provisioning timeout, wait for cleanup to finish, then run `sandbox start` directly. @@ -1016,7 +1020,7 @@ Use `openshell.v1.SandboxUpdates/UpdateSandbox` to change a stopped sandbox's workload image, command, environment overrides, labels, and annotations together. This separate service uses the same gateway listener and authentication as `OpenShell`; it requires `sandbox:write` and workspace user access. This operation initially supports the Kubernetes compute driver -only; other drivers return `UNIMPLEMENTED` after activation. There is no +for workload changes; metadata-only updates work with every compute driver. There is no `sandbox update` CLI command or curated SDK update method. Image updates default to disabled. Ask the operator to complete the @@ -1033,16 +1037,15 @@ login shell resolved from the workload image. A supplied environment map replace sandbox-level overrides; clearing it restores any template-provided defaults. Labels and annotations replace user metadata on the gateway resource, preserve system-owned keys, and do not set Kubernetes pod metadata. Attempts to supply -system-owned keys are rejected. At least one update field is required. +system-owned keys are rejected. Metadata-only changes commit directly without +contacting the compute driver. The retention annotation is preserved when omitted. Annotation changes accepted through `UpdateConfig` after the sandbox update is accepted remain in place when the update completes, including after a retry. Without a pending update, a request whose target values already match is a no-op. Use a different image tag or an immutable digest to select new image content. -Configuration updates require the driver's -`openshell.compute.update-sandbox-configuration` capability; image-only clients -can continue using `openshell.compute.update-sandbox-image`. Upgrade every gateway -before enabling updates: older gateways can ignore new request fields. +Workload changes require `openshell.compute.update-sandbox-configuration`. +Upgrade every gateway before enabling updates. Follow this sequence through the CLI and a generated/raw RPC client. @@ -1086,27 +1089,29 @@ If the new image fails to start and provisioning times out, wait until `provisioning.driver_operation_pending` is false. Run `sandbox stop` to move the reclaimed sandbox from `Error` to `Stopped`, then repeat the update sequence with a working image. Stop retains the timeout record and storage; it does not stop -compute again. Cleanup that is still pending cannot be bypassed. +compute again. This Stop behavior also applies when updates are disabled. +Cleanup that is still pending cannot be bypassed. An `ABORTED` version conflict requires another read before you construct a new conditional request. An update failure or disconnected response can leave a pending operation, even when `sandbox.spec.template.image` already names the -target image. Start, stop, provisioning retry, and delete reject the pending -operation. -The public `SandboxStatus` shape is unchanged; image intent and revision remain -private. Use the operation-pending error to guide recovery, not a status image -field. Read the current version and retry `UpdateSandbox` with the same selected fields and target values -you originally requested. Do not select another configuration or delete the sandbox to -bypass reconciliation. Only a successful retry clears the pending operation. +target image. Start, stop, and provisioning retry remain blocked until reconciliation +succeeds. The gateway retries accepted updates at startup and periodically, even +if new updates are disabled. If the driver is unavailable or no longer supports +updates, restore a compatible driver. Explicit deletion can reclaim a sandbox +whose update cannot complete; deletion also removes its stored workspace. + +To resume immediately, read the current resource version and call `UpdateSandbox` +with the same scope and name, that version, and no selected fields. The gateway +uses the stored operation and target values. With no pending update, this returns +`FAILED_PRECONDITION`. The operation ID is visible in +`status.provisioning.driver_operation_id` while pending; the full intent stays private. The optional `request_id` uses [durable request admission](/sdk/api-errors#durable-request-admission). -A retry with the same ID must keep the original payload, including its expected -version. An unresolved admission returns `REQUEST_OUTCOME_UNCERTAIN` rather than -executing again. Reconcile against the sandbox state and your original requested -configuration, then submit a new conditional request for the same target with a fresh version -and a new ID, or no ID. -Do not change the expected version under the original ID or blindly switch IDs -after a timeout. +Reusing an unresolved ID returns `REQUEST_OUTCOME_UNCERTAIN`. For explicit resume, +use a new ID or omit it, and use the fresh resource version. Do not change the +original payload under its original ID. A confirmed successful request still +replays without applying another update. ## Delete Sandboxes diff --git a/docs/kubernetes/high-availability.mdx b/docs/kubernetes/high-availability.mdx index 2d4eadf70b..73f40cc6f4 100644 --- a/docs/kubernetes/high-availability.mdx +++ b/docs/kubernetes/high-availability.mdx @@ -519,24 +519,18 @@ Use this sequence before activating the 2. Prevent incompatible gateways from returning. Pin compatible images and retire old rollback targets, Jobs, and other launch configurations that could reconnect to the database. -3. Check all PostgreSQL client backends in the same database. The new binary - sets `application_name` to `openshell-image-update-v2` on every data-pool and - lock-pool connection. Any unmarked client backend, including an - administrative session, blocks image updates. Close those sessions or use a - dedicated database. Do not relabel an old process to bypass this check. -4. Confirm live gateway membership records advertise image-update protocol 2. +3. Confirm live gateway membership records advertise sandbox-update protocol 1. Missing or incompatible capabilities, malformed records, and truncated membership reads reject updates. These observations are not durable proof of fleet compatibility. Expiry or absence of a membership record does not prove that its process and driver work have stopped. -5. Activate the flag only after completing retirement and preventing old +4. Activate the flag only after completing retirement and preventing old gateways from returning. See the exact [TOML, environment, process flag, and Helm forms](/how-it-works/gateways/configuration#sandbox-updates). A pending image update atomically sets the existing `provisioning.driver_operation_pending` and `provisioning.driver_operation_id` -fields alongside private image intent. Baseline start, stop, delete, and -provisioning-retry paths honor this per-sandbox barrier, including after a +fields alongside private image intent. Start, stop, and provisioning-retry paths honor this per-sandbox barrier, including after a legacy public record round-trip. Successful reconciliation preserves current provisioning diagnostics and clocks, clears the pending flag, and retains the new operation ID to fence delayed callbacks. Previously absent provisioning diff --git a/docs/kubernetes/setup.mdx b/docs/kubernetes/setup.mdx index 565a8f101d..ede500e931 100644 --- a/docs/kubernetes/setup.mdx +++ b/docs/kubernetes/setup.mdx @@ -409,13 +409,18 @@ managed mode, the configured image-pull Secrets. The gateway stages their contents into each sandbox runtime generation's Secrets in the workspace namespace. -The namespaced Role covers sandbox lifecycle and identity: +The namespaced Role covers sandbox lifecycle, supervisor resources, and identity. +Both the gateway chart and separate workspace chart grant these permissions. +Stopped-sandbox updates need Pod listing to detect remaining workload or supervisor Pods: | API Group | Resource | Verbs | |---|---|---| | `agents.x-k8s.io` | `sandboxes`, `sandboxes/status` | create, delete, get, list, patch, update, watch | | `""` | `events` | get, list, watch | -| `""` | `pods` | get | +| `""` | `pods` | create, delete, get, list, patch, watch | +| `""` | `services` | create, get | +| `""` | `secrets` | create, delete | +| `networking.k8s.io` | `networkpolicies` | create, get | The ClusterRole grants node inspection and token validation: diff --git a/docs/sdk/api-errors.mdx b/docs/sdk/api-errors.mdx index b782afc4ba..5d45369e68 100644 --- a/docs/sdk/api-errors.mdx +++ b/docs/sdk/api-errors.mdx @@ -201,28 +201,26 @@ before relying on IDs; older protobuf servers can silently ignore unknown fields `SandboxUpdates.UpdateSandbox` conditionally updates image, command, environment overrides, labels, and annotations for stopped Kubernetes sandboxes. It defaults to disabled and returns `FAILED_PRECONDITION` until the operator [activates a compatible deployment](/kubernetes/high-availability#activate-sandbox-updates). -After activation, other compute drivers return `UNIMPLEMENTED`. Supply a named +After activation, unsupported workload changes return `UNIMPLEMENTED`; metadata-only +updates do not require driver support. For a new update, supply a named `workspace_scope`, sandbox `name`, at least one selected update field, and a required nonzero `expected_resource_version` read from `sandbox.metadata.resource_version`. A stale version returns `ABORTED`; read fresh state before constructing another conditional request. The operation does not start compute. A failed or interrupted update can leave a pending operation. The desired spec -image alone does not prove driver reconciliation completed. Start, stop, -provisioning retry, and delete return `FAILED_PRECONDITION` while that operation remains. -Image intent and revision are private; the public `SandboxStatus` shape does not -change. On an operation-pending error, read a fresh resource version and retry -the same selected fields and target values originally requested. A different configuration cannot replace a -pending update. +alone does not prove driver reconciliation completed. Start, stop, and provisioning +retry return `FAILED_PRECONDITION` until completion. Recovery runs automatically, +including when new updates are disabled. To resume immediately, read the current +resource version and send `UpdateSandbox` with no selected fields. The gateway +loads the stored intent; no pending intent returns `FAILED_PRECONDITION`. +Explicit delete can reclaim a sandbox whose update cannot complete. If the original request supplied `request_id`, an error leaves its admission -unresolved. Reusing that ID with the original payload returns -`REQUEST_OUTCOME_UNCERTAIN`; changing its expected version returns -`REQUEST_ID_PAYLOAD_MISMATCH`. Reconcile against the original requested configuration, -then make a new conditional request for the same target with the fresh version and a new -ID, or without an ID. This is explicit recovery, not permission to blindly -repeat uncertain mutations. A replay of a confirmed success returns the -sandbox's current state without applying the image again. +unresolved. Reusing that ID returns `REQUEST_OUTCOME_UNCERTAIN`; changing its +payload returns `REQUEST_ID_PAYLOAD_MISMATCH`. For explicit resume, use the fresh +version with a new ID or no ID. A confirmed success replays the current sandbox +without applying another update. See [Update the Image of a Stopped Sandbox](/how-it-works/sandboxes/overview#update-the-image-of-a-stopped-sandbox) for the stop, update, and start workflow and storage guarantees. diff --git a/e2e/rust/Cargo.lock b/e2e/rust/Cargo.lock index a6e8d591ba..9f585578ce 100644 --- a/e2e/rust/Cargo.lock +++ b/e2e/rust/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e567177890eb1617b1f774005b66b26b2377afd138a2ca37aae7d8f0c81429d4" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -73,7 +64,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.19", + "thiserror", "time", ] @@ -86,7 +77,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.119", - "synstructure 0.13.2", + "synstructure", ] [[package]] @@ -244,30 +235,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "backtrace" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f4220217f3288537b83684130f42fad43320b1c3b805f1910d683d52ded24f" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] - -[[package]] -name = "backtrace-ext" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" -dependencies = [ - "backtrace", -] - [[package]] name = "base64" version = "0.22.1" @@ -355,7 +322,7 @@ dependencies = [ "serde_derive", "serde_json", "serde_urlencoded", - "thiserror 2.0.19", + "thiserror", "tokio", "tokio-util", "tower-service", @@ -799,12 +766,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" -[[package]] -name = "fixedbitset" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" - [[package]] name = "flate2" version = "1.1.10" @@ -997,10 +958,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] @@ -1029,18 +988,6 @@ dependencies = [ "rand_core 0.10.1", ] -[[package]] -name = "gimli" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1033caf0b349c518623b5396bfb2cf0bddf44f0306d543a250e5743297aafd10" - -[[package]] -name = "glob" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" - [[package]] name = "gloo-timers" version = "0.3.0" @@ -1333,16 +1280,13 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64 0.22.1", "bytes", "futures-channel", "futures-util", "http", "http-body", "hyper", - "ipnet", "libc", - "percent-encoding", "pin-project-lite", "socket2", "tokio", @@ -1391,9 +1335,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.4.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe090a42a0d3140fed8c63263ed1fecc02422cb2f4bfe55cd8de2de1b8e105dd" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", @@ -1405,43 +1349,22 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.4.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", - "serde", "tinystr", "writeable", "zerovec", ] -[[package]] -name = "icu_locale_fallback" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406e9ae5b95d8aa37db6293405931b766a6172d1848daee22d70eb44aa78a43c" -dependencies = [ - "icu_locale_core", - "icu_locale_fallback_data", - "icu_provider", - "potential_utf", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locale_fallback_data" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3632ebbd0c5c3637ba1a40bdf8288f2cb9d2268e73441a69d5fc73d7cfbaa87c" - [[package]] name = "icu_normalizer" -version = "2.4.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "404a3b8c486f205c87fe7f23ab6894d84a4ad76d6e4671ae1981ba7def87c599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1453,17 +1376,16 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.4.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20f0088bfb7441f7a37fa0c9e20cb1e9cba1cac6b9ce8cd2a6dc44294f8e8cbc" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.4.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ea83d991c56158f7cf898bf86436c1dfe7c07ee82fe88951f2695c9f37a379f" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -1474,20 +1396,18 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.4.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98f29af82d02b163fe50161388350e743bb3107cc8e8c2f7314cb505faddfcf" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.4.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", - "serde", - "stable_deref_trait", "writeable", "yoke", "zerofrom", @@ -1495,29 +1415,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_segmenter" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b195dc605f81aa181bec9b3bd14e26cc71b903e4644f6af578ca9772c7a710" -dependencies = [ - "icu_collections", - "icu_locale_fallback", - "icu_provider", - "icu_segmenter_data", - "potential_utf", - "smallvec", - "utf8_iter", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_segmenter_data" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "913a7d294ad056474749152107309fdee3ec17d2482d1ab70fdc61a81c64b9a3" - [[package]] name = "ident_case" version = "1.0.1" @@ -1557,18 +1454,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "ipnet" -version = "2.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" - -[[package]] -name = "is_ci" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" - [[package]] name = "itertools" version = "0.14.0" @@ -1614,7 +1499,7 @@ dependencies = [ "jsonptr", "serde", "serde_json", - "thiserror 2.0.19", + "thiserror", ] [[package]] @@ -1627,7 +1512,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror 2.0.19", + "thiserror", ] [[package]] @@ -1766,7 +1651,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "thiserror 2.0.19", + "thiserror", "tokio", "tokio-util", "tower", @@ -1789,7 +1674,7 @@ dependencies = [ "serde", "serde-value", "serde_json", - "thiserror 2.0.19", + "thiserror", ] [[package]] @@ -1828,7 +1713,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror 2.0.19", + "thiserror", "tokio", "tokio-util", "tracing", @@ -1937,36 +1822,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a86d3146ed3995b5913c414f6664344b9617457320782e64f0bb44afd49d74" -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "backtrace", - "backtrace-ext", - "cfg-if", - "miette-derive", - "owo-colors", - "supports-color", - "supports-hyperlinks", - "supports-unicode", - "terminal_size", - "textwrap", - "unicode-width 0.1.14", -] - -[[package]] -name = "miette-derive" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "mime" version = "0.3.17" @@ -2000,12 +1855,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "multimap" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" - [[package]] name = "nix" version = "0.29.0" @@ -2136,35 +1985,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "oauth2" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" -dependencies = [ - "base64 0.22.1", - "chrono", - "getrandom 0.2.17", - "http", - "rand 0.8.8", - "reqwest", - "serde", - "serde_json", - "serde_path_to_error", - "sha2 0.10.9", - "thiserror 1.0.69", - "url", -] - -[[package]] -name = "object" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd229a0361b9d0d4396176e02d65897f487eebeab7caa6d443855ee152ca0b9c" -dependencies = [ - "memchr", -] - [[package]] name = "oid-registry" version = "0.8.1" @@ -2180,59 +2000,6 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" -[[package]] -name = "openshell-bootstrap" -version = "0.0.0" -dependencies = [ - "bytes", - "miette", - "openshell-core", - "openshell-crypto", - "rcgen", - "serde", - "serde_json", - "tempfile", - "tokio", - "tracing", -] - -[[package]] -name = "openshell-core" -version = "0.0.0" -dependencies = [ - "async-trait", - "base64 0.22.1", - "chrono", - "glob", - "ipnet", - "libc", - "miette", - "nix", - "openshell-crypto", - "openshell-extension-core", - "openshell-policy-schema", - "prost", - "prost-types", - "protoc-bin-vendored", - "reqwest", - "rustix", - "rustls", - "rustls-pemfile", - "serde", - "serde_json", - "sha2 0.10.9", - "thiserror 2.0.19", - "tokio", - "tokio-stream", - "tonic", - "tonic-prost", - "tonic-prost-build", - "tonic-types", - "tracing", - "url", - "uuid", -] - [[package]] name = "openshell-crypto" version = "0.0.0" @@ -2245,7 +2012,7 @@ dependencies = [ "rustls", "serde", "sqlx", - "thiserror 2.0.19", + "thiserror", "tonic", "x509-parser", ] @@ -2265,11 +2032,9 @@ dependencies = [ "jsonwebtoken", "nix", "noyalib", - "openshell-bootstrap", "openshell-crypto", "openshell-ocsf-validate", "openshell-otel-test-support", - "openshell-sdk", "opentelemetry-proto", "prost", "rand 0.9.5", @@ -2289,18 +2054,6 @@ dependencies = [ "url", ] -[[package]] -name = "openshell-extension-core" -version = "0.0.0" -dependencies = [ - "hyper-util", - "serde", - "thiserror 2.0.19", - "tokio", - "tonic", - "tower", -] - [[package]] name = "openshell-ocsf" version = "0.0.0" @@ -2335,7 +2088,7 @@ dependencies = [ "opentelemetry-otlp", "opentelemetry_sdk", "serde_json", - "thiserror 2.0.19", + "thiserror", "tokio", "tonic", "tower-http", @@ -2358,43 +2111,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "openshell-policy-schema" -version = "0.0.0" -dependencies = [ - "miette", - "noyalib", - "serde", - "serde_json", - "serde_path_to_error", - "thiserror 2.0.19", -] - -[[package]] -name = "openshell-sdk" -version = "0.0.0" -dependencies = [ - "async-stream", - "async-trait", - "futures", - "hyper", - "hyper-util", - "miette", - "oauth2", - "openshell-core", - "openshell-crypto", - "reqwest", - "rustls", - "serde", - "thiserror 2.0.19", - "tokio", - "tokio-rustls", - "tokio-tungstenite", - "tonic", - "tower", - "tracing", -] - [[package]] name = "openssl-probe" version = "0.2.1" @@ -2411,7 +2127,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.19", + "thiserror", "tracing", ] @@ -2426,7 +2142,7 @@ dependencies = [ "opentelemetry-proto", "opentelemetry_sdk", "prost", - "thiserror 2.0.19", + "thiserror", "tokio", "tonic", "tonic-types", @@ -2458,7 +2174,7 @@ dependencies = [ "percent-encoding", "portable-atomic", "rand 0.9.5", - "thiserror 2.0.19", + "thiserror", "tokio", "tokio-stream", ] @@ -2478,12 +2194,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" -[[package]] -name = "owo-colors" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c45bb4a6ae1280ec0803b1ef9d3455eb50f01efbbe1447ab020f1d54fba9d8" - [[package]] name = "parking" version = "2.2.1" @@ -2581,17 +2291,6 @@ dependencies = [ "pest", ] -[[package]] -name = "petgraph" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" -dependencies = [ - "fixedbitset", - "hashbrown 0.15.5", - "indexmap", -] - [[package]] name = "pin-project" version = "1.1.13" @@ -2636,8 +2335,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ - "serde_core", - "writeable", "zerovec", ] @@ -2656,16 +2353,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.119", -] - [[package]] name = "proc-macro2" version = "1.0.107" @@ -2685,27 +2372,6 @@ dependencies = [ "prost-derive", ] -[[package]] -name = "prost-build" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" -dependencies = [ - "heck", - "itertools", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "pulldown-cmark", - "pulldown-cmark-to-cmark", - "regex", - "syn 2.0.119", - "tempfile", -] - [[package]] name = "prost-derive" version = "0.14.4" @@ -2728,90 +2394,6 @@ dependencies = [ "prost", ] -[[package]] -name = "protoc-bin-vendored" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8760a25b6ff9c620324822737e468478fa092234190d2e449760344354896ed9" -dependencies = [ - "protoc-bin-vendored-linux-aarch_64", - "protoc-bin-vendored-linux-ppcle_64", - "protoc-bin-vendored-linux-s390_64", - "protoc-bin-vendored-linux-x86_32", - "protoc-bin-vendored-linux-x86_64", - "protoc-bin-vendored-macos-aarch_64", - "protoc-bin-vendored-macos-x86_64", - "protoc-bin-vendored-win32", -] - -[[package]] -name = "protoc-bin-vendored-linux-aarch_64" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fa2624782ca04cd44f51554566717377acd240e4c0016d757dd74fccc9324f" - -[[package]] -name = "protoc-bin-vendored-linux-ppcle_64" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2417e9817fa237dab803ad4dda7357a111656e242959cc6b8f9a1a583367d42" - -[[package]] -name = "protoc-bin-vendored-linux-s390_64" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d189c34636356a46a7ed3188233dc8a88c431278cc54d4a19b096a2d270e985" - -[[package]] -name = "protoc-bin-vendored-linux-x86_32" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171e39f1e846e5f322ced1ac3b8d4cd3a3833ca24b6e5d58b3632574fe6204fa" - -[[package]] -name = "protoc-bin-vendored-linux-x86_64" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "873cdcc097593432086661aa432b8078f1cd87bfb02847c332e98ae2c119e966" - -[[package]] -name = "protoc-bin-vendored-macos-aarch_64" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb72df001783b8297847fe8f5f874ee400fd742c843d60583e8c23d96977c7f" - -[[package]] -name = "protoc-bin-vendored-macos-x86_64" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b04652167eca899dda05f32f5481adeaf25c623a98ce2fc146a001cc59a2add7" - -[[package]] -name = "protoc-bin-vendored-win32" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "263a3f48f01e7309e857138bd47f785585b4a005e8e56c6d2824ce91195999c3" - -[[package]] -name = "pulldown-cmark" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "278e9268c93b9e498a2da46c34d90ba93a3255eb99009646398f34bc73ab36eb" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - -[[package]] -name = "pulldown-cmark-to-cmark" -version = "22.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84bbb29c624230c4bd1047bbdb2aa47e41c860e9665ce62ba9504eebe91bf867" -dependencies = [ - "pulldown-cmark", -] - [[package]] name = "quote" version = "1.0.47" @@ -2833,24 +2415,13 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" -[[package]] -name = "rand" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ - "rand_chacha 0.9.0", + "rand_chacha", "rand_core 0.9.5", ] @@ -2865,16 +2436,6 @@ dependencies = [ "rand_core 0.10.1", ] -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - [[package]] name = "rand_chacha" version = "0.9.0" @@ -3007,45 +2568,6 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" -[[package]] -name = "reqwest" -version = "0.12.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "ring" version = "0.17.14" @@ -3060,12 +2582,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustc-demangle" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" - [[package]] name = "rustc-hash" version = "2.1.3" @@ -3289,17 +2805,6 @@ dependencies = [ "zmij", ] -[[package]] -name = "serde_path_to_error" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" -dependencies = [ - "itoa", - "serde", - "serde_core", -] - [[package]] name = "serde_repr" version = "0.1.21" @@ -3453,7 +2958,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.19", + "thiserror", "time", ] @@ -3532,7 +3037,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "smallvec", - "thiserror 2.0.19", + "thiserror", "tokio", "tokio-stream", "tracing", @@ -3573,7 +3078,7 @@ dependencies = [ "sqlx-postgres", "sqlx-sqlite", "syn 2.0.119", - "thiserror 2.0.19", + "thiserror", "tokio", "url", ] @@ -3600,7 +3105,7 @@ dependencies = [ "sha1 0.11.0", "sha2 0.11.0", "sqlx-core", - "thiserror 2.0.19", + "thiserror", "tracing", ] @@ -3634,7 +3139,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.19", + "thiserror", "tracing", "whoami", ] @@ -3658,7 +3163,7 @@ dependencies = [ "percent-encoding", "serde", "sqlx-core", - "thiserror 2.0.19", + "thiserror", "tracing", "url", ] @@ -3713,27 +3218,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "supports-color" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" -dependencies = [ - "is_ci", -] - -[[package]] -name = "supports-hyperlinks" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" - -[[package]] -name = "supports-unicode" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" - [[package]] name = "syn" version = "2.0.119" @@ -3761,9 +3245,6 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] [[package]] name = "synstructure" @@ -3776,17 +3257,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "synstructure" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - [[package]] name = "tempfile" version = "3.27.0" @@ -3800,53 +3270,13 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "terminal_size" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" -dependencies = [ - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "textwrap" -version = "0.16.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ecfad6c3abc80a577f2b91c1e412ee57e7a060d430b553c1b0c940974ebcd49" -dependencies = [ - "icu_segmenter", - "unicode-width 0.2.3", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" dependencies = [ - "thiserror-impl 2.0.19", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "thiserror-impl", ] [[package]] @@ -3901,12 +3331,11 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.5" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", - "serde_core", "zerovec", ] @@ -3965,22 +3394,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" -dependencies = [ - "futures-util", - "log", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tungstenite", -] - [[package]] name = "tokio-util" version = "0.7.19" @@ -4028,18 +3441,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tonic-build" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c07bd4e9f99e2a3ed8bebad596ae02a94e53745b68acc6900e22c3475c8bc44" -dependencies = [ - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "tonic-prost" version = "0.14.6" @@ -4051,22 +3452,6 @@ dependencies = [ "tonic", ] -[[package]] -name = "tonic-prost-build" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05d8957fac6b3542999796cb4449d45da790751962f974a457e5e00c43d78c" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "prost-types", - "quote", - "syn 2.0.119", - "tempfile", - "tonic-build", -] - [[package]] name = "tonic-types" version = "0.14.6" @@ -4106,16 +3491,13 @@ dependencies = [ "base64 0.22.1", "bitflags", "bytes", - "futures-util", "http", "http-body", "mime", "pin-project-lite", - "tower", "tower-layer", "tower-service", "tracing", - "url", "uuid", ] @@ -4227,25 +3609,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" -dependencies = [ - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand 0.9.5", - "rustls", - "rustls-pki-types", - "sha1 0.10.7", - "thiserror 2.0.19", - "utf-8", -] - [[package]] name = "typenum" version = "1.20.1" @@ -4258,12 +3621,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" -[[package]] -name = "unicase" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f" - [[package]] name = "unicode-bidi" version = "0.3.18" @@ -4297,18 +3654,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-width" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca718471876992059f251e33aafc334346ada08042b7661dd1fe313a9bced557" - [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -4337,15 +3682,8 @@ dependencies = [ "idna", "percent-encoding", "serde", - "serde_derive", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -4434,16 +3772,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.126" @@ -4476,16 +3804,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "web-sys" -version = "0.3.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "web-time" version = "1.1.0" @@ -4682,9 +4000,9 @@ checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "x509-parser" @@ -4700,7 +4018,7 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror 2.0.19", + "thiserror", "time", ] @@ -4716,9 +4034,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.4" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -4727,14 +4045,14 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", - "synstructure 0.14.0", + "syn 2.0.119", + "synstructure", ] [[package]] @@ -4775,7 +4093,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.119", - "synstructure 0.13.2", + "synstructure", ] [[package]] @@ -4800,23 +4118,21 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", "zerofrom", - "zerovec", ] [[package]] name = "zerovec" -version = "0.11.9" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ - "serde", "yoke", "zerofrom", "zerovec-derive", @@ -4824,13 +4140,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.7" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 2.0.119", ] [[package]] diff --git a/e2e/rust/Cargo.toml b/e2e/rust/Cargo.toml index 66293d3582..b40b170996 100644 --- a/e2e/rust/Cargo.toml +++ b/e2e/rust/Cargo.toml @@ -32,7 +32,7 @@ e2e-docker = ["e2e", "e2e-host-gateway", "e2e-local-container-driver"] e2e-config-push = ["e2e-docker"] e2e-gpu = ["e2e"] e2e-docker-gpu = ["e2e-docker", "e2e-gpu"] -e2e-kubernetes = ["e2e", "dep:openshell-bootstrap", "dep:openshell-sdk"] +e2e-kubernetes = ["e2e"] e2e-kubernetes-ha = ["e2e-kubernetes"] e2e-kubernetes-credential-drivers = ["e2e-kubernetes"] e2e-kubernetes-workspace-managed = ["e2e-kubernetes"] @@ -194,11 +194,6 @@ name = "kubernetes_runtime_reconcile" path = "tests/kubernetes_runtime_reconcile.rs" required-features = ["e2e-kubernetes"] -[[test]] -name = "kubernetes_image_update" -path = "tests/kubernetes_image_update.rs" -required-features = ["e2e-kubernetes"] - [[test]] name = "credential_drivers" path = "tests/credential_drivers.rs" @@ -278,8 +273,6 @@ required-features = ["e2e-local-container-driver"] openshell-crypto = { path = "../../crates/openshell-crypto" } openshell-otel-test-support = { path = "../../crates/openshell-otel-test-support" } opentelemetry-proto = { version = "0.32", default-features = false, features = ["gen-tonic", "trace"] } -openshell-bootstrap = { path = "../../crates/openshell-bootstrap", optional = true } -openshell-sdk = { path = "../../crates/openshell-sdk", optional = true } base64 = "0.22" bollard = "0.20" bytes = "1" diff --git a/e2e/rust/e2e-kubernetes.sh b/e2e/rust/e2e-kubernetes.sh index 1ffa79cea5..9bdcf4e6a2 100755 --- a/e2e/rust/e2e-kubernetes.sh +++ b/e2e/rust/e2e-kubernetes.sh @@ -98,12 +98,22 @@ run_suite() { } run_e2e() { + if [ "${OPENSHELL_E2E_KUBE_TEST:-}" = "kubernetes_image_update" ]; then + cargo test --locked --manifest-path "${ROOT}/tests/suites/features/Cargo.toml" \ + -p openshell-test-feature-kubernetes-updates -- --nocapture + return + fi run_conformance if [ "${E2E_FEATURES}" = "e2e-conformance-only" ]; then echo "::notice::Skipping Rust e2e tests (e2e-conformance-only)" return 0 fi + if [ -z "${OPENSHELL_E2E_KUBE_TEST:-}" ]; then + cargo test --locked --manifest-path "${ROOT}/tests/suites/features/Cargo.toml" \ + -p openshell-test-feature-kubernetes-updates -- --nocapture + fi + # Pin `--target-dir` so the profile `junit.path` resolves regardless of `CARGO_TARGET_DIR`. cargo nextest run --profile e2e-kubernetes \ --config-file "${ROOT}/.config/nextest.toml" \ diff --git a/e2e/with-kube-gateway.sh b/e2e/with-kube-gateway.sh index 31c0771dc8..fae4260438 100755 --- a/e2e/with-kube-gateway.sh +++ b/e2e/with-kube-gateway.sh @@ -98,6 +98,7 @@ PORTFORWARD_LOG="${WORKDIR}/portforward.log" PORTFORWARD_HEALTH_PID="" PORTFORWARD_HEALTH_LOG="${WORKDIR}/portforward-health.log" HELM_INSTALLED=0 +WORKSPACE_HELM_INSTALLED=0 EXTERNAL_PG_FIXTURE_DEPLOYED=0 EXTERNAL_PG_FIXTURE_SECRET="" EXTERNAL_PG_FIXTURE_MANIFEST="${ROOT}/e2e/kubernetes/postgres-fixture.yaml" @@ -583,6 +584,10 @@ cleanup() { fi fi + if [ "${WORKSPACE_HELM_INSTALLED}" = "1" ]; then + helmctl uninstall "${RELEASE_NAME}-workspace" --namespace "${NAMESPACE}" || true + fi + if [ "${EXTERNAL_PG_FIXTURE_DEPLOYED}" = "1" ] \ || [ "${OPENSHIFT_POSTGRES_SCC_GRANTED}" = "1" ]; then cleanup_postgres_fixture "${EXTERNAL_PG_FIXTURE_SECRET}" @@ -1532,6 +1537,15 @@ else deploy_postgres_fixture "${OPENSHELL_E2E_KUBE_EXTERNAL_POSTGRES_SECRET}" fi + if [ "${OPENSHELL_E2E_KUBE_SPLIT_WORKSPACE:-0}" = "1" ]; then + helmctl install "${RELEASE_NAME}-workspace" "${ROOT}/deploy/helm/openshell-workspace" \ + --namespace "${NAMESPACE}" --create-namespace \ + --set "gateway.serviceAccount.namespace=${NAMESPACE}" \ + --wait --timeout 2m + WORKSPACE_HELM_INSTALLED=1 + helm_extra_args+=(--set workspaceResources.enabled=false) + fi + echo "Installing Helm chart (release=${RELEASE_NAME}, namespace=${NAMESPACE}, tag=${IMAGE_TAG_VALUE})..." helmctl install "${RELEASE_NAME}" "${ROOT}/deploy/helm/openshell" \ --namespace "${NAMESPACE}" --create-namespace \ diff --git a/proto/compute_driver.proto b/proto/compute_driver.proto index 12c7efc2aa..e50f41d0ee 100644 --- a/proto/compute_driver.proto +++ b/proto/compute_driver.proto @@ -74,20 +74,9 @@ service ComputeDriver { rpc DeleteWorkspace(DeleteWorkspaceRequest) returns (DeleteWorkspaceResponse); } -// Optional image-update extension, served on the same endpoint as ComputeDriver. -// Keeping this separate preserves the baseline generated server trait for -// independently versioned external drivers. Drivers advertise -// openshell.compute.update-sandbox-image only when they serve this service; -// gateways must negotiate that capability before calling it. -service ComputeDriverImageUpdates { - // Idempotently replace only the workload image of a stopped sandbox, retaining - // its stable resource and storage. Unsupported drivers omit this service and - // return UNIMPLEMENTED without changing any resource. - rpc UpdateSandboxImage(UpdateSandboxImageRequest) - returns (UpdateSandboxImageResponse); -} - -// Optional extension; never send configuration changes through the image-only RPC. +// Optional stopped-sandbox configuration update extension on the same endpoint. +// Baseline generated driver traits remain unchanged. Negotiate +// openshell.compute.update-sandbox-configuration before calling this service. service ComputeDriverConfigurationUpdates { rpc UpdateSandboxConfiguration(UpdateSandboxConfigurationRequest) returns (UpdateSandboxConfigurationResponse); @@ -95,7 +84,7 @@ service ComputeDriverConfigurationUpdates { message UpdateSandboxConfigurationRequest { // Shared lifecycle, image, revision and runtime identity preconditions. - UpdateSandboxImageRequest image_update = 1; + SandboxUpdatePreconditions preconditions = 1; // Absent leaves the command unchanged; empty restores the default shell. SandboxMainProcessUpdate main_process = 2; // Effective user environment after template inheritance. Presence replaces it. @@ -481,7 +470,7 @@ message CreateSandboxResponse { string runtime_identity = 1; } -message UpdateSandboxImageRequest { +message SandboxUpdatePreconditions { string sandbox_id = 1; string name = 2; string image = 3; @@ -500,7 +489,6 @@ message UpdateSandboxImageRequest { uint64 revision = 8; } -message UpdateSandboxImageResponse {} message StopSandboxRequest { // Stable sandbox ID stored by the gateway. diff --git a/proto/openshell.proto b/proto/openshell.proto index 027be4a87c..e498a84af9 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -1347,7 +1347,8 @@ message CreateSandboxRequest { } // Update selected configuration of a stopped sandbox. Omitted fields are unchanged. -// Start explicitly after a successful update. At least one field must be selected. +// Start explicitly after a successful update. With no fields selected, resume +// the pending operation stored by the gateway using the current resource version. message UpdateSandboxRequest { // Workspace scope. Only a named workspace selection is accepted. openshell.datamodel.v1.WorkspaceSelector workspace_scope = 1; diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index 9214f4f9d0..1ae1800784 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -3696,7 +3696,8 @@ func (x *CreateSandboxRequest) GetServiceExposures() []*SandboxServiceExposure { } // Update selected configuration of a stopped sandbox. Omitted fields are unchanged. -// Start explicitly after a successful update. At least one field must be selected. +// Start explicitly after a successful update. With no fields selected, resume +// the pending operation stored by the gateway using the current resource version. type UpdateSandboxRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // Workspace scope. Only a named workspace selection is accepted. diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index a6909b8155..bdc21e2434 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -1455,26 +1455,26 @@ retired, their outstanding driver operations have settled, and old binaries cannot return through rollout or rollback configurations. Keep it false during a rolling upgrade. SQLite supports one gateway process, not shared-file HA. -On PostgreSQL, an unmarked client backend in the same database blocks updates, -including an administrative session. The new binary sets every pool -connection's `application_name` to `openshell-image-update-v2`; close unmarked -sessions or use a dedicated database, rather than relabeling old clients. Live -gateway membership must advertise image-update protocol 2; malformed or -truncated membership reads fail closed. Neither these observations nor an -expired membership TTL proves old gateways and their work have stopped. Follow -the published -[activation checklist](https://docs.nvidia.com/openshell/latest/kubernetes/high-availability#activate-sandbox-updates), -and do not downgrade while updates are pending or retained sandboxes require -the private revision protocol. - -For an operation-pending error, use the original selected fields and target values and a fresh -sandbox resource version to reconcile through `SandboxUpdates`. Intent and -revision are private, not new public status fields. Start, stop, provisioning -retry, and delete do not bypass the barrier. Preserve request-admission semantics: -never change the payload under an existing ID or blindly switch IDs after a -timeout. See the published +On PostgreSQL, fresh gateway membership must advertise sandbox-update protocol 1; +malformed or truncated membership reads fail closed. Administrative, monitoring, +and backup connections do not block updates, and custom `application_name` values +are preserved. Membership expiry does not prove a gateway has stopped. Follow the +[activation checklist](https://docs.nvidia.com/openshell/latest/kubernetes/high-availability#activate-sandbox-updates). + +The gateway retries accepted updates automatically, even with new updates disabled. +To resume immediately, read the sandbox resource version and call `UpdateSandbox` +with that version and no selected fields. Restore a compatible driver if recovery +reports missing support. Start, stop, and provisioning retry retain the barrier; +explicit deletion can reclaim an unrecoverable sandbox and its storage. Preserve +request admission semantics: use a new ID or no ID for the explicit resume request, +and never change the original payload under its original ID. See the [recovery contract](https://docs.nvidia.com/openshell/latest/sdk/api-errors#sandbox-image-update-recovery). +Split Helm deployments need the current `openshell-workspace` Role, including +`get` and `list` on Pods. The update preflight must find remaining Pods by owner +UID and controller-recorded name as well as labels. Upgrade the workspace chart +alongside the gateway chart; a label selector does not remove the `list` permission. + ### Step 7: Check VM-Backed Gateways Use the VM driver logs and host diagnostics available in the user's environment. Verify: diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index 647f0b999f..909656aa3d 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -527,6 +527,10 @@ stopped or completed. Starting a retained `Completed` or invalidates SSH sessions from the previous runtime generation. Delete remains the operation that removes retained state. +Before updating a retained `Completed` or `Error/MainProcessFailed` sandbox, +run `sandbox stop`. It cleans up compute and transitions to `Stopped`, retaining +the exit code until the next start. + The sandbox's SSH host identity survives stop/start and runtime restarts. API clients can read its public fingerprint from the sandbox resource or SSH-session response and pin it to the sandbox ID. Recreating a deleted @@ -578,21 +582,21 @@ unchanged; supplied lists and maps replace their user-owned values, including explicitly empty values. Template environment defaults still apply. System metadata is protected; top-level labels and annotations do not update pod metadata. Combined configuration changes require the configuration-update driver capability -and a uniformly upgraded protocol-2 gateway deployment. +and a uniformly upgraded gateway deployment. Metadata-only updates need no +driver capability and preserve the retention annotation. For an image that fails to start and reaches a provisioning timeout, wait for cleanup completion and settlement of the original driver operation, then run `sandbox stop` to obtain `Stopped` before correcting the image. This retains the timeout diagnostic and storage and does not bypass pending cleanup. -An operation-pending error after a failure blocks start, stop, provisioning -retry, and delete. Image intent and revision are private; the public `SandboxStatus` -shape is unchanged. Read a fresh version and retry the same selected fields and target values originally -requested, even if the spec already names it. An optional -`request_id` with an unresolved admission does not execute again; inspect and -reconcile state before submitting a new conditional request with a fresh -version and new ID, or no ID. Never change the payload under the original ID or -blindly switch IDs after a timeout. See the published +An operation-pending error blocks start, stop, and provisioning retry. The gateway +retries automatically even when new updates are disabled. To resume immediately, +read a fresh resource version and call `UpdateSandbox` with no selected fields; +the gateway loads the stored targets. Use a new request ID or no ID for this +explicit resume. An unresolved original ID returns uncertainty, and its payload +must not change. Explicit delete can reclaim a sandbox whose update cannot +complete, including its storage. See the published [image update workflow](https://docs.nvidia.com/openshell/latest/how-it-works/sandboxes/overview#update-the-image-of-a-stopped-sandbox) and [API errors](https://docs.nvidia.com/openshell/latest/sdk/api-errors). diff --git a/tasks/test.toml b/tasks/test.toml index 7714d14dd4..0e27645d67 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -254,6 +254,14 @@ run = [ "AGENT_SANDBOX_VERSION=v0.4.6 e2e/rust/e2e-kubernetes.sh", ] +["e2e:kubernetes:updates"] +description = "Validate sandbox updates with split workspace RBAC on both Agent Sandbox APIs" +env = { OPENSHELL_E2E_KUBE_TEST = "kubernetes_image_update", OPENSHELL_E2E_KUBE_SPLIT_WORKSPACE = "1" } +run = [ + "e2e/rust/e2e-kubernetes.sh", + "AGENT_SANDBOX_VERSION=v0.4.6 e2e/rust/e2e-kubernetes.sh", +] + ["e2e:kubernetes:isolation"] description = "Run Kubernetes e2e with the workload network fence and separate supervisor" run = "e2e/rust/e2e-kubernetes.sh" diff --git a/tests/suites/features/Cargo.lock b/tests/suites/features/Cargo.lock index 7e6509f278..f7a166861b 100644 --- a/tests/suites/features/Cargo.lock +++ b/tests/suites/features/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e567177890eb1617b1f774005b66b26b2377afd138a2ca37aae7d8f0c81429d4" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" version = "2.0.1" @@ -63,7 +72,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror", + "thiserror 2.0.20", "time", ] @@ -234,6 +243,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "backtrace" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f4220217f3288537b83684130f42fad43320b1c3b805f1910d683d52ded24f" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + [[package]] name = "base64" version = "0.22.1" @@ -306,7 +339,7 @@ dependencies = [ "serde_derive", "serde_json", "serde_urlencoded", - "thiserror", + "thiserror 2.0.20", "tokio", "tokio-util", "tower-service", @@ -718,6 +751,12 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flate2" version = "1.1.10" @@ -889,8 +928,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -917,6 +958,18 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "gimli" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1033caf0b349c518623b5396bfb2cf0bddf44f0306d543a250e5743297aafd10" + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + [[package]] name = "gloo-timers" version = "0.3.0" @@ -1204,13 +1257,16 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", "futures-util", "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", @@ -1259,9 +1315,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +checksum = "fe090a42a0d3140fed8c63263ed1fecc02422cb2f4bfe55cd8de2de1b8e105dd" dependencies = [ "displaydoc", "potential_utf", @@ -1273,22 +1329,43 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" dependencies = [ "displaydoc", "litemap", + "serde", "tinystr", "writeable", "zerovec", ] +[[package]] +name = "icu_locale_fallback" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406e9ae5b95d8aa37db6293405931b766a6172d1848daee22d70eb44aa78a43c" +dependencies = [ + "icu_locale_core", + "icu_locale_fallback_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_fallback_data" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3632ebbd0c5c3637ba1a40bdf8288f2cb9d2268e73441a69d5fc73d7cfbaa87c" + [[package]] name = "icu_normalizer" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +checksum = "404a3b8c486f205c87fe7f23ab6894d84a4ad76d6e4671ae1981ba7def87c599" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1300,15 +1377,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" +checksum = "20f0088bfb7441f7a37fa0c9e20cb1e9cba1cac6b9ce8cd2a6dc44294f8e8cbc" [[package]] name = "icu_properties" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +checksum = "2ea83d991c56158f7cf898bf86436c1dfe7c07ee82fe88951f2695c9f37a379f" dependencies = [ "displaydoc", "icu_collections", @@ -1321,18 +1398,20 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" +checksum = "b98f29af82d02b163fe50161388350e743bb3107cc8e8c2f7314cb505faddfcf" [[package]] name = "icu_provider" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514" dependencies = [ "displaydoc", "icu_locale_core", + "serde", + "stable_deref_trait", "writeable", "yoke", "zerofrom", @@ -1340,6 +1419,29 @@ dependencies = [ "zerovec", ] +[[package]] +name = "icu_segmenter" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b195dc605f81aa181bec9b3bd14e26cc71b903e4644f6af578ca9772c7a710" +dependencies = [ + "icu_collections", + "icu_locale_fallback", + "icu_provider", + "icu_segmenter_data", + "potential_utf", + "smallvec", + "utf8_iter", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_segmenter_data" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913a7d294ad056474749152107309fdee3ec17d2482d1ab70fdc61a81c64b9a3" + [[package]] name = "ident_case" version = "1.0.1" @@ -1379,6 +1481,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "ipnet" +version = "2.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" + +[[package]] +name = "is_ci" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + [[package]] name = "itertools" version = "0.14.0" @@ -1424,7 +1538,7 @@ dependencies = [ "jsonptr", "serde", "serde_json", - "thiserror", + "thiserror 2.0.20", ] [[package]] @@ -1437,7 +1551,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror", + "thiserror 2.0.20", ] [[package]] @@ -1523,7 +1637,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "thiserror", + "thiserror 2.0.20", "tokio", "tokio-util", "tower", @@ -1546,7 +1660,7 @@ dependencies = [ "serde", "serde-value", "serde_json", - "thiserror", + "thiserror 2.0.20", ] [[package]] @@ -1585,7 +1699,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror", + "thiserror 2.0.20", "tokio", "tokio-util", "tracing", @@ -1688,6 +1802,36 @@ dependencies = [ "rapidhash", ] +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "backtrace", + "backtrace-ext", + "cfg-if", + "miette-derive", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "unicode-width 0.1.14", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "mime" version = "0.3.17" @@ -1721,6 +1865,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + [[package]] name = "nix" version = "0.29.0" @@ -1801,6 +1951,35 @@ dependencies = [ "autocfg", ] +[[package]] +name = "oauth2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" +dependencies = [ + "base64 0.22.1", + "chrono", + "getrandom 0.2.17", + "http", + "rand 0.8.8", + "reqwest", + "serde", + "serde_json", + "serde_path_to_error", + "sha2 0.10.9", + "thiserror 1.0.69", + "url", +] + +[[package]] +name = "object" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd229a0361b9d0d4396176e02d65897f487eebeab7caa6d443855ee152ca0b9c" +dependencies = [ + "memchr", +] + [[package]] name = "oid-registry" version = "0.8.1" @@ -1816,6 +1995,22 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "openshell-bootstrap" +version = "0.0.0" +dependencies = [ + "bytes", + "miette", + "openshell-core", + "openshell-crypto", + "rcgen", + "serde", + "serde_json", + "tempfile", + "tokio", + "tracing", +] + [[package]] name = "openshell-conformance" version = "0.0.0" @@ -1827,6 +2022,43 @@ dependencies = [ "tokio", ] +[[package]] +name = "openshell-core" +version = "0.0.0" +dependencies = [ + "async-trait", + "base64 0.22.1", + "chrono", + "glob", + "ipnet", + "libc", + "miette", + "nix", + "openshell-crypto", + "openshell-extension-core", + "openshell-policy-schema", + "prost", + "prost-types", + "protoc-bin-vendored", + "reqwest", + "rustix", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "sha2 0.10.9", + "thiserror 2.0.20", + "tokio", + "tokio-stream", + "tonic", + "tonic-prost", + "tonic-prost-build", + "tonic-types", + "tracing", + "url", + "uuid", +] + [[package]] name = "openshell-crypto" version = "0.0.0" @@ -1839,7 +2071,7 @@ dependencies = [ "rustls", "serde", "sqlx", - "thiserror", + "thiserror 2.0.20", "tonic", "x509-parser", ] @@ -1879,6 +2111,18 @@ dependencies = [ "url", ] +[[package]] +name = "openshell-extension-core" +version = "0.0.0" +dependencies = [ + "hyper-util", + "serde", + "thiserror 2.0.20", + "tokio", + "tonic", + "tower", +] + [[package]] name = "openshell-ocsf" version = "0.0.0" @@ -1904,7 +2148,7 @@ dependencies = [ "opentelemetry-otlp", "opentelemetry_sdk", "serde_json", - "thiserror", + "thiserror 2.0.20", "tokio", "tonic", "tower-http", @@ -1927,6 +2171,56 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "openshell-policy-schema" +version = "0.0.0" +dependencies = [ + "miette", + "noyalib", + "serde", + "serde_json", + "serde_path_to_error", + "thiserror 2.0.20", +] + +[[package]] +name = "openshell-sdk" +version = "0.0.0" +dependencies = [ + "async-stream", + "async-trait", + "futures", + "hyper", + "hyper-util", + "miette", + "oauth2", + "openshell-core", + "openshell-crypto", + "reqwest", + "rustls", + "serde", + "thiserror 2.0.20", + "tokio", + "tokio-rustls", + "tokio-tungstenite", + "tonic", + "tower", + "tracing", +] + +[[package]] +name = "openshell-test-feature-kubernetes-updates" +version = "0.0.0" +dependencies = [ + "hex", + "openshell-testkit", + "rand 0.9.5", + "serde_json", + "tempfile", + "tokio", + "tonic", +] + [[package]] name = "openshell-test-feature-oci-image" version = "0.0.0" @@ -1948,6 +2242,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "openshell-testkit" +version = "0.0.0" +dependencies = [ + "futures", + "openshell-bootstrap", + "openshell-core", + "openshell-sdk", + "openshell-testkit-macros", + "rand 0.9.5", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "openshell-testkit-macros" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "openssl-probe" version = "0.2.1" @@ -1964,7 +2282,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror", + "thiserror 2.0.20", "tracing", ] @@ -1979,7 +2297,7 @@ dependencies = [ "opentelemetry-proto", "opentelemetry_sdk", "prost", - "thiserror", + "thiserror 2.0.20", "tokio", "tonic", "tonic-types", @@ -2011,7 +2329,7 @@ dependencies = [ "percent-encoding", "portable-atomic", "rand 0.9.5", - "thiserror", + "thiserror 2.0.20", "tokio", "tokio-stream", ] @@ -2025,6 +2343,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "owo-colors" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c45bb4a6ae1280ec0803b1ef9d3455eb50f01efbbe1447ab020f1d54fba9d8" + [[package]] name = "parking" version = "2.2.1" @@ -2122,6 +2446,17 @@ dependencies = [ "pest", ] +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", +] + [[package]] name = "pin-project" version = "1.1.13" @@ -2166,6 +2501,8 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ + "serde_core", + "writeable", "zerovec", ] @@ -2184,6 +2521,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.119", +] + [[package]] name = "proc-macro2" version = "1.0.107" @@ -2203,6 +2550,27 @@ dependencies = [ "prost-derive", ] +[[package]] +name = "prost-build" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" +dependencies = [ + "heck", + "itertools", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "pulldown-cmark", + "pulldown-cmark-to-cmark", + "regex", + "syn 2.0.119", + "tempfile", +] + [[package]] name = "prost-derive" version = "0.14.4" @@ -2225,6 +2593,90 @@ dependencies = [ "prost", ] +[[package]] +name = "protoc-bin-vendored" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8760a25b6ff9c620324822737e468478fa092234190d2e449760344354896ed9" +dependencies = [ + "protoc-bin-vendored-linux-aarch_64", + "protoc-bin-vendored-linux-ppcle_64", + "protoc-bin-vendored-linux-s390_64", + "protoc-bin-vendored-linux-x86_32", + "protoc-bin-vendored-linux-x86_64", + "protoc-bin-vendored-macos-aarch_64", + "protoc-bin-vendored-macos-x86_64", + "protoc-bin-vendored-win32", +] + +[[package]] +name = "protoc-bin-vendored-linux-aarch_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fa2624782ca04cd44f51554566717377acd240e4c0016d757dd74fccc9324f" + +[[package]] +name = "protoc-bin-vendored-linux-ppcle_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2417e9817fa237dab803ad4dda7357a111656e242959cc6b8f9a1a583367d42" + +[[package]] +name = "protoc-bin-vendored-linux-s390_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d189c34636356a46a7ed3188233dc8a88c431278cc54d4a19b096a2d270e985" + +[[package]] +name = "protoc-bin-vendored-linux-x86_32" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171e39f1e846e5f322ced1ac3b8d4cd3a3833ca24b6e5d58b3632574fe6204fa" + +[[package]] +name = "protoc-bin-vendored-linux-x86_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873cdcc097593432086661aa432b8078f1cd87bfb02847c332e98ae2c119e966" + +[[package]] +name = "protoc-bin-vendored-macos-aarch_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeb72df001783b8297847fe8f5f874ee400fd742c843d60583e8c23d96977c7f" + +[[package]] +name = "protoc-bin-vendored-macos-x86_64" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04652167eca899dda05f32f5481adeaf25c623a98ce2fc146a001cc59a2add7" + +[[package]] +name = "protoc-bin-vendored-win32" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "263a3f48f01e7309e857138bd47f785585b4a005e8e56c6d2824ce91195999c3" + +[[package]] +name = "pulldown-cmark" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278e9268c93b9e498a2da46c34d90ba93a3255eb99009646398f34bc73ab36eb" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + +[[package]] +name = "pulldown-cmark-to-cmark" +version = "22.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84bbb29c624230c4bd1047bbdb2aa47e41c860e9665ce62ba9504eebe91bf867" +dependencies = [ + "pulldown-cmark", +] + [[package]] name = "quote" version = "1.0.47" @@ -2246,13 +2698,24 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ - "rand_chacha", + "rand_chacha 0.9.0", "rand_core 0.9.5", ] @@ -2267,6 +2730,16 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_chacha" version = "0.9.0" @@ -2362,6 +2835,45 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "ring" version = "0.17.14" @@ -2376,6 +2888,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + [[package]] name = "rustc-hash" version = "2.1.3" @@ -2599,6 +3117,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + [[package]] name = "serde_repr" version = "0.1.21" @@ -2727,7 +3256,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 2.0.20", "time", ] @@ -2806,7 +3335,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "smallvec", - "thiserror", + "thiserror 2.0.20", "tokio", "tokio-stream", "tracing", @@ -2847,7 +3376,7 @@ dependencies = [ "sqlx-postgres", "sqlx-sqlite", "syn 2.0.119", - "thiserror", + "thiserror 2.0.20", "tokio", "url", ] @@ -2874,7 +3403,7 @@ dependencies = [ "sha1 0.11.0", "sha2 0.11.0", "sqlx-core", - "thiserror", + "thiserror 2.0.20", "tracing", ] @@ -2908,7 +3437,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 2.0.20", "tracing", "whoami", ] @@ -2932,7 +3461,7 @@ dependencies = [ "percent-encoding", "serde", "sqlx-core", - "thiserror", + "thiserror 2.0.20", "tracing", "url", ] @@ -2966,6 +3495,27 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "supports-color" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" +dependencies = [ + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" + +[[package]] +name = "supports-unicode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" + [[package]] name = "syn" version = "2.0.119" @@ -2993,6 +3543,9 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -3023,19 +3576,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.61.2", ] +[[package]] +name = "terminal_size" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +dependencies = [ + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "textwrap" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ecfad6c3abc80a577f2b91c1e412ee57e7a060d430b553c1b0c940974ebcd49" +dependencies = [ + "icu_segmenter", + "unicode-width 0.2.3", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.20", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] @@ -3090,11 +3683,12 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" dependencies = [ "displaydoc", + "serde_core", "zerovec", ] @@ -3153,6 +3747,22 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.19" @@ -3200,6 +3810,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic-build" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c07bd4e9f99e2a3ed8bebad596ae02a94e53745b68acc6900e22c3475c8bc44" +dependencies = [ + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "tonic-prost" version = "0.14.6" @@ -3211,6 +3833,22 @@ dependencies = [ "tonic", ] +[[package]] +name = "tonic-prost-build" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05d8957fac6b3542999796cb4449d45da790751962f974a457e5e00c43d78c" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "prost-types", + "quote", + "syn 2.0.119", + "tempfile", + "tonic-build", +] + [[package]] name = "tonic-types" version = "0.14.6" @@ -3250,13 +3888,16 @@ dependencies = [ "base64 0.22.1", "bitflags", "bytes", + "futures-util", "http", "http-body", "mime", "pin-project-lite", + "tower", "tower-layer", "tower-service", "tracing", + "url", "uuid", ] @@ -3368,6 +4009,25 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.5", + "rustls", + "rustls-pki-types", + "sha1 0.10.7", + "thiserror 2.0.20", + "utf-8", +] + [[package]] name = "typenum" version = "1.20.1" @@ -3380,6 +4040,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" +[[package]] +name = "unicase" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f" + [[package]] name = "unicode-bidi" version = "0.3.18" @@ -3407,6 +4073,18 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca718471876992059f251e33aafc334346ada08042b7661dd1fe313a9bced557" + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -3435,8 +4113,15 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -3509,6 +4194,16 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.128" @@ -3541,6 +4236,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "web-time" version = "1.1.0" @@ -3755,7 +4460,7 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 2.0.20", "time", ] @@ -3771,9 +4476,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -3782,9 +4487,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", @@ -3862,14 +4567,16 @@ dependencies = [ "displaydoc", "yoke", "zerofrom", + "zerovec", ] [[package]] name = "zerovec" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ + "serde", "yoke", "zerofrom", "zerovec-derive", @@ -3877,9 +4584,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", diff --git a/tests/suites/features/Cargo.toml b/tests/suites/features/Cargo.toml index 9259450a16..9b4760c2a9 100644 --- a/tests/suites/features/Cargo.toml +++ b/tests/suites/features/Cargo.toml @@ -3,4 +3,4 @@ [workspace] resolver = "2" -members = ["oci-image", "provider-refresh/keycloak"] +members = ["oci-image", "kubernetes-updates", "provider-refresh/keycloak"] diff --git a/tests/suites/features/kubernetes-updates/Cargo.toml b/tests/suites/features/kubernetes-updates/Cargo.toml new file mode 100644 index 0000000000..2f63c0cc45 --- /dev/null +++ b/tests/suites/features/kubernetes-updates/Cargo.toml @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +[package] +name = "openshell-test-feature-kubernetes-updates" +version = "0.0.0" +edition = "2024" + +[dependencies] +openshell-testkit = { path = "../../../testkit/testkit" } +serde_json = "1" +tempfile = "3" +rand = "0.9" +hex = "0.4" +tokio = { version = "1.43", features = ["process", "time"] } +tonic = "0.14" diff --git a/e2e/rust/tests/kubernetes_image_update.rs b/tests/suites/features/kubernetes-updates/tests/update.rs similarity index 50% rename from e2e/rust/tests/kubernetes_image_update.rs rename to tests/suites/features/kubernetes-updates/tests/update.rs index d1ff02e71f..4a49d4ec5a 100644 --- a/e2e/rust/tests/kubernetes_image_update.rs +++ b/tests/suites/features/kubernetes-updates/tests/update.rs @@ -1,72 +1,31 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -#![cfg(feature = "e2e-kubernetes")] - //! Exercise the public image-update RPC in both Agent Sandbox API-version lanes. -//! Kubernetes object checks are read-only and scoped to this test's sandbox. +//! Kubernetes checks are scoped to test-owned resources. use std::collections::BTreeMap; -use std::path::PathBuf; use std::time::Duration; -use openshell_bootstrap::{load_active_gateway, load_gateway_metadata}; -use openshell_e2e::harness::cli::{run_cli, wait_for_sandbox_phase}; -use openshell_e2e::harness::sandbox::SandboxGuard; -use openshell_sdk::raw::{AuthedGrpcClient, AuthedSandboxUpdatesClient, proto}; -use openshell_sdk::{ClientConfig, EdgeAuthInterceptor, OpenShellClient}; use serde_json::Value; -use tonic::transport::{Certificate, ClientTlsConfig, Endpoint, Identity}; +use std::sync::LazyLock; +use testkit::sdk::raw::{AuthedGrpcClient, AuthedSandboxUpdatesClient, proto}; +use testkit::{Context, Sandbox}; // Multi-platform release manifests; no test-local tags or cluster image loads. -const ORIGINAL_IMAGE: &str = "docker.io/library/alpine:3.21@sha256:ce64758a109eb420d874a118f87920e625e12d3634e03b4a5573fd9f6e5d3507"; -const UPDATED_IMAGE: &str = "docker.io/library/alpine:3.22@sha256:5291449c3df73caf6ed85e649dec1b9e818b39a5d8c871e97afc13e9cd5e8fa8"; +const ORIGINAL_IMAGE_DEFAULT: &str = "mirror.gcr.io/library/alpine:3.21@sha256:ce64758a109eb420d874a118f87920e625e12d3634e03b4a5573fd9f6e5d3507"; +const UPDATED_IMAGE_DEFAULT: &str = "mirror.gcr.io/library/alpine:3.22@sha256:5291449c3df73caf6ed85e649dec1b9e818b39a5d8c871e97afc13e9cd5e8fa8"; const SENTINEL_PATH: &str = "/sandbox/.image-update-sentinel"; -/// Reuse the wrapper's registered endpoint (including its isolated XDG config). -/// The SDK owns plaintext transport; the `OpenShift` wrapper registers an mTLS -/// gateway, for which we attach its existing client bundle to a tonic channel. -async fn gateway_client() -> OpenShellClient { - let name = std::env::var("OPENSHELL_GATEWAY") - .ok() - .filter(|name| !name.trim().is_empty()) - .or_else(load_active_gateway) - .expect("Kubernetes E2E wrapper must register a gateway"); - let metadata = load_gateway_metadata(&name).expect("load E2E gateway metadata"); - if metadata.gateway_endpoint.starts_with("http://") { - OpenShellClient::connect(ClientConfig::new(metadata.gateway_endpoint)) - .await - .expect("connect to E2E gateway") - } else { - assert!( - matches!(metadata.auth_mode.as_deref(), None | Some("mtls")), - "Kubernetes E2E wrapper must register plaintext or mTLS transport" - ); - let config = std::env::var_os("XDG_CONFIG_HOME").map_or_else( - || PathBuf::from(std::env::var_os("HOME").expect("HOME")).join(".config"), - PathBuf::from, - ); - let bundle = config.join("openshell/gateways").join(&name).join("mtls"); - let tls = ClientTlsConfig::new() - .ca_certificate(Certificate::from_pem( - std::fs::read(bundle.join("ca.crt")).expect("read E2E gateway CA"), - )) - .identity(Identity::from_pem( - std::fs::read(bundle.join("tls.crt")).expect("read E2E client certificate"), - std::fs::read(bundle.join("tls.key")).expect("read E2E client key"), - )); - let channel = Endpoint::from_shared(metadata.gateway_endpoint) - .expect("E2E gateway endpoint") - .connect_timeout(Duration::from_secs(10)) - .timeout(Duration::from_secs(60)) - .tls_config(tls) - .expect("configure E2E gateway mTLS") - .connect() - .await - .expect("connect to E2E gateway over mTLS"); - OpenShellClient::from_parts(channel, EdgeAuthInterceptor::noop()) - } -} +// CI can use a private mirror without changing the tested image versions. +static ORIGINAL_IMAGE: LazyLock = LazyLock::new(|| { + std::env::var("OPENSHELL_E2E_UPDATE_ORIGINAL_IMAGE") + .unwrap_or_else(|_| ORIGINAL_IMAGE_DEFAULT.into()) +}); +static UPDATED_IMAGE: LazyLock = LazyLock::new(|| { + std::env::var("OPENSHELL_E2E_UPDATE_TARGET_IMAGE") + .unwrap_or_else(|_| UPDATED_IMAGE_DEFAULT.into()) +}); fn request_id() -> String { let mut bytes = rand::random::<[u8; 16]>(); @@ -89,10 +48,10 @@ fn rpc(body: T) -> tonic::Request { request } -async fn get_sandbox(client: &mut AuthedGrpcClient, name: &str) -> proto::Sandbox { +async fn get_sandbox(client: &mut AuthedGrpcClient, workspace: &str, name: &str) -> proto::Sandbox { client .get_sandbox(rpc(proto::GetSandboxRequest { - workspace_scope: Some(proto::workspace_selector("default")), + workspace_scope: Some(proto::workspace_selector(workspace)), name: name.to_owned(), })) .await @@ -102,6 +61,164 @@ async fn get_sandbox(client: &mut AuthedGrpcClient, name: &str) -> proto::Sandbo .expect("Sandbox response") } +/// Stop can still be followed by driver-watch status writes. Refresh the CAS +/// version on a definite conflict, without retrying ambiguous driver failures. +async fn update_stopped_sandbox( + client: &mut AuthedGrpcClient, + updates: &mut AuthedSandboxUpdatesClient, + workspace: &str, + mut request: proto::UpdateSandboxRequest, +) -> (proto::Sandbox, proto::UpdateSandboxRequest) { + let mut sandbox_id = None; + for attempt in 0..20 { + let current = get_sandbox(client, workspace, &request.name).await; + let metadata = current.metadata.as_ref().expect("sandbox metadata"); + let id = sandbox_id.get_or_insert_with(|| metadata.id.clone()); + assert_eq!( + &metadata.id, id, + "conditional retry must not target a replacement" + ); + let status = current.status.as_ref().expect("sandbox status"); + assert_eq!(status.phase, proto::SandboxPhase::Stopped as i32); + assert!( + status + .provisioning + .as_ref() + .is_none_or(|record| !record.driver_operation_pending), + "do not retry a newly selected update over a pending operation" + ); + request.expected_resource_version = metadata.resource_version; + if attempt > 0 && !request.request_id.is_empty() { + // A changed version is a new request payload, not a replay. + request.request_id = request_id(); + } + match updates.update_sandbox(rpc(request.clone())).await { + Ok(response) => { + return ( + response.into_inner().sandbox.expect("updated Sandbox"), + request, + ); + } + Err(error) => { + let conflict = error.code() == tonic::Code::Aborted + && testkit::sdk::SdkError::from_status(error.clone()) + .error_details() + .is_some_and(|details| { + details.error_info().is_some_and(|info| { + info.domain == "openshell.nvidia.com" + && info.reason == "RESOURCE_VERSION_CONFLICT" + }) + }); + assert!( + conflict && attempt < 19, + "update stopped sandbox: {error:?}" + ); + eprintln!( + "refreshing sandbox {} after version conflict: {error}", + request.name + ); + tokio::time::sleep(Duration::from_millis(100)).await; + } + } + } + unreachable!("final conflict fails the test") +} + +async fn kubectl_mutation(args: &[&str]) -> std::process::Output { + let namespace = std::env::var("OPENSHELL_E2E_SANDBOX_NAMESPACE").expect("test namespace"); + let context = std::env::var("OPENSHELL_E2E_KUBE_CONTEXT_ACTIVE").expect("test context"); + tokio::process::Command::new("kubectl") + .args([ + "--context", + &context, + "--namespace", + &namespace, + "--request-timeout=30s", + ]) + .args(args) + .kill_on_drop(true) + .output() + .await + .expect("kubectl mutation") +} + +/// Exercise real API-server immutable UID validation independently of the +/// resourceVersion condition, after deleting and recreating the named resource. +async fn assert_recreated_resource_rejects_stale_patch(template: &Value, name: &str) { + use std::io::Write as _; + let resource = serde_json::json!({ + "apiVersion": template["apiVersion"], "kind": "Sandbox", + "metadata": {"name": name}, "spec": template["spec"], + }); + let mut file = tempfile::NamedTempFile::new().expect("test manifest"); + file.write_all(serde_json::to_string(&resource).unwrap().as_bytes()) + .unwrap(); + let path = file.path().to_str().unwrap(); + let create = kubectl_mutation(&["create", "-f", path, "-o", "json"]).await; + assert!( + create.status.success(), + "{}", + String::from_utf8_lossy(&create.stderr) + ); + let original: Value = serde_json::from_slice(&create.stdout).unwrap(); + let delete = kubectl_mutation(&[ + "delete", + "sandboxes.agents.x-k8s.io", + name, + "--wait=true", + "--timeout=60s", + ]) + .await; + assert!( + delete.status.success(), + "{}", + String::from_utf8_lossy(&delete.stderr) + ); + let create = kubectl_mutation(&["create", "-f", path, "-o", "json"]).await; + assert!( + create.status.success(), + "{}", + String::from_utf8_lossy(&create.stderr) + ); + let replacement: Value = serde_json::from_slice(&create.stdout).unwrap(); + let patch = serde_json::json!({"metadata": { + "uid": original["metadata"]["uid"], + "annotations": {"example.com/stale-patch": "must-not-apply"}, + }}) + .to_string(); + let rejected = kubectl_mutation(&[ + "patch", + "sandboxes.agents.x-k8s.io", + name, + "--type=merge", + "-p", + &patch, + ]) + .await; + let after = kubectl_get("sandboxes.agents.x-k8s.io", &[name]).await; + let cleanup = kubectl_mutation(&[ + "delete", + "sandboxes.agents.x-k8s.io", + name, + "--wait=true", + "--timeout=60s", + ]) + .await; + assert!( + cleanup.status.success(), + "{}", + String::from_utf8_lossy(&cleanup.stderr) + ); + assert_ne!(original["metadata"]["uid"], replacement["metadata"]["uid"]); + assert!(!rejected.status.success(), "stale UID patch must fail"); + assert!( + String::from_utf8_lossy(&rejected.stderr).contains("metadata.uid"), + "{}", + String::from_utf8_lossy(&rejected.stderr) + ); + assert!(after["metadata"]["annotations"]["example.com/stale-patch"].is_null()); +} + async fn kubectl_get(resource: &str, selector: &[&str]) -> Value { let namespace = std::env::var("OPENSHELL_E2E_SANDBOX_NAMESPACE") .expect("Kubernetes E2E wrapper must provide the sandbox namespace"); @@ -231,12 +348,13 @@ fn assert_identity_retained(before: &proto::Sandbox, after: &proto::Sandbox) { assert_eq!(after.host_key_fingerprint, before.host_key_fingerprint); } -async fn assert_base_release(sandbox: &SandboxGuard, release: &str) { +async fn assert_base_release(sandbox: &Sandbox, release: &str) { assert!( sandbox - .exec(&["cat", "/etc/alpine-release"]) + .exec(["cat", "/etc/alpine-release"]) .await .expect("base image release") + .stdout .trim() .starts_with(release) ); @@ -262,7 +380,7 @@ fn assert_update_completed(original: &proto::Sandbox, updated: &proto::Sandbox) .as_ref() .expect("template") .image, - UPDATED_IMAGE + *UPDATED_IMAGE ); } @@ -338,17 +456,24 @@ async fn assert_image_update_supported(client: &mut AuthedGrpcClient) { })); } -#[tokio::test] -async fn image_update_retains_workspace_and_identity() { - let gateway = gateway_client().await; +/// Updating a stopped sandbox retains storage and identity and changes the next workload. +#[testkit::test] +async fn image_update_retains_workspace_and_identity(cx: &mut Context) -> testkit::Result { + let selected = testkit::Gateway::from_env()?; + let workspace = selected.workspace.as_str(); + let gateway = selected.connect().await?; let mut client = gateway.raw_grpc(); let mut image_client = gateway.raw_sandbox_updates(); assert_image_update_supported(&mut client).await; - let mut sandbox = SandboxGuard::create(&["--from", ORIGINAL_IMAGE, "--no-auto-providers"]) - .await - .expect("create original Alpine sandbox"); - let original = get_sandbox(&mut client, &sandbox.name).await; + let sandbox = cx + // The testkit's unique prefix leaves five characters of the name limit. + .sandbox("image") + .spec(|spec| spec.image = Some(ORIGINAL_IMAGE.to_string())) + .create() + .await?; + sandbox.wait_ready().await?; + let original = get_sandbox(&mut client, workspace, sandbox.name()).await; let id = &original.metadata.as_ref().expect("sandbox metadata").id; assert!(!id.is_empty(), "sandbox must have a canonical ID"); assert!( @@ -358,7 +483,7 @@ async fn image_update_retains_workspace_and_identity() { assert_base_release(&sandbox, "3.21.").await; let sentinel = request_id(); sandbox - .exec(&[ + .exec([ "sh", "-c", &format!("printf '%s' '{sentinel}' > '{SENTINEL_PATH}'"), @@ -369,9 +494,9 @@ async fn image_update_retains_workspace_and_identity() { let original_claims = claim_uids(&before).await; let running_update = proto::UpdateSandboxRequest { - workspace_scope: Some(proto::workspace_selector("default")), - name: sandbox.name.clone(), - image: Some(UPDATED_IMAGE.to_owned()), + workspace_scope: Some(proto::workspace_selector(workspace)), + name: sandbox.name().to_owned(), + image: Some(UPDATED_IMAGE.to_string()), expected_resource_version: original .metadata .as_ref() @@ -385,14 +510,10 @@ async fn image_update_retains_workspace_and_identity() { .await .expect_err("running update must be rejected"); assert_eq!(error.code(), tonic::Code::FailedPrecondition); - assert_resource_retained(&before, &sandbox_resource(id).await, ORIGINAL_IMAGE); + assert_resource_retained(&before, &sandbox_resource(id).await, &ORIGINAL_IMAGE); - let (output, code) = run_cli(&["sandbox", "stop", &sandbox.name]).await; - assert_eq!(code, 0, "sandbox stop: {output}"); - wait_for_sandbox_phase(&sandbox.name, "Stopped", Duration::from_secs(120)) - .await - .expect("sandbox stopped"); - let stopped = get_sandbox(&mut client, &sandbox.name).await; + sandbox.stop().await?; + let stopped = get_sandbox(&mut client, workspace, sandbox.name()).await; let update = proto::UpdateSandboxRequest { expected_resource_version: stopped .metadata @@ -410,33 +531,30 @@ async fn image_update_retains_workspace_and_identity() { annotations: Some(proto::SandboxMapUpdate { values: std::collections::HashMap::from([("example.com/revision".into(), "2".into())]) }), ..running_update }; - let updated = image_client - .update_sandbox(rpc(update.clone())) - .await - .expect("update stopped sandbox image") - .into_inner() - .sandbox - .expect("updated Sandbox"); + let (updated, update) = + update_stopped_sandbox(&mut client, &mut image_client, workspace, update).await; assert_update_completed(&original, &updated); - assert_resource_retained(&before, &sandbox_resource(id).await, UPDATED_IMAGE); + assert_resource_retained(&before, &sandbox_resource(id).await, &UPDATED_IMAGE); assert_replay(&mut image_client, update, &updated).await; + assert_recreated_resource_rejects_stale_patch( + &sandbox_resource(id).await, + &cx.name("uid-race"), + ) + .await; - let (output, code) = run_cli(&["sandbox", "start", &sandbox.name]).await; - assert_eq!(code, 0, "sandbox start: {output}"); - wait_for_sandbox_phase(&sandbox.name, "Ready", Duration::from_secs(180)) - .await - .expect("updated sandbox ready"); + sandbox.start().await?; assert_base_release(&sandbox, "3.22.").await; assert_eq!( sandbox - .exec(&["cat", "/sandbox/harness/configuration"]) + .exec(["cat", "/sandbox/harness/configuration"]) .await .expect("updated command and environment ran on start") + .stdout .trim(), "updated:new-argument" ); - let observed = get_sandbox(&mut client, &sandbox.name).await; + let observed = get_sandbox(&mut client, workspace, sandbox.name()).await; assert_eq!( observed .metadata @@ -459,20 +577,130 @@ async fn image_update_retains_workspace_and_identity() { ); assert_eq!( sandbox - .exec(&["cat", SENTINEL_PATH]) + .exec(["cat", SENTINEL_PATH]) .await .expect("retained workspace sentinel") + .stdout .trim(), sentinel ); - let current = get_sandbox(&mut client, &sandbox.name).await; + let current = get_sandbox(&mut client, workspace, sandbox.name()).await; assert_identity_retained(&original, ¤t); let after = sandbox_resource(id).await; - assert_resource_retained(&before, &after, UPDATED_IMAGE); + assert_resource_retained(&before, &after, &UPDATED_IMAGE); assert_eq!( claim_uids(&after).await, original_claims, "all mounted PVC names and UIDs must survive image replacement" ); - sandbox.cleanup().await; + sandbox.delete().await?; + Ok(()) +} + +/// A terminal command can be stopped and repaired without replacing its storage. +#[testkit::test] +async fn terminal_workload_can_stop_update_and_restart(cx: &mut Context) -> testkit::Result { + let selected = testkit::Gateway::from_env()?; + let workspace = selected.workspace.as_str(); + let gateway = selected.connect().await?; + let mut client = gateway.raw_grpc(); + let mut updates = gateway.raw_sandbox_updates(); + let sandbox = cx + .sandbox("term") + .restart_policy(testkit::sdk::SandboxRestartPolicy::Never) + .spec(|spec| spec.image = Some(ORIGINAL_IMAGE.to_string())) + .create() + .await?; + sandbox.wait_ready().await?; + let original = get_sandbox(&mut client, workspace, sandbox.name()).await; + let before = sandbox_resource(sandbox.id()).await; + let original_claims = claim_uids(&before).await; + let sentinel = request_id(); + sandbox + .exec([ + "sh", + "-c", + &format!("printf '%s' '{sentinel}' > '{SENTINEL_PATH}'"), + ]) + .await?; + + for exit_code in [0, 1] { + sandbox.stop().await?; + update_stopped_sandbox( + &mut client, + &mut updates, + workspace, + proto::UpdateSandboxRequest { + workspace_scope: Some(proto::workspace_selector(workspace)), + name: sandbox.name().to_owned(), + command: Some(proto::SandboxCommandUpdate { + argv: vec!["/bin/sh".into(), "-c".into(), format!("exit {exit_code}")], + }), + ..Default::default() + }, + ) + .await; + // Do not wait for Ready: the command may exit before Ready is observed. + client + .start_sandbox(rpc(proto::StartSandboxRequest { + workspace_scope: Some(proto::workspace_selector(workspace)), + name: sandbox.name().to_owned(), + ..Default::default() + })) + .await + .expect("start terminal command"); + sandbox.wait_finished().await?; + let terminal = get_sandbox(&mut client, workspace, sandbox.name()).await; + let status = terminal.status.as_ref().unwrap(); + assert_eq!( + status.phase, + if exit_code == 0 { + proto::SandboxPhase::Completed + } else { + proto::SandboxPhase::Error + } as i32 + ); + assert_eq!(status.exit_code, Some(exit_code)); + assert!(status.conditions.iter().any(|condition| condition.reason + == if exit_code == 0 { + "MainProcessCompleted" + } else { + "MainProcessFailed" + })); + + sandbox.stop().await?; + let stopped = get_sandbox(&mut client, workspace, sandbox.name()).await; + assert_eq!( + stopped.status.as_ref().unwrap().phase, + proto::SandboxPhase::Stopped as i32 + ); + assert_eq!(stopped.status.as_ref().unwrap().exit_code, Some(exit_code)); + update_stopped_sandbox( + &mut client, + &mut updates, + workspace, + proto::UpdateSandboxRequest { + workspace_scope: Some(proto::workspace_selector(workspace)), + name: sandbox.name().to_owned(), + command: Some(proto::SandboxCommandUpdate { + argv: vec!["sleep".into(), "86400".into()], + }), + ..Default::default() + }, + ) + .await; + sandbox.start().await?; + let repaired = get_sandbox(&mut client, workspace, sandbox.name()).await; + assert_identity_retained(&original, &repaired); + assert_eq!(repaired.status.as_ref().unwrap().exit_code, None); + assert_eq!( + sandbox.exec(["cat", SENTINEL_PATH]).await?.stdout.trim(), + sentinel + ); + let after = sandbox_resource(sandbox.id()).await; + assert_resource_retained(&before, &after, &ORIGINAL_IMAGE); + assert_eq!(claim_uids(&after).await, original_claims); + } + sandbox.delete().await?; + Ok(()) } From 4030be5e3db8e4dcb00c4ddbc17b2615c335b512 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 28 Oct 2026 16:42:53 +0000 Subject: [PATCH 11/23] perf(server): index pending sandbox updates for recovery Signed-off-by: Gordon Sim --- crates/openshell-server/README.md | 9 +- .../009_add_pending_sandbox_updates_index.sql | 3 + .../009_add_pending_sandbox_updates_index.sql | 3 + .../src/compute/image_update.rs | 99 +++++++- .../src/persistence/sandbox_image.rs | 235 +++++++++++++++++- 5 files changed, 331 insertions(+), 18 deletions(-) create mode 100644 crates/openshell-server/migrations/postgres/009_add_pending_sandbox_updates_index.sql create mode 100644 crates/openshell-server/migrations/sqlite/009_add_pending_sandbox_updates_index.sql diff --git a/crates/openshell-server/README.md b/crates/openshell-server/README.md index cc5dc3d10b..3ffc2b1712 100644 --- a/crates/openshell-server/README.md +++ b/crates/openshell-server/README.md @@ -139,9 +139,12 @@ the label index without invoking a driver. New updates require operator activation and compatible gateway membership. Accepted updates recover from private durable intent at startup and in periodic -reconciliation, including when activation is subsequently disabled. An authorized -`UpdateSandbox` with no selected fields and the current resource version resumes -the stored intent without reconstructing its selections. Completion retains the +reconciliation, including when activation is subsequently disabled. Recovery +pages through a partial database index of pending private update records instead +of scanning sandboxes or completed receipts. Acceptance and completion maintain +the indexed status in the same transaction as the intent and lifecycle interlock. +An authorized `UpdateSandbox` with no selected fields and the current resource +version resumes the stored intent without reconstructing its selections. Completion retains the exact operation receipt for idempotent completion across replicas; a newer update invalidates it. Ambiguous results retain the baseline provisioning interlock. Explicit deletion can supersede a pending update: the driver only patches the diff --git a/crates/openshell-server/migrations/postgres/009_add_pending_sandbox_updates_index.sql b/crates/openshell-server/migrations/postgres/009_add_pending_sandbox_updates_index.sql new file mode 100644 index 0000000000..bdd068f86d --- /dev/null +++ b/crates/openshell-server/migrations/postgres/009_add_pending_sandbox_updates_index.sql @@ -0,0 +1,3 @@ +CREATE INDEX IF NOT EXISTS sandbox_pending_updates_idx + ON objects (object_type, id) + WHERE object_type = 'sandbox_image_state' AND status = 'pending'; diff --git a/crates/openshell-server/migrations/sqlite/009_add_pending_sandbox_updates_index.sql b/crates/openshell-server/migrations/sqlite/009_add_pending_sandbox_updates_index.sql new file mode 100644 index 0000000000..bdd068f86d --- /dev/null +++ b/crates/openshell-server/migrations/sqlite/009_add_pending_sandbox_updates_index.sql @@ -0,0 +1,3 @@ +CREATE INDEX IF NOT EXISTS sandbox_pending_updates_idx + ON objects (object_type, id) + WHERE object_type = 'sandbox_image_state' AND status = 'pending'; diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs index 6a7dc83b33..d5e153b393 100644 --- a/crates/openshell-server/src/compute/image_update.rs +++ b/crates/openshell-server/src/compute/image_update.rs @@ -13,6 +13,8 @@ use openshell_core::{GetResourceVersion, ObjectId, ObjectName}; use tonic::{Request, Status}; use tracing::info; +const UPDATE_RECOVERY_PAGE_SIZE: u32 = 128; + impl ComputeRuntime { pub(crate) fn with_sandbox_updates(mut self, enabled: bool) -> Self { self.sandbox_updates_enabled = enabled; @@ -349,31 +351,54 @@ impl ComputeRuntime { } pub(super) async fn recover_pending_sandbox_updates(&self) -> Result<(), String> { - use futures::StreamExt as _; let Ok(permit) = self.update_recovery_sweep.clone().try_acquire_owned() else { return Ok(()); }; let ids = self - .list_persisted_sandbox_ids("sandbox update recovery") - .await?; + .store + .list_pending_sandbox_update_ids(None, UPDATE_RECOVERY_PAGE_SIZE) + .await + .map_err(|error| format!("list pending sandbox updates: {error}"))?; + if ids.is_empty() { + return Ok(()); + } let runtime = self.clone(); // Recovery must not hold readiness or unrelated reconciliation hostage // to a slow remote driver. One bounded sweep per runtime, at most eight // operations in flight, with the normal per-sandbox lifecycle gate. tokio::spawn(async move { let _permit = permit; + if let Err(error) = runtime.recover_pending_sandbox_update_pages(ids).await { + tracing::warn!(%error, "Sandbox update recovery sweep failed"); + } + }); + Ok(()) + } + + async fn recover_pending_sandbox_update_pages( + &self, + mut ids: Vec, + ) -> Result<(), String> { + use futures::StreamExt as _; + while let Some(after) = ids.last().cloned() { futures::stream::iter(ids) .for_each_concurrent(8, |id| { - let runtime = runtime.clone(); - async move { - if let Err(error) = runtime.recover_one_sandbox_update(&id).await { + // Each sandbox owns independent locks even though these + // futures are polled concurrently in the same Tokio task. + crate::persistence::lock_order::branch(async move { + if let Err(error) = self.recover_one_sandbox_update(&id).await { tracing::warn!(sandbox_id = %id, %error, "Sandbox update remains pending; recovery will retry"); } - } + }) }) .await; - }); + ids = self + .store + .list_pending_sandbox_update_ids(Some(&after), UPDATE_RECOVERY_PAGE_SIZE) + .await + .map_err(|error| format!("list pending sandbox updates: {error}"))?; + } Ok(()) } @@ -561,6 +586,64 @@ mod tests { .collect() } + #[tokio::test] + async fn recovery_drains_multiple_pending_pages_with_updates_disabled() { + let (mut runtime, driver, original) = fixture(true).await; + runtime.sandbox_updates_enabled = false; + let mut expected_ids = Vec::new(); + for index in 0..129 { + let id = format!("pending-{index:03}"); + let mut sandbox = original.clone(); + let metadata = sandbox.metadata.as_mut().unwrap(); + metadata.id.clone_from(&id); + metadata.name.clone_from(&id); + runtime.store.put_message(&sandbox).await.unwrap(); + let sandbox = runtime + .store + .get_message::(&id) + .await + .unwrap() + .unwrap(); + runtime + .store + .begin_sandbox_image_update( + &id, + sandbox.get_resource_version(), + 0, + &SandboxImageUpdate { + operation_id: format!("operation-{index}"), + previous_image: "example/workload:old".into(), + image: "example/workload:new".into(), + revision: 1, + ..Default::default() + }, + ) + .await + .unwrap(); + expected_ids.push(id); + } + runtime.recover_pending_sandbox_updates().await.unwrap(); + drop(runtime.update_recovery_sweep.acquire().await.unwrap()); + let mut recovered_ids: Vec<_> = image_calls(&driver) + .into_iter() + .map(|call| call.sandbox_id) + .collect(); + recovered_ids.sort(); + assert_eq!(recovered_ids, expected_ids); + assert!( + runtime + .store + .list_pending_sandbox_update_ids(None, 128) + .await + .unwrap() + .is_empty() + ); + // A subsequent empty sweep must not revisit completed updates. + runtime.recover_pending_sandbox_updates().await.unwrap(); + drop(runtime.update_recovery_sweep.acquire().await.unwrap()); + assert_eq!(image_calls(&driver).len(), expected_ids.len()); + } + #[tokio::test] async fn startup_does_not_wait_for_a_blocked_update_driver() { use std::time::Duration; diff --git a/crates/openshell-server/src/persistence/sandbox_image.rs b/crates/openshell-server/src/persistence/sandbox_image.rs index 9e3ef32fb1..033af81294 100644 --- a/crates/openshell-server/src/persistence/sandbox_image.rs +++ b/crates/openshell-server/src/persistence/sandbox_image.rs @@ -15,9 +15,10 @@ use prost::Message; use sqlx::{Postgres, Sqlite, Transaction}; const IMAGE_STATE_OBJECT_TYPE: &str = "sandbox_image_state"; +const IMAGE_STATE_ID_PREFIX: &str = "sandbox-image-state:"; fn state_id(sandbox_id: &str) -> String { - format!("sandbox-image-state:{sandbox_id}") + format!("{IMAGE_STATE_ID_PREFIX}{sandbox_id}") } fn conflict(current_resource_version: Option) -> PersistenceError { @@ -304,6 +305,52 @@ fn project_complete( } impl Store { + /// Discover only pending updates through the partial index, without reading + /// sandbox records or completed receipts. The cursor is a sandbox ID from + /// the preceding page; callers must recheck current intent before recovery. + pub(crate) async fn list_pending_sandbox_update_ids( + &self, + after: Option<&str>, + limit: u32, + ) -> PersistenceResult> { + let after = after.map_or_else(String::new, state_id); + let ids = match self { + Self::Sqlite(store) => { + sqlx::query_scalar::<_, String>( + "SELECT id FROM objects +WHERE object_type = 'sandbox_image_state' AND status = 'pending' AND id > ?1 +ORDER BY id LIMIT ?2", + ) + .bind(&after) + .bind(i64::from(limit)) + .fetch_all(&store.pool) + .await + } + Self::Postgres(store) => { + sqlx::query_scalar::<_, String>( + "SELECT id FROM objects +WHERE object_type = 'sandbox_image_state' AND status = 'pending' AND id > $1 +ORDER BY id LIMIT $2", + ) + .bind(&after) + .bind(i64::from(limit)) + .fetch_all(&store.pool) + .await + } + } + .map_err(|error| map_db_error(&error))?; + ids.into_iter() + .map(|id| { + id.strip_prefix(IMAGE_STATE_ID_PREFIX) + .filter(|sandbox_id| !sandbox_id.is_empty()) + .map(str::to_owned) + .ok_or_else(|| { + PersistenceError::Database("invalid sandbox image state identity".into()) + }) + }) + .collect() + } + /// Remove private image state when its owning sandbox is reclaimed. pub(crate) async fn delete_sandbox_image_state( &self, @@ -518,13 +565,21 @@ WHERE object_type = 'sandbox' AND id = $1 AND resource_version = $4", let id = state_id(sandbox_id); let state_payload = state.encode_to_vec(); + // Keep the discovery index in the same transaction as the intent and + // public lifecycle interlock. Completed receipts remain stored but are + // excluded from recovery scans. + let state_status = if state.pending.is_some() { + "pending" + } else { + "completed" + }; let affected = match self { Self::Sqlite(tx) => sqlx::query( r#"INSERT INTO "objects" ( - "object_type", "id", "name", "workspace", "payload", "created_at_ms", "updated_at_ms" -) VALUES (?1, ?2, NULL, '', ?3, ?4, ?4) + "object_type", "id", "name", "workspace", "payload", "created_at_ms", "updated_at_ms", "status" +) VALUES (?1, ?2, NULL, '', ?3, ?4, ?4, ?5) ON CONFLICT ("id") DO UPDATE -SET "payload" = excluded."payload", "updated_at_ms" = excluded."updated_at_ms", +SET "payload" = excluded."payload", "updated_at_ms" = excluded."updated_at_ms", "status" = excluded."status", "resource_version" = "objects"."resource_version" + 1 WHERE "objects"."object_type" = ?1 AND "objects"."name" IS NULL AND "objects"."workspace" = ''"#, ) @@ -532,15 +587,16 @@ WHERE "objects"."object_type" = ?1 AND "objects"."name" IS NULL AND "objects"."w .bind(&id) .bind(&state_payload) .bind(now_ms) + .bind(state_status) .execute(&mut **tx) .await .map(|result| result.rows_affected()), Self::Postgres(tx) => sqlx::query( "INSERT INTO objects ( - object_type, id, name, workspace, payload, created_at_ms, updated_at_ms -) VALUES ($1, $2, NULL, '', $3, $4, $4) + object_type, id, name, workspace, payload, created_at_ms, updated_at_ms, status +) VALUES ($1, $2, NULL, '', $3, $4, $4, $5) ON CONFLICT (id) DO UPDATE -SET payload = EXCLUDED.payload, updated_at_ms = EXCLUDED.updated_at_ms, +SET payload = EXCLUDED.payload, updated_at_ms = EXCLUDED.updated_at_ms, status = EXCLUDED.status, resource_version = objects.resource_version + 1 WHERE objects.object_type = $1 AND objects.name IS NULL AND objects.workspace = ''", ) @@ -548,6 +604,7 @@ WHERE objects.object_type = $1 AND objects.name IS NULL AND objects.workspace = .bind(&id) .bind(&state_payload) .bind(now_ms) + .bind(state_status) .execute(&mut **tx) .await .map(|result| result.rows_affected()), @@ -926,6 +983,156 @@ mod tests { (store, stored) } + async fn assert_pending_update_discovery(store: &Store) { + assert!( + store + .list_pending_sandbox_update_ids(None, 2) + .await + .unwrap() + .is_empty() + ); + for id in ["d", "b", "e", "a", "c"] { + let mut original = sandbox(); + let metadata = original.metadata.as_mut().unwrap(); + metadata.id = id.into(); + metadata.name = id.into(); + store.put_message(&original).await.unwrap(); + if id == "e" { + continue; // An ordinary sandbox has no update state. + } + let original = store.get_message::(id).await.unwrap().unwrap(); + // Rejected acceptance must not add a discovery entry. + assert!( + store + .begin_sandbox_image_update(id, resource_version(&original) + 1, 0, &intent()) + .await + .is_err() + ); + store + .begin_sandbox_image_update(id, resource_version(&original), 0, &intent()) + .await + .unwrap(); + } + let completed = store + .complete_sandbox_image_update("c", &intent()) + .await + .unwrap(); + let receipt = store.get_sandbox_image_state("c").await.unwrap().unwrap(); + assert_eq!(receipt.completed, Some(intent())); + + let first = store + .list_pending_sandbox_update_ids(None, 2) + .await + .unwrap(); + assert_eq!(first, ["a", "b"]); + // Removing the first page must not shift the next page past any work. + store + .complete_sandbox_image_update("a", &intent()) + .await + .unwrap(); + store.delete_sandbox_image_state("b").await.unwrap(); + assert_eq!( + store + .list_pending_sandbox_update_ids(first.last().map(String::as_str), 2) + .await + .unwrap(), + ["d"] + ); + assert!( + store + .list_pending_sandbox_update_ids(Some("d"), 2) + .await + .unwrap() + .is_empty() + ); + + let next = StoredSandboxImageUpdate { + operation_id: "next-operation".into(), + previous_image: "new-image".into(), + image: "newer-image".into(), + revision: 2, + ..Default::default() + }; + store + .begin_sandbox_image_update("c", resource_version(&completed), 1, &next) + .await + .unwrap(); + // A stale completion must not remove the newer pending entry. + assert!( + store + .complete_sandbox_image_update("c", &intent()) + .await + .is_err() + ); + assert_eq!( + store + .list_pending_sandbox_update_ids(None, 2) + .await + .unwrap(), + ["c", "d"] + ); + store.delete_sandbox_image_state("d").await.unwrap(); + store + .complete_sandbox_image_update("c", &next) + .await + .unwrap(); + // Idempotent completion leaves the entry absent and the receipt intact. + store + .complete_sandbox_image_update("c", &next) + .await + .unwrap(); + assert!( + store + .list_pending_sandbox_update_ids(None, 2) + .await + .unwrap() + .is_empty() + ); + assert_eq!( + store + .get_sandbox_image_state("c") + .await + .unwrap() + .unwrap() + .completed, + Some(next) + ); + } + + #[tokio::test] + async fn sqlite_pending_update_discovery_tracks_transactions_and_pages() { + let store = super::super::test_store().await; + assert_pending_update_discovery(&store).await; + let Store::Sqlite(sqlite) = &store else { + unreachable!() + }; + let plan = sqlx::query_as::<_, (i64, i64, i64, String)>( + "EXPLAIN QUERY PLAN SELECT id FROM objects +WHERE object_type = 'sandbox_image_state' AND status = 'pending' AND id > ?1 +ORDER BY id LIMIT ?2", + ) + .bind("") + .bind(2_i64) + .fetch_all(&sqlite.pool) + .await + .unwrap(); + assert!( + plan.iter() + .any(|row| row.3.contains("sandbox_pending_updates_idx")), + "{plan:?}" + ); + } + + #[tokio::test] + #[ignore = "requires PostgreSQL; run mise run test:rust:postgres"] + async fn postgres_pending_update_discovery_tracks_transactions_and_pages() { + let schema = super::super::test_postgres::TestSchema::create("pending_updates").await; + let store = schema.connect_store().await; + assert_pending_update_discovery(&store).await; + store.close().await; + schema.drop_schema().await; + } + #[test] fn legacy_image_intent_decodes_without_configuration_selections() { let decoded = @@ -1277,6 +1484,13 @@ BEGIN SELECT RAISE(ABORT, 'injected image state write failure'); END", .unwrap() .is_none() ); + assert!( + store + .list_pending_sandbox_update_ids(None, 10) + .await + .unwrap() + .is_empty() + ); sqlx::query("DROP TRIGGER fail_image_insert") .execute(&sqlite.pool) .await @@ -1312,6 +1526,13 @@ BEGIN SELECT RAISE(ABORT, 'injected image state write failure'); END", store.get_sandbox_image_state("sandbox-id").await.unwrap(), pending ); + assert_eq!( + store + .list_pending_sandbox_update_ids(None, 10) + .await + .unwrap(), + ["sandbox-id"] + ); } #[tokio::test] From 1ea7e92635eba8f85ac4b3ac37cff0a01812522f Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 28 Oct 2026 16:57:46 +0000 Subject: [PATCH 12/23] docs(sandbox): clarify stop behavior when updates are disabled Signed-off-by: Gordon Sim --- docs/how-it-works/sandboxes/overview.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index 4a6aeb12c0..83ba37bc17 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -1008,7 +1008,8 @@ longer need its retained state. To change the configuration of a retained `Completed` or `Error/MainProcessFailed` sandbox, run `sandbox stop` first. Stop cleans up compute and moves the sandbox -to `Stopped`, preserving its exit code until the next start. +to `Stopped`, preserving its exit code until the next start. This stop behavior +also applies when sandbox updates are disabled. If an infrastructure failure leaves a sandbox in `Error`, fix the reported cause, then run `sandbox stop` followed by `sandbox start`. Wait for stop to succeed before starting. This retains the sandbox and its persistent workspace on backends that support restarting stopped sandboxes; it cannot recover deleted resources or storage. From c1abbb8c198bdb80a8d67dc917ee650b50c2b163 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 28 Oct 2026 17:27:29 +0000 Subject: [PATCH 13/23] fix(server): scope deletion bypass to the matching sandbox update Signed-off-by: Gordon Sim --- crates/openshell-server/README.md | 5 +- .../src/compute/image_update.rs | 213 ++++++++++++++++++ crates/openshell-server/src/compute/mod.rs | 40 ++-- .../src/persistence/sandbox_image.rs | 179 ++++++++++++++- 4 files changed, 417 insertions(+), 20 deletions(-) diff --git a/crates/openshell-server/README.md b/crates/openshell-server/README.md index 3ffc2b1712..5912d3263e 100644 --- a/crates/openshell-server/README.md +++ b/crates/openshell-server/README.md @@ -149,7 +149,10 @@ exact operation receipt for idempotent completion across replicas; a newer updat invalidates it. Ambiguous results retain the baseline provisioning interlock. Explicit deletion can supersede a pending update: the driver only patches the original immutable resource and never creates a replacement. The Deleting CAS -prevents delayed completion, and successful deletion reclaims private intent. +prevents delayed completion. Cleanup bypasses the pending-driver guard only when +the pending operation ID matches the persisted update intent. Final removal +deletes the sandbox and private intent atomically, retaining that evidence if +cleanup fails or loses a resource-version race. Metadata replacement preserves gateway-owned keys, including retention, while other user keys under OpenShell domains remain editable. Completion preserves diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs index d5e153b393..4ec5bde7a8 100644 --- a/crates/openshell-server/src/compute/image_update.rs +++ b/crates/openshell-server/src/compute/image_update.rs @@ -422,6 +422,28 @@ impl ComputeRuntime { .map_err(|_| Status::deadline_exceeded("sandbox update recovery timed out"))? } + /// Only explicit deletion of the matching update may bypass the driver + /// interlock. Deleting alone says nothing about an outstanding create/start. + pub(super) async fn pending_driver_operation_blocks_cleanup( + &self, + sandbox: &Sandbox, + ) -> Result { + if !super::provisioning_deadline::driver_operation_pending(sandbox) { + return Ok(false); + } + if sandbox.phase() != SandboxPhase::Deleting as i32 { + return Ok(true); + } + let state = self + .store + .get_sandbox_image_state(sandbox.object_id()) + .await + .map_err(|error| format!("read pending sandbox update for cleanup: {error}"))?; + Ok(state + .and_then(|state| state.pending) + .is_none_or(|intent| ensure_image_update_interlock(sandbox, &intent).is_err())) + } + pub(super) async fn ensure_no_pending_image_update( &self, sandbox: &Sandbox, @@ -496,6 +518,7 @@ mod tests { use crate::compute::{ COMPUTE_RUNTIME_IDENTITY_ANNOTATION, apply_driver_snapshot, provisioning_deadline, }; + use crate::persistence::ObjectType; use crate::sandbox_index::SandboxIndex; use crate::sandbox_watch::SandboxWatchBus; use crate::supervisor_session::SupervisorSessionRegistry; @@ -854,6 +877,196 @@ mod tests { ); } + #[tokio::test] + async fn deleting_does_not_bypass_unrelated_pending_driver_operations() { + for missing_intent in [false, true] { + let (runtime, driver, original) = fixture(true).await; + driver.set_image_update_error(Some(Code::Unavailable)); + runtime + .update_sandbox_image( + original.object_id(), + "new-image".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + let mut deleting = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + deleting.set_phase(SandboxPhase::Deleting as i32); + if missing_intent { + runtime + .store + .delete_sandbox_image_state(original.object_id()) + .await + .unwrap(); + } else { + deleting + .status + .as_mut() + .unwrap() + .provisioning + .as_mut() + .unwrap() + .driver_operation_id = "unrelated-create-or-start".into(); + } + runtime.store.put_message(&deleting).await.unwrap(); + let deleting = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + let version = deleting.get_resource_version(); + driver.clear_calls(); + + runtime + .recover_persisted_lifecycle_transitions() + .await + .unwrap(); + runtime.apply_deleted(original.object_id()).await.unwrap(); + { + let _guard = runtime.lock_sandbox_local(original.object_id()).await; + runtime + .apply_deleted_if_version_locked(&deleting, version) + .await + .unwrap(); + assert!( + !runtime + .remove_sandbox_record_if_version_locked(original.object_id(), version) + .await + .unwrap() + ); + } + let record = runtime + .store + .get(Sandbox::object_type(), original.object_id()) + .await + .unwrap() + .unwrap(); + runtime + .prune_missing_sandbox(record, i64::MAX, 0) + .await + .unwrap(); + assert_eq!( + runtime + .delete_sandbox("default", original.object_name()) + .await + .unwrap_err() + .code(), + if missing_intent { + Code::FailedPrecondition + } else { + Code::Aborted + } + ); + assert_eq!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap(), + Some(deleting) + ); + assert!(driver.calls().is_empty()); + } + } + + #[tokio::test] + async fn deleting_pending_update_can_retry_failed_record_removal() { + let (mut runtime, driver, original) = fixture(true).await; + let directory = tempfile::tempdir().unwrap(); + let database_url = format!("sqlite://{}", directory.path().join("delete.db").display()); + runtime.store = Arc::new( + crate::persistence::Store::connect(&database_url) + .await + .unwrap(), + ); + crate::ensure_default_workspace(&runtime.store) + .await + .unwrap(); + runtime.store.put_message(&original).await.unwrap(); + driver.set_image_update_error(Some(Code::Unavailable)); + runtime + .update_sandbox_image( + original.object_id(), + "new-image".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + let mut deleting = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + deleting.set_phase(SandboxPhase::Deleting as i32); + runtime.store.put_message(&deleting).await.unwrap(); + let pending = runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap(); + let pool = sqlx::SqlitePool::connect(&database_url).await.unwrap(); + sqlx::query( + "CREATE TRIGGER fail_sandbox_delete BEFORE DELETE ON objects +WHEN OLD.object_type = 'sandbox' +BEGIN SELECT RAISE(ABORT, 'injected sandbox deletion failure'); END", + ) + .execute(&pool) + .await + .unwrap(); + assert!(runtime.apply_deleted(original.object_id()).await.is_err()); + let retained = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + assert_eq!(retained.phase(), SandboxPhase::Deleting as i32); + assert_eq!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap(), + pending + ); + assert!( + !runtime + .pending_driver_operation_blocks_cleanup(&retained) + .await + .unwrap() + ); + + sqlx::query("DROP TRIGGER fail_sandbox_delete") + .execute(&pool) + .await + .unwrap(); + runtime.apply_deleted(original.object_id()).await.unwrap(); + assert!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .is_none() + ); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_none() + ); + pool.close().await; + } + #[tokio::test] async fn explicit_delete_supersedes_pending_update_without_restoring_the_driver() { let (mut runtime, driver, original) = fixture(true).await; diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index 4cfafa3b63..40b9fd65eb 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -3647,8 +3647,9 @@ impl ComputeRuntime { let mut delete_resource_version = record.resource_version; let mut sandbox = decode_sandbox_record(&record)?; - if provisioning_deadline::driver_operation_pending(&sandbox) - && sandbox.phase() != SandboxPhase::Deleting as i32 + if self + .pending_driver_operation_blocks_cleanup(&sandbox) + .await? { return Ok(false); } @@ -3675,10 +3676,11 @@ impl ComputeRuntime { return Err(error); } - match self - .store - .delete_if(Sandbox::object_type(), sandbox_id, delete_resource_version) - .await + match Box::pin( + self.store + .delete_sandbox_with_image_state_if(sandbox_id, delete_resource_version), + ) + .await { Ok(true) => { self.cleanup_removed_sandbox_state(sandbox_id); @@ -4445,8 +4447,9 @@ impl ComputeRuntime { continue; } }; - if provisioning_deadline::driver_operation_pending(&sandbox) - && sandbox.phase() != SandboxPhase::Deleting as i32 + if self + .pending_driver_operation_blocks_cleanup(&sandbox) + .await? { warn!( sandbox_id, @@ -6178,8 +6181,9 @@ impl ComputeRuntime { // Timeout cleanup can emit Deleted before an explicit stop exposes // Stopped for repair. A delayed (or repeated) event must retain that // recovery record too; explicit deletion still transitions to Deleting. - if (provisioning_deadline::driver_operation_pending(sandbox) - && sandbox.phase() != SandboxPhase::Deleting as i32) + if self + .pending_driver_operation_blocks_cleanup(sandbox) + .await? || (provisioning_deadline::timed_out(sandbox) && matches!( SandboxPhase::try_from(sandbox.phase()), @@ -6220,8 +6224,9 @@ impl ComputeRuntime { sandbox: &Sandbox, expected_resource_version: u64, ) -> Result<(), String> { - if provisioning_deadline::driver_operation_pending(sandbox) - && sandbox.phase() != SandboxPhase::Deleting as i32 + if self + .pending_driver_operation_blocks_cleanup(sandbox) + .await? { return Ok(()); } @@ -6232,10 +6237,8 @@ impl ComputeRuntime { } async fn cleanup_sandbox_owned_records(&self, sandbox: &Sandbox) -> Result<(), String> { - self.store - .delete_sandbox_image_state(sandbox.object_id()) - .await - .map_err(|error| format!("delete sandbox image state: {error}"))?; + // Keep private update intent until atomic sandbox removal: a cleanup + // failure or CAS conflict must leave evidence for the deletion retry. self.cleanup_ssh_identity(sandbox) .await .map_err(|error| error.to_string())?; @@ -6551,8 +6554,9 @@ impl ComputeRuntime { } let sandbox = decode_sandbox_record(¤t_record)?; - if provisioning_deadline::driver_operation_pending(&sandbox) - && sandbox.phase() != SandboxPhase::Deleting as i32 + if self + .pending_driver_operation_blocks_cleanup(&sandbox) + .await? { return Ok(()); } diff --git a/crates/openshell-server/src/persistence/sandbox_image.rs b/crates/openshell-server/src/persistence/sandbox_image.rs index 033af81294..386fe78136 100644 --- a/crates/openshell-server/src/persistence/sandbox_image.rs +++ b/crates/openshell-server/src/persistence/sandbox_image.rs @@ -351,7 +351,55 @@ ORDER BY id LIMIT $2", .collect() } - /// Remove private image state when its owning sandbox is reclaimed. + /// Remove a sandbox and its private update state in the same transaction. + /// Failed cleanup must retain the intent that authorizes deletion to bypass + /// the pending driver operation interlock. + pub(crate) async fn delete_sandbox_with_image_state_if( + &self, + sandbox_id: &str, + expected_resource_version: u64, + ) -> PersistenceResult { + let mut tx = ImageTransaction::begin(self).await?; + let sandbox = match tx.lock_sandbox(sandbox_id).await { + Ok(sandbox) => sandbox, + Err(PersistenceError::Conflict { + current_resource_version: None, + }) => return Ok(false), + Err(error) => return Err(error), + }; + if resource_version(&sandbox) != expected_resource_version { + return Err(conflict(Some(resource_version(&sandbox)))); + } + let image_state_id = state_id(sandbox_id); + for (object_type, id) in [ + ("sandbox", sandbox_id), + (IMAGE_STATE_OBJECT_TYPE, image_state_id.as_str()), + ] { + match &mut tx { + ImageTransaction::Sqlite(tx) => { + sqlx::query("DELETE FROM objects WHERE object_type = ?1 AND id = ?2") + .bind(object_type) + .bind(id) + .execute(&mut **tx) + .await + .map_err(|error| map_db_error(&error))?; + } + ImageTransaction::Postgres(tx) => { + sqlx::query("DELETE FROM objects WHERE object_type = $1 AND id = $2") + .bind(object_type) + .bind(id) + .execute(&mut **tx) + .await + .map_err(|error| map_db_error(&error))?; + } + } + } + tx.commit().await?; + Ok(true) + } + + /// Remove private image state independently to exercise recovery fixtures. + #[cfg(test)] pub(crate) async fn delete_sandbox_image_state( &self, sandbox_id: &str, @@ -983,6 +1031,135 @@ mod tests { (store, stored) } + async fn assert_atomic_sandbox_deletion(store: &Store) { + store.put_message(&sandbox()).await.unwrap(); + let original = store + .get_message::("sandbox-id") + .await + .unwrap() + .unwrap(); + let accepted = store + .begin_sandbox_image_update("sandbox-id", resource_version(&original), 0, &intent()) + .await + .unwrap(); + let pending = store.get_sandbox_image_state("sandbox-id").await.unwrap(); + assert!(matches!( + store + .delete_sandbox_with_image_state_if("sandbox-id", resource_version(&original)) + .await, + Err(PersistenceError::Conflict { .. }) + )); + assert_eq!( + store.get_message::("sandbox-id").await.unwrap(), + Some(accepted.clone()) + ); + assert_eq!( + store.get_sandbox_image_state("sandbox-id").await.unwrap(), + pending + ); + assert!( + store + .delete_sandbox_with_image_state_if("sandbox-id", resource_version(&accepted)) + .await + .unwrap() + ); + assert!( + store + .get_message::("sandbox-id") + .await + .unwrap() + .is_none() + ); + assert!( + store + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .is_none() + ); + assert!( + !store + .delete_sandbox_with_image_state_if("sandbox-id", resource_version(&accepted)) + .await + .unwrap() + ); + assert!( + store + .complete_sandbox_image_update("sandbox-id", &intent()) + .await + .is_err() + ); + } + + #[tokio::test] + async fn sqlite_sandbox_deletion_preserves_intent_on_conflict() { + let store = super::super::test_store().await; + assert_atomic_sandbox_deletion(&store).await; + } + + #[tokio::test] + async fn sqlite_private_state_deletion_failure_rolls_back_sandbox_removal() { + let (store, original) = fixture().await; + let accepted = store + .begin_sandbox_image_update("sandbox-id", resource_version(&original), 0, &intent()) + .await + .unwrap(); + let pending = store.get_sandbox_image_state("sandbox-id").await.unwrap(); + let Store::Sqlite(sqlite) = &store else { + panic!("expected SQLite"); + }; + sqlx::query( + "CREATE TRIGGER fail_image_delete BEFORE DELETE ON objects +WHEN OLD.object_type = 'sandbox_image_state' +BEGIN SELECT RAISE(ABORT, 'injected image state deletion failure'); END", + ) + .execute(&sqlite.pool) + .await + .unwrap(); + assert!( + store + .delete_sandbox_with_image_state_if("sandbox-id", resource_version(&accepted)) + .await + .is_err() + ); + assert_eq!( + store.get_message::("sandbox-id").await.unwrap(), + Some(accepted.clone()) + ); + assert_eq!( + store.get_sandbox_image_state("sandbox-id").await.unwrap(), + pending + ); + sqlx::query("DROP TRIGGER fail_image_delete") + .execute(&sqlite.pool) + .await + .unwrap(); + assert!( + store + .delete_sandbox_with_image_state_if("sandbox-id", resource_version(&accepted)) + .await + .unwrap() + ); + assert!( + store + .get_sandbox_image_state("sandbox-id") + .await + .unwrap() + .is_none() + ); + } + + #[tokio::test] + #[ignore = "requires PostgreSQL; run mise run test:rust:postgres"] + async fn postgres_sandbox_deletion_preserves_intent_on_conflict() { + let schema = + super::super::test_postgres::TestSchema::create("sandbox_update_deletion").await; + let store = schema.connect_store().await; + assert_atomic_sandbox_deletion(&store).await; + store.close().await; + schema.drop_schema().await; + } + async fn assert_pending_update_discovery(store: &Store) { assert!( store From d074b2d01a544595664123d10bf706a09c027e55 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 28 Oct 2026 18:18:36 +0000 Subject: [PATCH 14/23] fix(server): back off pending sandbox update recovery Signed-off-by: Gordon Sim --- crates/openshell-server/README.md | 7 +- .../src/compute/image_update.rs | 334 ++++++++++++++++-- crates/openshell-server/src/compute/mod.rs | 4 + docs/how-it-works/sandboxes/overview.mdx | 6 +- skills/debug-openshell-cluster/SKILL.md | 3 + skills/openshell-cli/SKILL.md | 4 +- 6 files changed, 327 insertions(+), 31 deletions(-) diff --git a/crates/openshell-server/README.md b/crates/openshell-server/README.md index 5912d3263e..ef7b0546b5 100644 --- a/crates/openshell-server/README.md +++ b/crates/openshell-server/README.md @@ -143,8 +143,13 @@ reconciliation, including when activation is subsequently disabled. Recovery pages through a partial database index of pending private update records instead of scanning sandboxes or completed receipts. Acceptance and completion maintain the indexed status in the same transaction as the intent and lifecycle interlock. +Each gateway keeps automatic recovery backoff in memory. Failed attempts wait +1, 2, 4, 8, then 15 minutes; each failure log includes the attempt and retry delay. +Replicas retry independently, and a gateway restart resets its backoff. A new +operation starts without delay. Completed or deleted updates are removed from +the backoff map as recovery observes them. An authorized `UpdateSandbox` with no selected fields and the current resource -version resumes the stored intent without reconstructing its selections. Completion retains the +version resumes immediately, bypassing backoff without reconstructing its selections. Completion retains the exact operation receipt for idempotent completion across replicas; a newer update invalidates it. Ambiguous results retain the baseline provisioning interlock. Explicit deletion can supersede a pending update: the driver only patches the diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs index 4ec5bde7a8..d609753bfc 100644 --- a/crates/openshell-server/src/compute/image_update.rs +++ b/crates/openshell-server/src/compute/image_update.rs @@ -14,6 +14,14 @@ use tonic::{Request, Status}; use tracing::info; const UPDATE_RECOVERY_PAGE_SIZE: u32 = 128; +const UPDATE_RECOVERY_TIMEOUT: std::time::Duration = std::time::Duration::from_mins(1); + +#[derive(Clone)] +pub(super) struct UpdateRecoveryBackoff { + operation_id: String, + attempts: u32, + next_retry: tokio::time::Instant, +} impl ComputeRuntime { pub(crate) fn with_sandbox_updates(mut self, enabled: bool) -> Self { @@ -252,6 +260,10 @@ impl ComputeRuntime { .map_err(|error| { crate::grpc::persistence_error_to_status(error, "complete sandbox image update") })?; + self.update_recovery_backoff + .lock() + .await + .remove(pending.object_id()); self.sandbox_index.update_from_sandbox(&updated); self.sandbox_watch_bus.notify(updated.object_id()); info!(sandbox_id = %updated.object_id(), operation_id = %intent.operation_id, @@ -331,25 +343,6 @@ impl ComputeRuntime { Ok(()) } - /// Recover from private durable intent, independent of new-update activation. - pub(super) async fn recover_sandbox_update(&self, sandbox: &Sandbox) -> Result { - let state = self - .store - .get_sandbox_image_state(sandbox.object_id()) - .await - .map_err(|_| Status::unavailable("cannot read pending sandbox update"))?; - let Some(intent) = state.and_then(|state| state.pending) else { - return Ok(false); - }; - if sandbox.phase() == SandboxPhase::Deleting as i32 { - return Ok(false); - } - ensure_image_update_stopped(sandbox)?; - self.ensure_configuration_update_supported()?; - self.complete_image_update(sandbox.clone(), intent).await?; - Ok(true) - } - pub(super) async fn recover_pending_sandbox_updates(&self) -> Result<(), String> { let Ok(permit) = self.update_recovery_sweep.clone().try_acquire_owned() else { return Ok(()); @@ -360,6 +353,7 @@ impl ComputeRuntime { .await .map_err(|error| format!("list pending sandbox updates: {error}"))?; if ids.is_empty() { + self.update_recovery_backoff.lock().await.clear(); return Ok(()); } let runtime = self.clone(); @@ -380,7 +374,9 @@ impl ComputeRuntime { mut ids: Vec, ) -> Result<(), String> { use futures::StreamExt as _; + let mut pending_ids = std::collections::HashSet::new(); while let Some(after) = ids.last().cloned() { + pending_ids.extend(ids.iter().cloned()); futures::stream::iter(ids) .for_each_concurrent(8, |id| { // Each sandbox owns independent locks even though these @@ -388,7 +384,7 @@ impl ComputeRuntime { crate::persistence::lock_order::branch(async move { if let Err(error) = self.recover_one_sandbox_update(&id).await { tracing::warn!(sandbox_id = %id, %error, - "Sandbox update remains pending; recovery will retry"); + "Cannot read pending sandbox update for recovery"); } }) }) @@ -399,27 +395,97 @@ impl ComputeRuntime { .await .map_err(|error| format!("list pending sandbox updates: {error}"))?; } + // Forget sandboxes completed or deleted by another replica. Only prune + // after a successful full scan, so a failed page does not reset backoff. + self.update_recovery_backoff + .lock() + .await + .retain(|id, _| pending_ids.contains(id)); Ok(()) } async fn recover_one_sandbox_update(&self, id: &str) -> Result<(), Status> { + self.recover_one_sandbox_update_at(id, tokio::time::Instant::now()) + .await + } + + async fn recover_one_sandbox_update_at( + &self, + id: &str, + now: tokio::time::Instant, + ) -> Result<(), Status> { let Some(_gate) = self.lifecycle_gates.try_lock_for(id) else { return Ok(()); }; - let recover = async { + let deadline = tokio::time::Instant::now() + UPDATE_RECOVERY_TIMEOUT; + let read = async { let sandbox = self .store .get_message::(id) .await .map_err(|_| Status::unavailable("cannot read sandbox for update recovery"))?; - if let Some(sandbox) = sandbox { - self.recover_sandbox_update(&sandbox).await?; - } + let state = self + .store + .get_sandbox_image_state(id) + .await + .map_err(|_| Status::unavailable("cannot read pending sandbox update"))?; + Ok::<_, Status>((sandbox, state.and_then(|state| state.pending))) + }; + let (Some(sandbox), Some(intent)) = tokio::time::timeout_at(deadline, read) + .await + .map_err(|_| Status::deadline_exceeded("reading pending sandbox update timed out"))?? + else { + self.update_recovery_backoff.lock().await.remove(id); + return Ok(()); + }; + if sandbox.phase() == SandboxPhase::Deleting as i32 { + self.update_recovery_backoff.lock().await.remove(id); + return Ok(()); + } + let previous = self + .update_recovery_backoff + .lock() + .await + .get(id) + .cloned() + .filter(|backoff| backoff.operation_id == intent.operation_id); + if previous + .as_ref() + .is_some_and(|backoff| backoff.next_retry > now) + { + return Ok(()); + } + let recover = async { + ensure_image_update_stopped(&sandbox)?; + self.ensure_configuration_update_supported()?; + self.complete_image_update(sandbox, intent.clone()).await?; Ok(()) }; - tokio::time::timeout(std::time::Duration::from_mins(1), recover) + let result = tokio::time::timeout_at(deadline, recover) .await - .map_err(|_| Status::deadline_exceeded("sandbox update recovery timed out"))? + .unwrap_or_else(|_| { + Err(Status::deadline_exceeded( + "sandbox update recovery timed out", + )) + }); + if let Err(error) = result { + let attempts = previous.map_or(1, |backoff| backoff.attempts.saturating_add(1)); + let delay = std::time::Duration::from_secs( + 60 * (1_u64 << attempts.saturating_sub(1).min(4)).min(15), + ); + self.update_recovery_backoff.lock().await.insert( + id.to_owned(), + UpdateRecoveryBackoff { + operation_id: intent.operation_id.clone(), + attempts, + next_retry: tokio::time::Instant::now() + delay, + }, + ); + tracing::warn!(sandbox_id = %id, operation_id = %intent.operation_id, + attempt = attempts, retry_after_secs = delay.as_secs(), %error, + "Sandbox update remains pending; recovery deferred"); + } + Ok(()) } /// Only explicit deletion of the matching update may bypass the driver @@ -752,6 +818,11 @@ mod tests { ); runtime.image_update_driver = updater; driver.set_image_update_error(None); + // Repeated scans respect this gateway's delay even after the + // driver has been repaired. + runtime.recover_pending_sandbox_updates().await.unwrap(); + drop(runtime.update_recovery_sweep.acquire().await.unwrap()); + assert_eq!(image_calls(&driver).len(), 1); let pending = runtime .store .get_message::(original.object_id()) @@ -759,8 +830,12 @@ mod tests { .unwrap() .unwrap(); if automatic { - runtime.recover_pending_sandbox_updates().await.unwrap(); - drop(runtime.update_recovery_sweep.acquire().await.unwrap()); + let next = + runtime.update_recovery_backoff.lock().await[original.object_id()].next_retry; + runtime + .recover_one_sandbox_update_at(original.object_id(), next) + .await + .unwrap(); } else { runtime .update_sandbox_configuration( @@ -787,6 +862,209 @@ mod tests { } } + #[tokio::test] + async fn failed_automatic_updates_back_off_but_explicit_resume_is_immediate() { + let (runtime, driver, original) = fixture(true).await; + driver.set_image_update_error(Some(Code::Unavailable)); + runtime + .update_sandbox_image( + original.object_id(), + "new-image".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + let pending = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + for (attempt, delay) in [ + (1, 60_000), + (2, 120_000), + (3, 240_000), + (4, 480_000), + (5, 900_000), + (6, 900_000), + ] { + let due = runtime + .update_recovery_backoff + .lock() + .await + .get(original.object_id()) + .map_or_else(tokio::time::Instant::now, |backoff| backoff.next_retry); + let before = tokio::time::Instant::now(); + runtime + .recover_one_sandbox_update_at(original.object_id(), due) + .await + .unwrap(); + let after = tokio::time::Instant::now(); + let backoff = + runtime.update_recovery_backoff.lock().await[original.object_id()].clone(); + assert_eq!(backoff.attempts, attempt); + let delay = std::time::Duration::from_millis(delay); + assert!((before + delay..=after + delay).contains(&backoff.next_retry)); + runtime + .recover_one_sandbox_update_at( + original.object_id(), + backoff.next_retry - std::time::Duration::from_millis(1), + ) + .await + .unwrap(); + assert_eq!(image_calls(&driver).len(), attempt as usize + 1); + } + driver.set_image_update_error(None); + // Scheduling never changes the public version; a fresh version is not + // required merely because another automatic attempt failed. + runtime + .update_sandbox_configuration( + original.object_id(), + &openshell_core::proto::UpdateSandboxRequest { + expected_resource_version: pending.get_resource_version(), + ..Default::default() + }, + ) + .await + .unwrap(); + let state = runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap(); + assert!(state.pending.is_none()); + assert!(runtime.update_recovery_backoff.lock().await.is_empty()); + } + + #[tokio::test] + async fn recovery_backoff_is_local_and_does_not_delay_a_new_operation() { + let (runtime, driver, original) = fixture(true).await; + driver.set_image_update_error(Some(Code::Unavailable)); + runtime + .update_sandbox_image( + original.object_id(), + "new-image".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + let state = runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap(); + runtime + .recover_one_sandbox_update(original.object_id()) + .await + .unwrap(); + runtime + .clone() + .recover_one_sandbox_update(original.object_id()) + .await + .unwrap(); + assert_eq!(image_calls(&driver).len(), 2); + assert_eq!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap(), + state + ); + + // A fresh runtime (restart or another replica) has no backoff, even + // though it reads the same durable pending intent. + let mut restarted = runtime.clone(); + restarted.update_recovery_backoff = Arc::default(); + driver.set_image_update_error(None); + restarted + .recover_one_sandbox_update(original.object_id()) + .await + .unwrap(); + assert_eq!(image_calls(&driver).len(), 3); + assert!(!runtime.update_recovery_backoff.lock().await.is_empty()); + + let completed = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + driver.set_image_update_error(Some(Code::Unavailable)); + restarted + .update_sandbox_image( + original.object_id(), + "third-image".into(), + completed.get_resource_version(), + ) + .await + .unwrap_err(); + // The original runtime still remembers the previous operation's delay, + // but the new operation must be eligible immediately. + runtime + .recover_one_sandbox_update(original.object_id()) + .await + .unwrap(); + assert_eq!(image_calls(&driver).len(), 5); + assert_eq!( + runtime.update_recovery_backoff.lock().await[original.object_id()].attempts, + 1 + ); + + driver.set_image_update_error(None); + restarted + .recover_one_sandbox_update(original.object_id()) + .await + .unwrap(); + runtime.recover_pending_sandbox_updates().await.unwrap(); + assert!(runtime.update_recovery_backoff.lock().await.is_empty()); + } + + #[tokio::test] + async fn timed_out_automatic_update_retains_intent_and_defers_recovery() { + let (runtime, driver, original) = fixture(true).await; + driver.set_image_update_error(Some(Code::Unavailable)); + runtime + .update_sandbox_image( + original.object_id(), + "new-image".into(), + original.get_resource_version(), + ) + .await + .unwrap_err(); + driver.set_image_update_error(None); + let (entered, release) = driver.pause_image_updates(); + runtime.recover_pending_sandbox_updates().await.unwrap(); + entered.notified().await; + tokio::time::pause(); + tokio::time::advance(UPDATE_RECOVERY_TIMEOUT).await; + tokio::task::yield_now().await; + tokio::time::resume(); + drop(runtime.update_recovery_sweep.acquire().await.unwrap()); + let state = runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap(); + assert!(state.pending.is_some()); + let backoff = runtime.update_recovery_backoff.lock().await[original.object_id()].clone(); + assert_eq!(backoff.attempts, 1); + assert!(backoff.next_retry > tokio::time::Instant::now()); + runtime.recover_pending_sandbox_updates().await.unwrap(); + drop(runtime.update_recovery_sweep.acquire().await.unwrap()); + // The fake records calls only after the pause, so the timed-out call + // has not reached its recording point. No second attempt may enter. + assert_eq!(image_calls(&driver).len(), 1); + assert!( + tokio::time::timeout(std::time::Duration::from_millis(10), entered.notified()) + .await + .is_err() + ); + release.add_permits(1); + } + #[tokio::test] async fn metadata_only_update_preserves_retention_and_needs_no_driver_capability() { use openshell_core::proto::{SandboxMapUpdate, UpdateSandboxRequest}; diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index 40b9fd65eb..af2c4acd94 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -918,6 +918,7 @@ pub struct ComputeRuntime { image_preparation_timeout_seconds: u32, sandbox_updates_enabled: bool, update_recovery_sweep: Arc, + update_recovery_backoff: Arc>>, store: Arc, sandbox_index: SandboxIndex, sandbox_watch_bus: SandboxWatchBus, @@ -1037,6 +1038,7 @@ impl ComputeRuntime { image_preparation_timeout_seconds: 1800, sandbox_updates_enabled: false, update_recovery_sweep: Arc::new(tokio::sync::Semaphore::new(1)), + update_recovery_backoff: Arc::default(), store, sandbox_index, sandbox_watch_bus, @@ -8524,6 +8526,7 @@ pub fn new_test_runtime_with_driver( image_preparation_timeout_seconds: 1800, sandbox_updates_enabled: false, update_recovery_sweep: Arc::new(tokio::sync::Semaphore::new(1)), + update_recovery_backoff: Arc::default(), store, sandbox_index: SandboxIndex::new(), sandbox_watch_bus: SandboxWatchBus::new(), @@ -9726,6 +9729,7 @@ mod tests { image_preparation_timeout_seconds: 1800, sandbox_updates_enabled: false, update_recovery_sweep: Arc::new(Semaphore::new(1)), + update_recovery_backoff: Arc::default(), store, sandbox_index: SandboxIndex::new(), sandbox_watch_bus: SandboxWatchBus::new(), diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index 83ba37bc17..7f81c43d85 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -1098,7 +1098,11 @@ conditional request. An update failure or disconnected response can leave a pending operation, even when `sandbox.spec.template.image` already names the target image. Start, stop, and provisioning retry remain blocked until reconciliation succeeds. The gateway retries accepted updates at startup and periodically, even -if new updates are disabled. If the driver is unavailable or no longer supports +if new updates are disabled. Failed automatic attempts wait 1, 2, 4, 8, then +15 minutes before another attempt becomes eligible. Recovery continues at the +15-minute limit; periodic scans can add up to a minute to the wait. Each gateway +retries independently, and restarting a gateway resets its retry delay. +If the driver is unavailable or no longer supports updates, restore a compatible driver. Explicit deletion can reclaim a sandbox whose update cannot complete; deletion also removes its stored workspace. diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index bdc21e2434..a550c79922 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -1462,6 +1462,9 @@ are preserved. Membership expiry does not prove a gateway has stopped. Follow th [activation checklist](https://docs.nvidia.com/openshell/latest/kubernetes/high-availability#activate-sandbox-updates). The gateway retries accepted updates automatically, even with new updates disabled. +Repeated automatic failures back off up to 15 minutes per gateway. Replicas retry +independently, and restarting a gateway resets its delay. Recovery warnings include +the attempt count and retry delay. To resume immediately, read the sandbox resource version and call `UpdateSandbox` with that version and no selected fields. Restore a compatible driver if recovery reports missing support. Start, stop, and provisioning retry retain the barrier; diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index 909656aa3d..b91f37afe4 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -591,7 +591,9 @@ cleanup completion and settlement of the original driver operation, then run timeout diagnostic and storage and does not bypass pending cleanup. An operation-pending error blocks start, stop, and provisioning retry. The gateway -retries automatically even when new updates are disabled. To resume immediately, +retries automatically even when new updates are disabled. Repeated automatic +failures back off up to 15 minutes per gateway; restarting a gateway resets the delay. +To resume immediately, read a fresh resource version and call `UpdateSandbox` with no selected fields; the gateway loads the stored targets. Use a new request ID or no ID for this explicit resume. An unresolved original ID returns uncertainty, and its payload From a682fa17eb999eb363578d6ab226ad67d27f20c5 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 28 Oct 2026 18:35:18 +0000 Subject: [PATCH 15/23] ci: restore combined-chart Kubernetes e2e coverage Signed-off-by: Gordon Sim --- .agents/skills/helm-dev-environment/SKILL.md | 4 ++-- .github/workflows/e2e-kubernetes-test.yml | 2 -- e2e/with-kube-gateway.sh | 14 -------------- tasks/test.toml | 4 ++-- 4 files changed, 4 insertions(+), 20 deletions(-) diff --git a/.agents/skills/helm-dev-environment/SKILL.md b/.agents/skills/helm-dev-environment/SKILL.md index ee01e683a7..ee387308f5 100644 --- a/.agents/skills/helm-dev-environment/SKILL.md +++ b/.agents/skills/helm-dev-environment/SKILL.md @@ -638,8 +638,8 @@ for dependencies still declared in `Chart.yaml`. ## Sandbox update regression lane Run `mise run e2e:kubernetes:updates` for the testkit update suite against both -supported Agent Sandbox APIs with `workspaceResources.enabled=false` and the -separate workspace chart. It verifies stopped-only updates, retained CR/PVC +supported Agent Sandbox APIs with the combined Helm chart and its bundled +workspace resources. It verifies stopped-only updates, retained CR/PVC identity and contents, command/environment changes, and request replay. `OPENSHELL_E2E_UPDATE_ORIGINAL_IMAGE` and `OPENSHELL_E2E_UPDATE_TARGET_IMAGE` can select mirrored Alpine 3.21 and 3.22 manifests. Defaults use the public registry diff --git a/.github/workflows/e2e-kubernetes-test.yml b/.github/workflows/e2e-kubernetes-test.yml index 706feb050c..cf6eb07b2d 100644 --- a/.github/workflows/e2e-kubernetes-test.yml +++ b/.github/workflows/e2e-kubernetes-test.yml @@ -137,8 +137,6 @@ jobs: OPENSHELL_E2E_KUBE_EXTRA_VALUES: ${{ inputs.extra-helm-values }} OPENSHELL_E2E_KUBE_EXTERNAL_POSTGRES_SECRET: ${{ inputs.external-postgres-secret }} OPENSHELL_E2E_KUBE_TEST: ${{ inputs.test-name }} - # Default shared-mode runs exercise the independently installed workspace Role. - OPENSHELL_E2E_KUBE_SPLIT_WORKSPACE: ${{ inputs.e2e-task == 'e2e:kubernetes' && inputs.test-name == '' && inputs.extra-helm-values == '' && '1' || '0' }} OPENSHELL_E2E_KUBERNETES_FEATURES: ${{ inputs.kubernetes-features }} OPENSHELL_E2E_KUBE_USE_ENVOY: ${{ inputs.use-envoy-gateway && '1' || '0' }} IMAGE_TAG: ${{ inputs.image-tag }} diff --git a/e2e/with-kube-gateway.sh b/e2e/with-kube-gateway.sh index fae4260438..31c0771dc8 100755 --- a/e2e/with-kube-gateway.sh +++ b/e2e/with-kube-gateway.sh @@ -98,7 +98,6 @@ PORTFORWARD_LOG="${WORKDIR}/portforward.log" PORTFORWARD_HEALTH_PID="" PORTFORWARD_HEALTH_LOG="${WORKDIR}/portforward-health.log" HELM_INSTALLED=0 -WORKSPACE_HELM_INSTALLED=0 EXTERNAL_PG_FIXTURE_DEPLOYED=0 EXTERNAL_PG_FIXTURE_SECRET="" EXTERNAL_PG_FIXTURE_MANIFEST="${ROOT}/e2e/kubernetes/postgres-fixture.yaml" @@ -584,10 +583,6 @@ cleanup() { fi fi - if [ "${WORKSPACE_HELM_INSTALLED}" = "1" ]; then - helmctl uninstall "${RELEASE_NAME}-workspace" --namespace "${NAMESPACE}" || true - fi - if [ "${EXTERNAL_PG_FIXTURE_DEPLOYED}" = "1" ] \ || [ "${OPENSHIFT_POSTGRES_SCC_GRANTED}" = "1" ]; then cleanup_postgres_fixture "${EXTERNAL_PG_FIXTURE_SECRET}" @@ -1537,15 +1532,6 @@ else deploy_postgres_fixture "${OPENSHELL_E2E_KUBE_EXTERNAL_POSTGRES_SECRET}" fi - if [ "${OPENSHELL_E2E_KUBE_SPLIT_WORKSPACE:-0}" = "1" ]; then - helmctl install "${RELEASE_NAME}-workspace" "${ROOT}/deploy/helm/openshell-workspace" \ - --namespace "${NAMESPACE}" --create-namespace \ - --set "gateway.serviceAccount.namespace=${NAMESPACE}" \ - --wait --timeout 2m - WORKSPACE_HELM_INSTALLED=1 - helm_extra_args+=(--set workspaceResources.enabled=false) - fi - echo "Installing Helm chart (release=${RELEASE_NAME}, namespace=${NAMESPACE}, tag=${IMAGE_TAG_VALUE})..." helmctl install "${RELEASE_NAME}" "${ROOT}/deploy/helm/openshell" \ --namespace "${NAMESPACE}" --create-namespace \ diff --git a/tasks/test.toml b/tasks/test.toml index 0e27645d67..6bafa95e9e 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -255,8 +255,8 @@ run = [ ] ["e2e:kubernetes:updates"] -description = "Validate sandbox updates with split workspace RBAC on both Agent Sandbox APIs" -env = { OPENSHELL_E2E_KUBE_TEST = "kubernetes_image_update", OPENSHELL_E2E_KUBE_SPLIT_WORKSPACE = "1" } +description = "Validate sandbox updates with the combined Helm chart on both Agent Sandbox APIs" +env = { OPENSHELL_E2E_KUBE_TEST = "kubernetes_image_update" } run = [ "e2e/rust/e2e-kubernetes.sh", "AGENT_SANDBOX_VERSION=v0.4.6 e2e/rust/e2e-kubernetes.sh", From 4bb559600951455e60bd07cf7b130e33b38f5d47 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 28 Oct 2026 19:08:12 +0000 Subject: [PATCH 16/23] test(kubernetes): use uuid for update request IDs Signed-off-by: Gordon Sim --- tests/suites/features/Cargo.lock | 3 +-- tests/suites/features/kubernetes-updates/Cargo.toml | 3 +-- .../features/kubernetes-updates/tests/update.rs | 13 +------------ 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/tests/suites/features/Cargo.lock b/tests/suites/features/Cargo.lock index f7a166861b..bceb5b94d5 100644 --- a/tests/suites/features/Cargo.lock +++ b/tests/suites/features/Cargo.lock @@ -2212,13 +2212,12 @@ dependencies = [ name = "openshell-test-feature-kubernetes-updates" version = "0.0.0" dependencies = [ - "hex", "openshell-testkit", - "rand 0.9.5", "serde_json", "tempfile", "tokio", "tonic", + "uuid", ] [[package]] diff --git a/tests/suites/features/kubernetes-updates/Cargo.toml b/tests/suites/features/kubernetes-updates/Cargo.toml index 2f63c0cc45..3348510e53 100644 --- a/tests/suites/features/kubernetes-updates/Cargo.toml +++ b/tests/suites/features/kubernetes-updates/Cargo.toml @@ -9,7 +9,6 @@ edition = "2024" openshell-testkit = { path = "../../../testkit/testkit" } serde_json = "1" tempfile = "3" -rand = "0.9" -hex = "0.4" tokio = { version = "1.43", features = ["process", "time"] } tonic = "0.14" +uuid = { version = "1.10", features = ["v4"] } diff --git a/tests/suites/features/kubernetes-updates/tests/update.rs b/tests/suites/features/kubernetes-updates/tests/update.rs index 4a49d4ec5a..61ac57e9fa 100644 --- a/tests/suites/features/kubernetes-updates/tests/update.rs +++ b/tests/suites/features/kubernetes-updates/tests/update.rs @@ -28,18 +28,7 @@ static UPDATED_IMAGE: LazyLock = LazyLock::new(|| { }); fn request_id() -> String { - let mut bytes = rand::random::<[u8; 16]>(); - bytes[6] = (bytes[6] & 0x0f) | 0x40; - bytes[8] = (bytes[8] & 0x3f) | 0x80; - let hex = hex::encode(bytes); - format!( - "{}-{}-{}-{}-{}", - &hex[..8], - &hex[8..12], - &hex[12..16], - &hex[16..20], - &hex[20..] - ) + uuid::Uuid::new_v4().to_string() } fn rpc(body: T) -> tonic::Request { From 3ff6359b45d664c236e90264c4e6d0b35a1a50b1 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 28 Oct 2026 20:10:42 +0000 Subject: [PATCH 17/23] fix(kubernetes): reject oversized annotations before accepting sandbox updates Signed-off-by: Gordon Sim --- .../src/image_update.rs | 17 +++++ .../src/image_update_tests.rs | 72 +++++++++++++++++++ docs/how-it-works/sandboxes/overview.mdx | 5 +- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/crates/openshell-driver-kubernetes/src/image_update.rs b/crates/openshell-driver-kubernetes/src/image_update.rs index 314d529727..0f12a925a7 100644 --- a/crates/openshell-driver-kubernetes/src/image_update.rs +++ b/crates/openshell-driver-kubernetes/src/image_update.rs @@ -21,6 +21,8 @@ use std::sync::LazyLock; // Deliberately separate from the runtime bootstrap operation annotations. Those // annotations drive reconciliation and only describe create/start/stop. const IMAGE_UPDATE_ANNOTATION: &str = "openshell.ai/sandbox-image-update"; +// Kubernetes limits the sum of all annotation keys and values, in bytes. +const MAX_ANNOTATION_BYTES: usize = 256 * 1024; #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] struct ImageUpdateRecord { @@ -163,6 +165,21 @@ impl KubernetesComputeDriver { if let Some(configuration) = configuration { prepare_configuration(&mut candidate, configuration, repeat)?; } + // Check the encoded candidate before preflight succeeds and the gateway + // durably accepts an intent. Raw argv limits do not account for JSON + // escaping, operation evidence, or existing annotations. + let annotation_bytes: usize = candidate + .metadata + .annotations + .iter() + .flat_map(|annotations| annotations.iter()) + .map(|(key, value)| key.len() + value.len()) + .sum(); + if annotation_bytes > MAX_ANNOTATION_BYTES { + return Err(KubernetesDriverError::InvalidArgument(format!( + "sandbox update exceeds Kubernetes annotation size limit ({annotation_bytes} > {MAX_ANNOTATION_BYTES} bytes)" + ))); + } // Revalidate the saved provenance and attachment UIDs against current // operator policy, even for retries. Do not manufacture new provenance // or re-render driver_config from a caller's request. diff --git a/crates/openshell-driver-kubernetes/src/image_update_tests.rs b/crates/openshell-driver-kubernetes/src/image_update_tests.rs index c2c4ce48eb..17594c1688 100644 --- a/crates/openshell-driver-kubernetes/src/image_update_tests.rs +++ b/crates/openshell-driver-kubernetes/src/image_update_tests.rs @@ -789,6 +789,78 @@ async fn configuration_update_atomically_changes_restart_inputs_and_retries_with } } +#[tokio::test] +async fn configuration_update_rejects_oversized_encoded_annotations_without_writes() { + use openshell_core::proto::compute::v1::{ + SandboxMainProcessUpdate, UpdateSandboxConfigurationRequest, + }; + // Both commands fit the gateway's count, per-argument, and total byte + // limits. The second exceeds the annotation budget only after JSON escaping. + let mut full_command = vec!["/bin/echo".to_string()]; + full_command.extend((0..7).map(|_| "a".repeat(32 * 1024))); + full_command.push("a".repeat(32 * 1024 - "/bin/echo".len())); + let mut escaped_command = vec!["/bin/echo".to_string()]; + escaped_command.extend((0..8).map(|_| "\"".repeat(16 * 1024))); + for version in [SANDBOX_VERSION_V1ALPHA1, SANDBOX_VERSION_V1BETA1] { + for command in [&full_command, &escaped_command] { + let (driver, state) = fixture(version, false); + state.lock().unwrap().sandbox["metadata"]["annotations"] + [ANNOTATION_SANDBOX_RUNTIME_MAIN_PROCESS_SPEC] = serde_json::json!( + openshell_core::sandbox_env::MainProcessConfig::encode_driver_spec(None).unwrap() + ); + let before = state.lock().unwrap().sandbox.clone(); + let mut update = UpdateSandboxConfigurationRequest { + preconditions: Some(request()), + main_process: Some(SandboxMainProcessUpdate { + command: command.clone(), + tty: false, + }), + environment: None, + }; + for validate_only in [true, false] { + update.preconditions.as_mut().unwrap().validate_only = validate_only; + let error = driver + .update_sandbox_configuration(&update) + .await + .unwrap_err(); + assert!(matches!(error, KubernetesDriverError::InvalidArgument(_))); + assert!(error.to_string().contains("annotation size limit")); + let state = state.lock().unwrap(); + assert_eq!(state.sandbox, before); + assert!(state.patches.is_empty()); + } + } + } +} + +#[tokio::test] +async fn image_update_annotation_budget_includes_existing_keys_and_values() { + for version in [SANDBOX_VERSION_V1ALPHA1, SANDBOX_VERSION_V1BETA1] { + let (driver, state) = fixture(version, false); + let mut request = request(); + request.validate_only = true; + let mut candidate: DynamicObject = + serde_json::from_value(state.lock().unwrap().sandbox.clone()).unwrap(); + prepare_update(&mut candidate, &request, None).unwrap(); + let existing_bytes: usize = candidate + .metadata + .annotations + .unwrap() + .iter() + .map(|(key, value)| key.len() + value.len()) + .sum(); + let key = "operator.example/padding"; + let padding = "a".repeat(MAX_ANNOTATION_BYTES - existing_bytes - key.len()); + state.lock().unwrap().sandbox["metadata"]["annotations"][key] = serde_json::json!(padding); + driver.update_sandbox_image(&request).await.unwrap(); + state.lock().unwrap().sandbox["metadata"]["annotations"][key] = + serde_json::json!(format!("{padding}a")); + let error = driver.update_sandbox_image(&request).await.unwrap_err(); + assert!(matches!(error, KubernetesDriverError::InvalidArgument(_))); + assert!(state.lock().unwrap().patches.is_empty()); + } +} + #[tokio::test] async fn configuration_update_rejects_reserved_environment_without_writes() { use openshell_core::proto::compute::v1::{ diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index 7f81c43d85..36a8753cf5 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -1034,7 +1034,10 @@ volume claim. It does not delete and recreate the sandbox, reseed its existing workspace from the new image, or change the trusted supervisor and sandbox runtime images. Omitted fields retain their current values. A supplied command replaces the argv list without shell expansion; an empty list restores the default -login shell resolved from the workload image. A supplied environment map replaces +login shell resolved from the workload image. The Kubernetes driver rejects an +update before acceptance if the encoded command and other custom-resource +annotations exceed Kubernetes' combined 256 KiB annotation limit. +A supplied environment map replaces sandbox-level overrides; clearing it restores any template-provided defaults. Labels and annotations replace user metadata on the gateway resource, preserve system-owned keys, and do not set Kubernetes pod metadata. Attempts to supply From 4cdde40729fd0287ac225ef972f13f82be2f0839 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 28 Oct 2026 20:42:00 +0000 Subject: [PATCH 18/23] docs(skills): correct pending sandbox update recovery guidance Signed-off-by: Gordon Sim --- .agents/skills/helm-dev-environment/SKILL.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.agents/skills/helm-dev-environment/SKILL.md b/.agents/skills/helm-dev-environment/SKILL.md index ee387308f5..df8189ad71 100644 --- a/.agents/skills/helm-dev-environment/SKILL.md +++ b/.agents/skills/helm-dev-environment/SKILL.md @@ -441,8 +441,9 @@ treat PostgreSQL connection markers or membership TTL expiry as retirement proof. SQLite testing supports one gateway process only. Image-update clients must call the separate `SandboxUpdates` service on the existing gateway listener, not add a method to the baseline `OpenShell` service or inspect new -public `SandboxStatus` image fields. Pending-operation recovery uses the same -requested image with a fresh version and the documented request-ID semantics. +public `SandboxStatus` image fields. Resume a pending operation with +`SandboxUpdates.UpdateSandbox`, the current resource version, and no selected +fields, following the documented request-ID semantics. The kube e2e wrapper creates only one port-forward, to `svc/openshell`; it no longer forwards the unauthenticated health listener or runs a `/readyz` e2e From 3333b5f91bec704a9cf9d4f53f474f0fc9fddd86 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 28 Oct 2026 21:18:10 +0000 Subject: [PATCH 19/23] fix(sandbox): preserve terminal results when stopping missing compute Signed-off-by: Gordon Sim --- crates/openshell-cli/src/run.rs | 8 + .../sandbox_create_lifecycle_integration.rs | 64 ++++- crates/openshell-server/src/compute/mod.rs | 102 +++++++- .../src/compute/tests/error_recovery.rs | 220 ++++++++++++++++++ docs/how-it-works/sandboxes/overview.mdx | 4 + skills/openshell-cli/SKILL.md | 4 +- 6 files changed, 390 insertions(+), 12 deletions(-) diff --git a/crates/openshell-cli/src/run.rs b/crates/openshell-cli/src/run.rs index ba31f35d87..eb224685ed 100644 --- a/crates/openshell-cli/src/run.rs +++ b/crates/openshell-cli/src/run.rs @@ -4116,6 +4116,14 @@ pub async fn sandbox_stop( .into_inner() .sandbox .ok_or_else(|| miette!("gateway returned no sandbox after stop"))?; + // A successful stop can preserve a canonical result when the transient + // compute resource is already gone. There is no Stopped event to wait for. + if sandbox.phase() == SandboxPhase::Completed as i32 + || (sandbox.phase() == SandboxPhase::Error as i32 && has_main_process_result(&sandbox)) + { + println!("{} Sandbox {name} already finished", "✓".green().bold()); + return Ok(()); + } wait_for_lifecycle_phase(&mut client, sandbox, SandboxPhase::Stopped).await?; println!("{} Stopped sandbox {name}", "✓".green().bold()); Ok(()) diff --git a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs index db9c02ffaf..587910fbaf 100644 --- a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs +++ b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs @@ -67,6 +67,7 @@ struct SandboxState { create_requests: Arc>>, expose_service_requests: Arc>>, fail_delete_sandbox_message: Arc>>, + stop_response: Arc>>, vm_error_after_started: Arc, vm_error_with_observed_exit: Arc, vm_slow_progress_before_ready: Arc, @@ -231,7 +232,17 @@ impl OpenShell for TestOpenShell { &self, _request: tonic::Request, ) -> Result, Status> { - Err(Status::unimplemented("unused")) + let sandbox = self + .state + .stop_response + .lock() + .await + .clone() + .ok_or_else(|| Status::unimplemented("unused"))?; + Ok(Response::new(SandboxResponse { + sandbox: Some(sandbox), + ..Default::default() + })) } async fn start_sandbox( @@ -1709,6 +1720,57 @@ fn test_config() -> run::SandboxCreateConfig<'static> { } } +#[tokio::test] +async fn sandbox_stop_accepts_terminal_results_without_waiting_for_stopped() { + let server = run_server().await; + let tls = test_tls(&server); + let config_dir = helpers::tempdir().unwrap(); + for (phase, exit_code, reason, succeeds) in [ + ( + SandboxPhase::Completed, + Some(0), + "MainProcessCompleted", + true, + ), + (SandboxPhase::Error, Some(17), "MainProcessFailed", true), + (SandboxPhase::Stopped, None, "Stopped", true), + ( + SandboxPhase::Error, + Some(17), + "ComputeResourceMissing", + false, + ), + ] { + let sandbox = Sandbox { + status: Some(SandboxStatus { + phase: phase as i32, + exit_code, + conditions: vec![SandboxCondition { + r#type: "Ready".into(), + status: "False".into(), + reason: reason.into(), + ..Default::default() + }], + ..Default::default() + }), + ..Default::default() + }; + *server.openshell.state.stop_response.lock().await = Some(sandbox); + Environment::new() + .set("XDG_CONFIG_HOME", config_dir.path()) + .run_async(async { + let result = tokio::time::timeout( + Duration::from_secs(5), + run::sandbox_stop(&server.endpoint, "terminal-stop-test", "default", &tls), + ) + .await + .expect("stop must finish without watching for another phase"); + assert_eq!(result.is_ok(), succeeds, "{reason}: {result:?}"); + }) + .await; + } +} + #[tokio::test] async fn sandbox_delete_continues_after_entry_failure() { let server = run_server().await; diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index af2c4acd94..2039ef4f7f 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -2203,8 +2203,12 @@ impl ComputeRuntime { Ok(settled) } Err(err) => { - self.recover_failed_lifecycle(&lifecycle_guard, &transition, &previous, true) - .await; + if let Some(terminal) = self + .recover_failed_lifecycle(&lifecycle_guard, &transition, &previous, true) + .await + { + return Ok(terminal); + } Err(Status::new( err.code(), format!("{} sandbox failed: {}", operation.verb(), err.message()), @@ -2681,7 +2685,8 @@ impl ComputeRuntime { settled, }) => { provisioning_operation::ensure_current_result(&settled, &settled)?; - self.recover_failed_lifecycle(&lifecycle_guard, &settled, &previous, false) + let _ = self + .recover_failed_lifecycle(&lifecycle_guard, &settled, &previous, false) .await; Err(Status::new( err.code(), @@ -2934,7 +2939,7 @@ impl ComputeRuntime { transition: &Sandbox, previous: &Sandbox, expected_stopped: bool, - ) { + ) -> Option { let sandbox_id = transition.object_id(); let sandbox_name = transition.object_name(); let observed = tokio::time::timeout( @@ -2946,6 +2951,14 @@ impl ComputeRuntime { let _sandbox_guard = self.lock_sandbox_for_lifecycle(lifecycle_guard).await; match observed { + Ok(None) if terminal_stop_exit_code(transition).is_some() => { + match self.restore_missing_terminal_stop(transition).await { + Ok(terminal) => return Some(terminal), + Err(error) => { + warn!(sandbox_id, %error, "Failed to restore terminal result after stop"); + } + } + } Ok(Some(snapshot)) if snapshot.id == sandbox_id && snapshot.status.is_some() => { let backend_phase = derive_phase(snapshot.status.as_ref()); let observed_stopped = backend_phase == SandboxPhase::Stopped @@ -3014,6 +3027,38 @@ impl ComputeRuntime { ); } } + None + } + + /// Called under the sandbox mutation lock after an authoritative lookup + /// confirms absent compute. The persisted exit code survives a gateway + /// restart; Stopping only retains it when stop began from a terminal result. + async fn restore_missing_terminal_stop(&self, transition: &Sandbox) -> Result { + let exit_code = terminal_stop_exit_code(transition) + .ok_or_else(|| Status::failed_precondition("stop has no terminal result to restore"))?; + let instance_id = transition + .status + .as_ref() + .unwrap() + .main_process_instance_id + .clone(); + let restored = self + .store + .update_message_cas::( + transition.object_id(), + sandbox_resource_version(transition), + |sandbox| apply_main_process_exit(sandbox, &instance_id, exit_code), + ) + .await + .map_err(|error| { + crate::grpc::persistence_error_to_status(error, "restore terminal sandbox result") + })?; + self.sandbox_index.update_from_sandbox(&restored); + self.sandbox_watch_bus.notify(restored.object_id()); + self.cleanup_stopped_sandbox_sessions(&restored) + .await + .map_err(Status::internal)?; + Ok(restored) } async fn reconcile_lifecycle_snapshot( @@ -4472,12 +4517,20 @@ impl ComputeRuntime { } } SandboxPhase::Stopping => { - self.recover_quiesce_transition(QuiesceOperation::Stop, &sandbox) - .await; + self.recover_quiesce_transition( + QuiesceOperation::Stop, + &sandbox, + &lifecycle_guard, + ) + .await; } SandboxPhase::Suspending => { - self.recover_quiesce_transition(QuiesceOperation::Suspend, &sandbox) - .await; + self.recover_quiesce_transition( + QuiesceOperation::Suspend, + &sandbox, + &lifecycle_guard, + ) + .await; } SandboxPhase::Starting => { if let Err(error) = self.validate_isolation_backend_binding(&sandbox) { @@ -4552,7 +4605,7 @@ impl ComputeRuntime { if let ProvisioningOperationError::Driver { settled, .. } = err && in_flight_resume_intent(&settled).is_some() { - Box::pin(self.recover_failed_lifecycle( + let _ = Box::pin(self.recover_failed_lifecycle( &lifecycle_guard, &settled, &sandbox, @@ -4571,12 +4624,24 @@ impl ComputeRuntime { /// Re-issue the idempotent driver call of a stop or suspend interrupted /// by a gateway restart, then commit its settled phase. - async fn recover_quiesce_transition(&self, operation: QuiesceOperation, sandbox: &Sandbox) { + async fn recover_quiesce_transition( + &self, + operation: QuiesceOperation, + sandbox: &Sandbox, + lifecycle_guard: &SandboxLifecycleGuard, + ) { let sandbox_id = sandbox.object_id(); if let Err(err) = self .call_quiesce_driver(operation, sandbox_id, sandbox.object_name()) .await { + if terminal_stop_exit_code(sandbox).is_some() + && Box::pin(self.recover_failed_lifecycle(lifecycle_guard, sandbox, sandbox, true)) + .await + .is_some() + { + return; + } warn!(sandbox_id, operation = operation.verb(), error = %err, "Failed to recover sandbox lifecycle transition"); return; } @@ -6602,6 +6667,13 @@ impl ComputeRuntime { let sandbox = decode_sandbox_record(¤t_record)?; let phase = SandboxPhase::try_from(sandbox.phase()).unwrap_or(SandboxPhase::Unknown); + if terminal_stop_exit_code(&sandbox).is_some() { + return self + .restore_missing_terminal_stop(&sandbox) + .await + .map(|_| ()) + .map_err(|error| error.to_string()); + } if phase == SandboxPhase::Completed || is_failed_main_process_result(&sandbox) || provisioning_deadline::timed_out(&sandbox) @@ -6797,6 +6869,16 @@ fn has_specific_infrastructure_error(sandbox: &Sandbox) -> bool { }) } +fn terminal_stop_exit_code(sandbox: &Sandbox) -> Option { + if sandbox.phase() != SandboxPhase::Stopping as i32 + || provisioning_deadline::timed_out(sandbox) + || provisioning_deadline::driver_operation_pending(sandbox) + { + return None; + } + sandbox.status.as_ref()?.exit_code +} + fn is_failed_main_process_result(sandbox: &Sandbox) -> bool { sandbox.phase() == SandboxPhase::Error as i32 && sandbox.status.as_ref().is_some_and(|status| { diff --git a/crates/openshell-server/src/compute/tests/error_recovery.rs b/crates/openshell-server/src/compute/tests/error_recovery.rs index 7fdfea0eeb..8d269d1804 100644 --- a/crates/openshell-server/src/compute/tests/error_recovery.rs +++ b/crates/openshell-server/src/compute/tests/error_recovery.rs @@ -16,6 +16,226 @@ async fn stored(runtime: &ComputeRuntime, id: &str) -> Sandbox { .unwrap() } +#[tokio::test] +async fn terminal_stop_preserves_result_when_compute_is_missing() { + for exit_code in [0, 1, 137] { + let driver = ControlledDriver::new(); + driver.set_stop_outcome(ControlledLifecycleOutcome::NotFound); + let runtime = test_runtime(driver.clone()).await; + let mut sandbox = sandbox_record("terminal-id", "terminal", SandboxPhase::Ready); + apply_main_process_exit(&mut sandbox, "exited-instance", exit_code); + runtime.store.put_message(&sandbox).await.unwrap(); + let session = ssh_session_record("old-session", sandbox.object_id()); + runtime.store.put_message(&session).await.unwrap(); + register_test_supervisor_session(&runtime, sandbox.object_id()); + + for _ in 0..2 { + let result = runtime.stop_sandbox("default", "terminal").await.unwrap(); + assert_eq!(result.phase(), sandbox.phase()); + assert_eq!(result.status.as_ref().unwrap().exit_code, Some(exit_code)); + assert_eq!( + result.status.as_ref().unwrap().main_process_instance_id, + "exited-instance" + ); + assert_eq!( + ready_condition(&result).unwrap().reason, + ready_condition(&sandbox).unwrap().reason + ); + assert_eq!(result.spec, sandbox.spec); + assert!(!runtime.supervisor_sessions.has_session(sandbox.object_id())); + assert!( + runtime + .store + .get_message::(session.object_id()) + .await + .unwrap() + .is_none() + ); + + let record = runtime + .store + .get(Sandbox::object_type(), sandbox.object_id()) + .await + .unwrap() + .unwrap(); + runtime + .prune_missing_sandbox(record, openshell_core::time::now_ms(), 0) + .await + .unwrap(); + assert_eq!(stored(&runtime, sandbox.object_id()).await, result); + } + assert_eq!(driver.start_calls(), 0); + assert_eq!(driver.delete_calls(), 0); + } +} + +#[tokio::test] +async fn terminal_stop_recovers_from_persisted_result_after_restart_or_pruning() { + for exit_code in [0, 1, 137] { + for startup in [false, true] { + let driver = ControlledDriver::new(); + driver.set_stop_outcome(ControlledLifecycleOutcome::NotFound); + let runtime = test_runtime(driver).await; + let mut sandbox = sandbox_record("terminal-id", "terminal", SandboxPhase::Ready); + apply_main_process_exit(&mut sandbox, "exited-instance", exit_code); + runtime.store.put_message(&sandbox).await.unwrap(); + let terminal = stored(&runtime, sandbox.object_id()).await; + // Simulate a gateway dying after persisting Stopping, with no + // in-memory pre-stop snapshot available to either recovery path. + runtime + .write_lifecycle_phase( + &terminal, + SandboxPhase::Stopping, + "StopRequested", + "Stop requested", + ) + .await + .unwrap(); + let session = ssh_session_record("old-session", sandbox.object_id()); + runtime.store.put_message(&session).await.unwrap(); + register_test_supervisor_session(&runtime, sandbox.object_id()); + + if startup { + runtime + .recover_persisted_lifecycle_transitions() + .await + .unwrap(); + } else { + let record = runtime + .store + .get(Sandbox::object_type(), sandbox.object_id()) + .await + .unwrap() + .unwrap(); + runtime + .prune_missing_sandbox(record, openshell_core::time::now_ms(), 0) + .await + .unwrap(); + } + let result = stored(&runtime, sandbox.object_id()).await; + assert_eq!(result.phase(), terminal.phase()); + assert_eq!(result.status.as_ref().unwrap().exit_code, Some(exit_code)); + assert_eq!( + ready_condition(&result).unwrap().reason, + ready_condition(&terminal).unwrap().reason + ); + assert!(!runtime.supervisor_sessions.has_session(sandbox.object_id())); + assert!( + runtime + .store + .get_message::(session.object_id()) + .await + .unwrap() + .is_none() + ); + } + } +} + +#[tokio::test] +async fn terminal_stop_keeps_uncertain_compute_pending_until_explicit_retry() { + let driver = ControlledDriver::new(); + driver.set_stop_outcome(ControlledLifecycleOutcome::NotFound); + driver.set_get_outcome(ControlledGetOutcome::Error("lookup unavailable")); + let runtime = test_runtime(driver.clone()).await; + let mut sandbox = sandbox_record("terminal-id", "terminal", SandboxPhase::Ready); + apply_main_process_exit(&mut sandbox, "exited-instance", 0); + runtime.store.put_message(&sandbox).await.unwrap(); + + assert_eq!( + runtime + .stop_sandbox("default", "terminal") + .await + .unwrap_err() + .code(), + Code::NotFound + ); + let pending = stored(&runtime, sandbox.object_id()).await; + assert_eq!(pending.phase(), SandboxPhase::Stopping as i32); + assert_eq!(pending.status.as_ref().unwrap().exit_code, Some(0)); + runtime + .recover_persisted_lifecycle_transitions() + .await + .unwrap(); + assert_eq!(stored(&runtime, sandbox.object_id()).await, pending); + + driver.set_get_outcome(ControlledGetOutcome::Missing); + let result = runtime.stop_sandbox("default", "terminal").await.unwrap(); + assert_eq!(result.phase(), SandboxPhase::Completed as i32); + assert_eq!(result.status.as_ref().unwrap().exit_code, Some(0)); +} + +#[tokio::test] +async fn terminal_stop_recovery_does_not_overwrite_concurrent_changes() { + let driver = ControlledDriver::new(); + driver.set_stop_outcome(ControlledLifecycleOutcome::NotFound); + driver.block_get(); + let runtime = test_runtime(driver.clone()).await; + let mut sandbox = sandbox_record("terminal-id", "terminal", SandboxPhase::Ready); + apply_main_process_exit(&mut sandbox, "exited-instance", 0); + runtime.store.put_message(&sandbox).await.unwrap(); + let stop = { + let runtime = runtime.clone(); + tokio::spawn(async move { runtime.stop_sandbox("default", "terminal").await }) + }; + driver.get_started.notified().await; + let pending = stored(&runtime, sandbox.object_id()).await; + let deleting = runtime + .write_lifecycle_phase( + &pending, + SandboxPhase::Deleting, + "DeleteRequested", + "Delete requested", + ) + .await + .unwrap(); + driver.release_get(); + + assert!(stop.await.unwrap().is_err()); + assert_eq!(stored(&runtime, sandbox.object_id()).await, deleting); +} + +#[tokio::test] +async fn stop_without_terminal_result_still_reports_missing_compute() { + let driver = ControlledDriver::new(); + driver.set_stop_outcome(ControlledLifecycleOutcome::NotFound); + let runtime = test_runtime(driver).await; + let sandbox = sandbox_record("running-id", "running", SandboxPhase::Ready); + runtime.store.put_message(&sandbox).await.unwrap(); + assert_eq!( + runtime + .stop_sandbox("default", "running") + .await + .unwrap_err() + .code(), + Code::NotFound + ); + let pending = stored(&runtime, sandbox.object_id()).await; + assert_eq!(pending.phase(), SandboxPhase::Stopping as i32); + assert_eq!(pending.status.as_ref().unwrap().exit_code, None); + runtime + .recover_persisted_lifecycle_transitions() + .await + .unwrap(); + assert_eq!(stored(&runtime, sandbox.object_id()).await, pending); + let record = runtime + .store + .get(Sandbox::object_type(), sandbox.object_id()) + .await + .unwrap() + .unwrap(); + runtime + .prune_missing_sandbox(record, openshell_core::time::now_ms(), 0) + .await + .unwrap(); + let failed = stored(&runtime, sandbox.object_id()).await; + assert_eq!(failed.phase(), SandboxPhase::Error as i32); + assert_eq!( + ready_condition(&failed).unwrap().reason, + "ComputeResourceMissing" + ); +} + #[tokio::test] async fn failed_gateway_start_can_be_stopped_and_retried() { let driver = ControlledDriver::new(); diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index 36a8753cf5..adb9c30400 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -1011,6 +1011,10 @@ sandbox, run `sandbox stop` first. Stop cleans up compute and moves the sandbox to `Stopped`, preserving its exit code until the next start. This stop behavior also applies when sandbox updates are disabled. +If the terminal sandbox's compute resource is already gone, stop succeeds and +preserves its terminal phase and exit code. Configuration updates require a +retained compute resource. + If an infrastructure failure leaves a sandbox in `Error`, fix the reported cause, then run `sandbox stop` followed by `sandbox start`. Wait for stop to succeed before starting. This retains the sandbox and its persistent workspace on backends that support restarting stopped sandboxes; it cannot recover deleted resources or storage. For a provisioning timeout, wait for cleanup to finish, then run `sandbox start` directly. diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index b91f37afe4..63ec4b4d66 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -529,7 +529,9 @@ the operation that removes retained state. Before updating a retained `Completed` or `Error/MainProcessFailed` sandbox, run `sandbox stop`. It cleans up compute and transitions to `Stopped`, retaining -the exit code until the next start. +the exit code until the next start. If the terminal sandbox's compute resource +is already gone, stop succeeds and preserves its terminal phase and exit code; +configuration updates require retained compute. The sandbox's SSH host identity survives stop/start and runtime restarts. API clients can read its public fingerprint from the sandbox resource or From 9aa04e13eef9c0a74c3e2e4ffae5e49d282132c8 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 28 Oct 2026 21:29:56 +0000 Subject: [PATCH 20/23] fix(server): bound sandbox update attempts to unblock recovery and deletion Signed-off-by: Gordon Sim --- .../src/compute/image_update.rs | 222 +++++++++++++++++- docs/how-it-works/sandboxes/overview.mdx | 7 +- skills/openshell-cli/SKILL.md | 4 +- 3 files changed, 225 insertions(+), 8 deletions(-) diff --git a/crates/openshell-server/src/compute/image_update.rs b/crates/openshell-server/src/compute/image_update.rs index d609753bfc..4a19ee2a53 100644 --- a/crates/openshell-server/src/compute/image_update.rs +++ b/crates/openshell-server/src/compute/image_update.rs @@ -14,7 +14,7 @@ use tonic::{Request, Status}; use tracing::info; const UPDATE_RECOVERY_PAGE_SIZE: u32 = 128; -const UPDATE_RECOVERY_TIMEOUT: std::time::Duration = std::time::Duration::from_mins(1); +const UPDATE_ATTEMPT_TIMEOUT: std::time::Duration = std::time::Duration::from_mins(1); #[derive(Clone)] pub(super) struct UpdateRecoveryBackoff { @@ -211,8 +211,12 @@ impl ComputeRuntime { // and reconciliation progress while preflight waits on the driver. // The acceptance CAS below rejects any intervening record changes. drop(sandbox_guard); - self.reconcile_sandbox_update(¤t, &intent, true) - .await?; + tokio::time::timeout( + UPDATE_ATTEMPT_TIMEOUT, + self.reconcile_sandbox_update(¤t, &intent, true), + ) + .await + .map_err(|_| Status::deadline_exceeded("sandbox update preflight timed out"))??; sandbox_guard = self.lock_sandbox_for_lifecycle(&lifecycle_guard).await; // The private intent, selected configuration, and OLD-understood pending // operation flag commit in one version-fenced transaction. @@ -234,7 +238,19 @@ impl ComputeRuntime { let runtime = self.clone(); tokio::spawn(async move { let _lifecycle_guard = lifecycle_guard; - runtime.complete_image_update(accepted, intent).await + // Client cancellation must not cancel accepted work, but a stalled + // driver must release the gate for recovery, resume, or deletion. + // Timeout is ambiguous: retain any pending intent and its interlock. + tokio::time::timeout( + UPDATE_ATTEMPT_TIMEOUT, + runtime.complete_image_update(accepted, intent), + ) + .await + .unwrap_or_else(|_| { + Err(Status::deadline_exceeded( + "sandbox update timed out; recovery will retry any pending intent", + )) + }) }) .await .map_err(|_| { @@ -417,7 +433,7 @@ impl ComputeRuntime { let Some(_gate) = self.lifecycle_gates.try_lock_for(id) else { return Ok(()); }; - let deadline = tokio::time::Instant::now() + UPDATE_RECOVERY_TIMEOUT; + let deadline = tokio::time::Instant::now() + UPDATE_ATTEMPT_TIMEOUT; let read = async { let sandbox = self .store @@ -1021,6 +1037,200 @@ mod tests { assert!(runtime.update_recovery_backoff.lock().await.is_empty()); } + #[tokio::test] + async fn timed_out_explicit_update_releases_gate_and_preserves_recovery() { + use std::time::Duration; + + for cancel_request in [false, true] { + for recovery in ["automatic", "resume", "delete"] { + let (runtime, driver, original) = fixture(true).await; + let (entered, release) = driver.pause_image_updates(); + let update = { + let runtime = runtime.clone(); + let original = original.clone(); + tokio::spawn(async move { + runtime + .update_sandbox_image( + original.object_id(), + "new-image".into(), + original.get_resource_version(), + ) + .await + }) + }; + entered.notified().await; + release.add_permits(1); // Let preflight pass; stall the accepted update. + entered.notified().await; + let intent = runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap() + .pending + .unwrap(); + if cancel_request { + update.abort(); + } + tokio::time::pause(); + tokio::time::advance(UPDATE_ATTEMPT_TIMEOUT).await; + tokio::task::yield_now().await; + tokio::time::resume(); + let result = tokio::time::timeout(Duration::from_secs(2), update) + .await + .expect("explicit update must have a bounded lifetime"); + if cancel_request { + assert!(result.unwrap_err().is_cancelled()); + } else { + assert_eq!(result.unwrap().unwrap_err().code(), Code::DeadlineExceeded); + } + drop( + tokio::time::timeout( + Duration::from_secs(2), + runtime.lifecycle_gates.lock_for(original.object_id()), + ) + .await + .expect("the detached worker must release its lifecycle gate"), + ); + let pending = runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(); + ensure_image_update_interlock(&pending, &intent).unwrap(); + assert_eq!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .unwrap() + .pending, + Some(intent.clone()) + ); + + tokio::time::timeout(Duration::from_secs(2), async { + match recovery { + "automatic" => { + release.add_permits(1); + runtime.recover_pending_sandbox_updates().await.unwrap(); + drop(runtime.update_recovery_sweep.acquire().await.unwrap()); + } + "resume" => { + release.add_permits(1); + runtime + .update_sandbox_configuration( + original.object_id(), + &openshell_core::proto::UpdateSandboxRequest { + expected_resource_version: pending.get_resource_version(), + ..Default::default() + }, + ) + .await + .unwrap(); + } + "delete" => { + // Deletion must work while the updater remains stalled. + runtime + .delete_sandbox("default", original.object_name()) + .await + .unwrap(); + } + _ => unreachable!(), + } + }) + .await + .expect("a timed-out update must permit recovery or deletion"); + let state = runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap(); + if recovery == "delete" { + assert!(state.is_none()); + assert!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .is_none() + ); + assert!( + runtime + .store + .complete_sandbox_image_update(original.object_id(), &intent) + .await + .is_err(), + "late completion cannot resurrect a deleted sandbox" + ); + } else { + assert!(state.unwrap().pending.is_none()); + let calls = image_calls(&driver); + assert_eq!(calls.len(), 1); + assert_eq!(calls[0].operation_id, intent.operation_id); + } + } + } + } + + #[tokio::test] + async fn timed_out_update_preflight_leaves_sandbox_available_for_deletion() { + use std::time::Duration; + + let (runtime, driver, original) = fixture(true).await; + let (entered, _release) = driver.pause_image_updates(); + let update = { + let runtime = runtime.clone(); + let original = original.clone(); + tokio::spawn(async move { + runtime + .update_sandbox_image( + original.object_id(), + "new-image".into(), + original.get_resource_version(), + ) + .await + }) + }; + entered.notified().await; + tokio::time::pause(); + tokio::time::advance(UPDATE_ATTEMPT_TIMEOUT).await; + tokio::task::yield_now().await; + tokio::time::resume(); + let error = tokio::time::timeout(Duration::from_secs(2), update) + .await + .expect("preflight must time out before accepting an update") + .unwrap() + .unwrap_err(); + assert_eq!(error.code(), Code::DeadlineExceeded); + assert_eq!( + runtime + .store + .get_message::(original.object_id()) + .await + .unwrap() + .unwrap(), + original + ); + assert!( + runtime + .store + .get_sandbox_image_state(original.object_id()) + .await + .unwrap() + .is_none() + ); + tokio::time::timeout( + Duration::from_secs(2), + runtime.delete_sandbox("default", original.object_name()), + ) + .await + .expect("preflight timeout must release the lifecycle gate") + .unwrap(); + } + #[tokio::test] async fn timed_out_automatic_update_retains_intent_and_defers_recovery() { let (runtime, driver, original) = fixture(true).await; @@ -1038,7 +1248,7 @@ mod tests { runtime.recover_pending_sandbox_updates().await.unwrap(); entered.notified().await; tokio::time::pause(); - tokio::time::advance(UPDATE_RECOVERY_TIMEOUT).await; + tokio::time::advance(UPDATE_ATTEMPT_TIMEOUT).await; tokio::task::yield_now().await; tokio::time::resume(); drop(runtime.update_recovery_sweep.acquire().await.unwrap()); diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index adb9c30400..a3b01280e1 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -1101,7 +1101,12 @@ compute again. This Stop behavior also applies when updates are disabled. Cleanup that is still pending cannot be bypassed. An `ABORTED` version conflict requires another read before you construct a new -conditional request. An update failure or disconnected response can leave a +conditional request. The gateway limits driver preflight and each accepted update +attempt to one minute each. A timed-out preflight does not accept an update. +An accepted update continues after client cancellation until it completes or +times out. A timeout releases the sandbox for recovery or deletion; it does not +roll back an update the driver may have applied. +An update failure or disconnected response can leave a pending operation, even when `sandbox.spec.template.image` already names the target image. Start, stop, and provisioning retry remain blocked until reconciliation succeeds. The gateway retries accepted updates at startup and periodically, even diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index 63ec4b4d66..37b7bb2c09 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -593,7 +593,9 @@ cleanup completion and settlement of the original driver operation, then run timeout diagnostic and storage and does not bypass pending cleanup. An operation-pending error blocks start, stop, and provisioning retry. The gateway -retries automatically even when new updates are disabled. Repeated automatic +limits preflight and each accepted update attempt to one minute each. A timeout +after acceptance preserves pending intent for recovery; it does not imply rollback. +The gateway retries automatically even when new updates are disabled. Repeated automatic failures back off up to 15 minutes per gateway; restarting a gateway resets the delay. To resume immediately, read a fresh resource version and call `UpdateSandbox` with no selected fields; From 41c4083aa586a38f0bfecc5cdfee3db15121a4c7 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Thu, 29 Oct 2026 15:39:46 +0000 Subject: [PATCH 21/23] fix(server): remove unintended sandbox label count limit Signed-off-by: Gordon Sim --- crates/openshell-server/src/grpc/sandbox.rs | 15 +++++++++++++++ .../src/grpc/sandbox/image_update_tests.rs | 13 +++++++++++++ crates/openshell-server/src/grpc/validation.rs | 12 +----------- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index 4b5011c623..a797da2589 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -8092,6 +8092,21 @@ mod tests { assert_eq!(process.run_as_group, "1234"); } + #[test] + fn create_sandbox_accepts_more_than_128_labels() { + let request = CreateSandboxRequest { + name: "many-labels".into(), + spec: Some(SandboxSpec::default()), + labels: (0..129) + .map(|index| (format!("label-{index}"), "value".into())) + .collect(), + ..Default::default() + }; + for workload_template in ["", "workload-template"] { + validate_create_sandbox_request_pre_io(&request, workload_template).unwrap(); + } + } + #[tokio::test] async fn create_sandbox_still_rejects_long_label_values() { let state = test_server_state().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 e8c7b764ab..e83d786ee0 100644 --- a/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs +++ b/crates/openshell-server/src/grpc/sandbox/image_update_tests.rs @@ -317,6 +317,19 @@ async fn public_image_update_replays_without_reapplying_or_touching_same_name_re assert_eq!(driver.calls().iter().filter(|call| matches!(call, FakeComputeDriverCall::UpdateSandboxConfiguration { request } if !request.preconditions.as_ref().unwrap().validate_only)).count(), 1); } +#[test] +fn configuration_update_accepts_more_than_128_labels() { + let update = UpdateSandboxRequest { + labels: Some(openshell_core::proto::SandboxMapUpdate { + values: (0..129) + .map(|index| (format!("label-{index}"), "value".into())) + .collect(), + }), + ..request() + }; + validate_image_update_request(&update).unwrap(); +} + #[test] fn configuration_update_presence_and_reserved_metadata() { let mut update = request(); diff --git a/crates/openshell-server/src/grpc/validation.rs b/crates/openshell-server/src/grpc/validation.rs index a5152bc80b..d84488bcca 100644 --- a/crates/openshell-server/src/grpc/validation.rs +++ b/crates/openshell-server/src/grpc/validation.rs @@ -459,20 +459,10 @@ pub(super) fn validate_string_map( Ok(()) } -/// Labels share a bounded metadata budget but use Kubernetes value syntax. +/// Validate label keys and values using Kubernetes syntax. pub(super) fn validate_labels( labels: &std::collections::HashMap, ) -> Result<(), Status> { - const MAX_METADATA_LABELS_ENTRIES: usize = 128; - if labels.len() > MAX_METADATA_LABELS_ENTRIES { - return Err(invalid_argument( - "labels", - format!( - "labels exceeds maximum entries ({} > {MAX_METADATA_LABELS_ENTRIES})", - labels.len() - ), - )); - } for (key, value) in labels { validate_label_key(key)?; validate_label_value(value)?; From f108248a61b63fdc878436100880aecbfe3b4b7b Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Thu, 29 Oct 2026 19:29:58 +0000 Subject: [PATCH 22/23] fix(kubernetes): check known pod names during sandbox update preflight Signed-off-by: Gordon Sim --- crates/openshell-driver-kubernetes/README.md | 6 +- .../src/image_update.rs | 85 ++++----- .../src/image_update_tests.rs | 179 +++++++++++++++--- skills/debug-openshell-cluster/SKILL.md | 11 +- 4 files changed, 195 insertions(+), 86 deletions(-) diff --git a/crates/openshell-driver-kubernetes/README.md b/crates/openshell-driver-kubernetes/README.md index 2808e242c3..b95fb6bf3f 100644 --- a/crates/openshell-driver-kubernetes/README.md +++ b/crates/openshell-driver-kubernetes/README.md @@ -309,7 +309,11 @@ linked factories opt in through `build_with_configuration_updates`. The request identifies the sandbox, original resource UID, expected image, operation ID, and monotonic revision. The driver checks the suspended state, completed bootstrap, current resource UID, and absence of workload and supervisor -Pods, including Pods found only by owner UID or recorded name. It revalidates +Pods by directly reading the controller-recorded workload name, the Sandbox +resource name, and the stable dedicated-supervisor name. Duplicate names are +read once, and terminating Pods block updates. These checks make at most three +Pod reads regardless of namespace size; they do not discover unexpectedly named +Pods. The driver revalidates external-resource admission before patching the existing resource with a `resourceVersion` condition. The patch includes the verified UID; Kubernetes immutable-UID validation also rejects a same-name replacement. No resource or diff --git a/crates/openshell-driver-kubernetes/src/image_update.rs b/crates/openshell-driver-kubernetes/src/image_update.rs index 0f12a925a7..7340943400 100644 --- a/crates/openshell-driver-kubernetes/src/image_update.rs +++ b/crates/openshell-driver-kubernetes/src/image_update.rs @@ -4,18 +4,19 @@ //! Storage-preserving, stopped-only workload image mutation. use super::{ - KUBE_API_TIMEOUT, KubernetesComputeDriver, KubernetesDriverError, LABEL_SANDBOX_ID, - LABEL_SANDBOX_NAME, SANDBOX_POD_NAME_ANNOTATION, SANDBOX_VERSION_V1BETA1, - WORKSPACE_INIT_CONTAINER_NAME, accepts_auth_namespace, admission_error, annotation_or_label, + KUBE_API_TIMEOUT, KubernetesComputeDriver, KubernetesDriverError, LABEL_SANDBOX_NAME, + SANDBOX_POD_NAME_ANNOTATION, SANDBOX_VERSION_V1BETA1, WORKSPACE_INIT_CONTAINER_NAME, + accepts_auth_namespace, admission_error, annotation_or_label, is_kube_resource_version_conflict, parse_kubernetes_runtime_identity, sandbox_id_from_object, sandbox_runtime_bootstrap_in_progress, select_expected_sandbox_runtime, }; +use crate::sandbox_runtime::SandboxRuntimeNames; use k8s_openapi::api::core::v1::Pod; use kube::Api; use kube::api::{DynamicObject, ListParams, Patch, PatchParams}; use openshell_core::proto::compute::v1::SandboxUpdatePreconditions; use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::sync::LazyLock; // Deliberately separate from the runtime bootstrap operation annotations. Those @@ -89,7 +90,7 @@ impl KubernetesComputeDriver { .gate_for(&request.sandbox_id) .lock_owned() .await; - // Include discovery, admission and Pod pagination in a single bound. + // Include discovery, admission and Pod reads in a single bound. let result = tokio::time::timeout( KUBE_API_TIMEOUT, self.update_sandbox_image_inner(request, configuration), @@ -255,31 +256,41 @@ impl KubernetesComputeDriver { namespace: &str, ) -> Result<(), KubernetesDriverError> { let pods = Api::::namespaced(self.client.clone(), namespace); - // The controller's workload Pod need not carry the OpenShell sandbox - // label. Inspect owner UIDs and recorded names as well as labels and - // annotations, and reject terminating Pods too. Listing the namespace - // also catches supervisors from earlier runtime generations. - let mut params = ListParams::default().limit(500); - loop { - let page = pods - .list(¶ms) + let names = SandboxRuntimeNames::new(sandbox_id); + // Check both the controller-recorded and default workload names. The + // dedicated supervisor name is stable across generations; check it even + // with shared supervision to catch a leftover dedicated Pod. Direct + // reads keep preflight independent of the number of namespace Pods. + let pod_names: BTreeSet<_> = [ + object.metadata.name.as_deref(), + object + .metadata + .annotations + .as_ref() + .and_then(|annotations| annotations.get(SANDBOX_POD_NAME_ANNOTATION)) + .map(String::as_str), + Some(names.supervisor_pod.as_str()), + ] + .into_iter() + .flatten() + .filter(|name| !name.is_empty()) + .collect(); + for name in pod_names { + // Terminating Pods still block updates. Only a 404 proves absence; + // authorization, transport and other API failures must propagate. + if pods + .get_opt(name) .await - .map_err(KubernetesDriverError::from_kube)?; - if page - .items - .iter() - .any(|pod| image_update_pod_matches(pod, object, sandbox_id)) + .map_err(KubernetesDriverError::from_kube)? + .is_some() { return Err(KubernetesDriverError::Precondition( "cannot update image while sandbox workload or supervisor Pods still exist" .into(), )); } - match page.metadata.continue_.filter(|token| !token.is_empty()) { - Some(token) => params = params.continue_token(&token), - None => return Ok(()), - } } + Ok(()) } } @@ -598,36 +609,6 @@ fn prepare_configuration( Ok(()) } -fn image_update_pod_matches(pod: &Pod, object: &DynamicObject, sandbox_id: &str) -> bool { - let metadata = &pod.metadata; - metadata.owner_references.as_ref().is_some_and(|owners| { - owners - .iter() - .any(|owner| Some(owner.uid.as_str()) == object.metadata.uid.as_deref()) - }) || metadata - .labels - .as_ref() - .and_then(|labels| labels.get(LABEL_SANDBOX_ID)) - .map(String::as_str) - == Some(sandbox_id) - || metadata - .annotations - .as_ref() - .and_then(|annotations| annotations.get(LABEL_SANDBOX_ID)) - .map(String::as_str) - == Some(sandbox_id) - || metadata.name.as_deref().is_some_and(|name| { - Some(name) == object.metadata.name.as_deref() - || object - .metadata - .annotations - .as_ref() - .and_then(|annotations| annotations.get(SANDBOX_POD_NAME_ANNOTATION)) - .map(String::as_str) - == Some(name) - }) -} - #[cfg(test)] #[path = "image_update_tests.rs"] mod tests; diff --git a/crates/openshell-driver-kubernetes/src/image_update_tests.rs b/crates/openshell-driver-kubernetes/src/image_update_tests.rs index 17594c1688..6a079d9575 100644 --- a/crates/openshell-driver-kubernetes/src/image_update_tests.rs +++ b/crates/openshell-driver-kubernetes/src/image_update_tests.rs @@ -5,7 +5,7 @@ use super::super::{ ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_OPERATION, ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_PHASE, ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAPPING, ANNOTATION_SANDBOX_RUNTIME_LOG_LEVEL, ANNOTATION_SANDBOX_RUNTIME_MAIN_PROCESS_SPEC, ANNOTATION_SANDBOX_RUNTIME_READINESS, - KubernetesComputeConfig, LABEL_SANDBOX_WORKSPACE, OperatorNamespaceAllowlist, + KubernetesComputeConfig, LABEL_SANDBOX_ID, LABEL_SANDBOX_WORKSPACE, OperatorNamespaceAllowlist, SANDBOX_BOOTSTRAP_CONTAINER_NAME, SANDBOX_BOOTSTRAP_VOLUME_NAME, SANDBOX_GROUP, SANDBOX_VERSION_V1ALPHA1, WORKSPACE_INIT_MOUNT_PATH, WorkspaceMode, }; @@ -23,7 +23,7 @@ struct ApiState { calls: Vec<(http::Method, String)>, patches: Vec, conflict: bool, - pods_continue: bool, + pod_error: Option<(String, http::StatusCode)>, } fn response( @@ -129,14 +129,13 @@ fn fixture( calls: Vec::new(), patches: Vec::new(), conflict: false, - pods_continue: false, + pod_error: None, })); let service_state = state.clone(); let service = tower::service_fn(move |request: http::Request| { let state = service_state.clone(); async move { let path = request.uri().path().to_string(); - let query = request.uri().query().unwrap_or_default().to_string(); let method = request.method().clone(); let body = request.into_body().collect().await.unwrap().to_bytes(); let mut state = state.lock().unwrap(); @@ -152,12 +151,38 @@ fn fixture( http::Method::GET, "/api/v1/namespaces/openshell/persistentvolumeclaims/team-data", ) => state.pvc.clone(), - (http::Method::GET, "/api/v1/namespaces/openshell/pods") => { - if state.pods_continue && !query.contains("continue=") { - serde_json::json!({"apiVersion":"v1", "kind":"PodList", "metadata":{"continue":"page-two"}, "items":[]}) - } else { - serde_json::json!({"apiVersion":"v1", "kind":"PodList", "metadata":{}, "items":state.pods}) + (http::Method::GET, path) + if path.starts_with("/api/v1/namespaces/openshell/pods/") => + { + let name = path + .strip_prefix("/api/v1/namespaces/openshell/pods/") + .unwrap(); + if let Some((error_name, status)) = &state.pod_error + && error_name == name + { + return Ok(response( + *status, + serde_json::json!({ + "apiVersion":"v1", "kind":"Status", "status":"Failure", + "reason":status.canonical_reason().unwrap(), + "message":"pod read failed", "code":status.as_u16() + }), + )); } + let Some(pod) = state + .pods + .iter() + .find(|pod| pod["metadata"]["name"] == name) + else { + return Ok(response( + http::StatusCode::NOT_FOUND, + serde_json::json!({ + "apiVersion":"v1", "kind":"Status", "status":"Failure", + "reason":"NotFound", "message":"pod not found", "code":404 + }), + )); + }; + pod.clone() } (http::Method::PATCH, path) if path.ends_with("/sandboxes/sandbox-cr") => { let mutation: serde_json::Value = serde_json::from_slice(&body).unwrap(); @@ -253,7 +278,7 @@ async fn image_update_preflight_validates_without_writes_and_apply_rechecks() { .iter() .any(|(_, path)| path.ends_with("/persistentvolumeclaims/team-data")) ); - assert!(state.calls.iter().any(|(_, path)| path.ends_with("/pods"))); + assert_eq!(pod_read_names(&state).len(), 3); } // Operator approval can change between preflight and apply. Both requests // independently enforce the entire stopped/admission check. @@ -461,27 +486,123 @@ async fn image_update_rejects_running_bootstrapping_and_unspecified_operating_st } } +fn pod_read_names(state: &ApiState) -> Vec<&str> { + state + .calls + .iter() + .filter_map(|(method, path)| { + assert_ne!( + path, "/api/v1/namespaces/openshell/pods", + "must not list Pods" + ); + let name = path.strip_prefix("/api/v1/namespaces/openshell/pods/")?; + assert_eq!(method, http::Method::GET); + Some(name) + }) + .collect() +} + #[tokio::test] -async fn image_update_checks_actual_workload_and_supervisor_pods_including_later_pages() { - for metadata in [ - serde_json::json!({"name":"controller-workload", "ownerReferences":[{"apiVersion":"agents.x-k8s.io/v1beta1", "kind":"Sandbox", "name":"sandbox-cr", "uid":"resource-uid"}]}), - serde_json::json!({"name":"supervisor", "labels":{LABEL_SANDBOX_ID:"sandbox-1"}}), - serde_json::json!({"name":"recorded-workload", "deletionTimestamp":"2026-10-15T18:00:00Z"}), - serde_json::json!({"name":"workload-with-annotation", "annotations":{LABEL_SANDBOX_ID:"sandbox-1"}}), - ] { - let (driver, state) = fixture(SANDBOX_VERSION_V1BETA1, false); - { - let mut state = state.lock().unwrap(); - state - .pods - .push(serde_json::json!({"apiVersion":"v1", "kind":"Pod", "metadata":metadata})); - state.pods_continue = true; +async fn image_update_rejects_existing_known_pods_including_terminating_pods() { + for version in [SANDBOX_VERSION_V1ALPHA1, SANDBOX_VERSION_V1BETA1] { + for name in ["sandbox-cr", "recorded-workload", "os-supervisor-sandbox-1"] { + for terminating in [false, true] { + let (driver, state) = fixture(version, false); + let mut metadata = serde_json::json!({"name":name}); + if terminating { + metadata["deletionTimestamp"] = "2026-10-15T18:00:00Z".into(); + } + state.lock().unwrap().pods.push(serde_json::json!({ + "apiVersion":"v1", "kind":"Pod", "metadata":metadata + })); + for validate_only in [true, false] { + let result = driver + .update_sandbox_image(&SandboxUpdatePreconditions { + validate_only, + ..request() + }) + .await; + assert!( + matches!(result, Err(KubernetesDriverError::Precondition(message)) if message.contains("Pods still exist")), + "{version}: {name}, terminating={terminating}, validate_only={validate_only}" + ); + assert!(state.lock().unwrap().patches.is_empty()); + } + } + } + } +} + +#[tokio::test] +async fn image_update_reads_only_distinct_known_pod_names() { + for version in [SANDBOX_VERSION_V1ALPHA1, SANDBOX_VERSION_V1BETA1] { + for recorded_name in [ + None, + Some(""), + Some("sandbox-cr"), + Some("recorded-workload"), + Some("os-supervisor-sandbox-1"), + ] { + let (driver, state) = fixture(version, false); + { + let mut state = state.lock().unwrap(); + let annotations = state.sandbox["metadata"]["annotations"] + .as_object_mut() + .unwrap(); + annotations.remove(SANDBOX_POD_NAME_ANNOTATION); + if let Some(name) = recorded_name { + annotations.insert(SANDBOX_POD_NAME_ANNOTATION.into(), name.into()); + } + state.pods.push(serde_json::json!({ + "apiVersion":"v1", "kind":"Pod", "metadata":{"name":"unrelated-workload"} + })); + } + for validate_only in [true, false] { + state.lock().unwrap().calls.clear(); + driver + .update_sandbox_image(&SandboxUpdatePreconditions { + validate_only, + ..request() + }) + .await + .unwrap(); + let state = state.lock().unwrap(); + let mut actual = pod_read_names(&state); + actual.sort_unstable(); + let mut expected = vec!["os-supervisor-sandbox-1", "sandbox-cr"]; + if recorded_name == Some("recorded-workload") { + expected.insert(1, "recorded-workload"); + } + assert_eq!(actual, expected, "{version}: {recorded_name:?}"); + assert_eq!(state.patches.len(), usize::from(!validate_only)); + } + } + } +} + +#[tokio::test] +async fn image_update_propagates_known_pod_read_errors_without_writes() { + for version in [SANDBOX_VERSION_V1ALPHA1, SANDBOX_VERSION_V1BETA1] { + for name in ["sandbox-cr", "recorded-workload", "os-supervisor-sandbox-1"] { + for status in [ + http::StatusCode::FORBIDDEN, + http::StatusCode::INTERNAL_SERVER_ERROR, + ] { + let (driver, state) = fixture(version, false); + state.lock().unwrap().pod_error = Some((name.into(), status)); + for validate_only in [true, false] { + let error = driver + .update_sandbox_image(&SandboxUpdatePreconditions { + validate_only, + ..request() + }) + .await + .unwrap_err(); + assert!(error.to_string().contains("pod read failed"), "{error}"); + assert!(state.lock().unwrap().patches.is_empty()); + } + } } - let result = driver.update_sandbox_image(&request()).await; - assert!( - matches!(result, Err(KubernetesDriverError::Precondition(message)) if message.contains("Pods still exist")) - ); - assert!(state.lock().unwrap().patches.is_empty()); } } diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index a550c79922..17cafd957a 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -1473,10 +1473,13 @@ request admission semantics: use a new ID or no ID for the explicit resume reque and never change the original payload under its original ID. See the [recovery contract](https://docs.nvidia.com/openshell/latest/sdk/api-errors#sandbox-image-update-recovery). -Split Helm deployments need the current `openshell-workspace` Role, including -`get` and `list` on Pods. The update preflight must find remaining Pods by owner -UID and controller-recorded name as well as labels. Upgrade the workspace chart -alongside the gateway chart; a label selector does not remove the `list` permission. +Split Helm deployments need the current `openshell-workspace` Role. Update +preflight requires `get` on Pods: it checks the controller-recorded workload +name, the Sandbox resource name, and `os-supervisor-` directly. +Any remaining Pod at those names, including a terminating Pod, blocks the update. +The checks make at most three Pod reads regardless of namespace size and do not +discover unexpectedly named Pods. Upgrade the workspace chart alongside the +gateway chart. ### Step 7: Check VM-Backed Gateways From 84f97b13ae43690833b5f028e4249468874ea0a7 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Thu, 29 Oct 2026 20:15:29 +0000 Subject: [PATCH 23/23] docs: clarify sandbox update permissions and driver support Signed-off-by: Gordon Sim --- docs/kubernetes/setup.mdx | 3 ++- skills/openshell-cli/SKILL.md | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/kubernetes/setup.mdx b/docs/kubernetes/setup.mdx index ede500e931..bbc223e32f 100644 --- a/docs/kubernetes/setup.mdx +++ b/docs/kubernetes/setup.mdx @@ -411,7 +411,8 @@ namespace. The namespaced Role covers sandbox lifecycle, supervisor resources, and identity. Both the gateway chart and separate workspace chart grant these permissions. -Stopped-sandbox updates need Pod listing to detect remaining workload or supervisor Pods: +Stopped-sandbox updates use direct Pod `get` requests to check known workload and +supervisor Pod names for remaining Pods. | API Group | Resource | Verbs | |---|---|---| diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index 37b7bb2c09..f0c32f2d89 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -570,8 +570,9 @@ complete the published [activation checklist](https://docs.nvidia.com/openshell/latest/kubernetes/high-availability#activate-sandbox-updates) before enabling `enable_sandbox_updates`. Keep it false during a rolling upgrade and never enable it merely to bypass a failed compatibility check. -After activation, the RPC initially supports only stopped Kubernetes sandboxes; -other drivers return `UNIMPLEMENTED`. Stop and +After activation, image, command, and environment updates initially support only +stopped Kubernetes sandboxes; other drivers return `UNIMPLEMENTED` for those +fields. Metadata-only updates also support stopped sandboxes on other drivers. Stop and wait for `Stopped`, read the sandbox's current resource version through `GetSandbox`, call raw `UpdateSandbox` with the named workspace, sandbox name, selected image, command, environment overrides, labels or annotations, and required nonzero `expected_resource_version`, then start after