From ea6c6891dcdaaa97db4897ef438d6462d1cb3bbd Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Wed, 9 Sep 2026 12:37:57 -0700 Subject: [PATCH 01/15] feat(supervisor): stage gateway configuration snapshot delivery Signed-off-by: Piotr Mlocek --- architecture/gateway.md | 18 + architecture/sandbox.md | 38 + crates/openshell-core/src/proto/mod.rs | 7 + crates/openshell-server/src/compute/mod.rs | 55 + .../openshell-server/src/config_delivery.rs | 661 ++++ crates/openshell-server/src/grpc/policy.rs | 666 +++- crates/openshell-server/src/grpc/provider.rs | 51 +- crates/openshell-server/src/grpc/sandbox.rs | 16 + crates/openshell-server/src/lib.rs | 21 + .../src/persistence/postgres.rs | 44 + .../src/persistence/sqlite.rs | 30 + .../openshell-server/src/persistence/tests.rs | 83 +- crates/openshell-server/src/policy_store.rs | 19 + .../openshell-server/src/provider_refresh.rs | 24 +- .../src/supervisor_session.rs | 434 ++- .../src/supervisor_session.rs | 42 + docs/reference/gateway-config.mdx | 3 +- proto/openshell.proto | 132 +- proto/sandbox.proto | 18 +- sdk/go/proto/openshellv1/openshell.pb.go | 2941 +++++++++++------ sdk/go/proto/openshellv1/openshell_grpc.pb.go | 14 +- sdk/go/proto/sandboxv1/sandbox.pb.go | 256 +- sdk/typescript/src/raw.ts | 2 +- skills/debug-openshell-cluster/SKILL.md | 2 + 24 files changed, 4413 insertions(+), 1164 deletions(-) create mode 100644 crates/openshell-server/src/config_delivery.rs diff --git a/architecture/gateway.md b/architecture/gateway.md index 8771fd4c38..70000c2c22 100644 --- a/architecture/gateway.md +++ b/architecture/gateway.md @@ -654,6 +654,24 @@ successful create therefore yields an immediately usable provider; failures roll back the provider record. Service-account JSON and private keys remain gateway-side refresh bootstrap material; sandboxes receive minted access tokens instead. +## Supervisor configuration routing + +Committed configuration mutations publish component and scope identifiers, +never configuration payloads, to a bounded coalescing scheduler. The scheduler +builds the latest full snapshot for each affected active sandbox. An async +router owns session lookup, message sizing, sequence allocation, and enqueue. +Its local implementation uses the process-local supervisor registry. A future +HA implementation can resolve the gateway that owns a session and forward the +same typed message without changing mutation handlers. + +Polling remains authoritative during the first rollout stage. Snapshot build, +fanout, or enqueue failure cannot fail a mutation that already committed. +Provider snapshots may contain credentials and must not be +persisted or included in logs. + +See [sandbox configuration delivery](sandbox.md#supervisor-configuration-delivery) +for bootstrap, revision, and supervisor application semantics. + ## Supervisor Relay Sandbox workloads maintain an outbound supervisor session to the gateway. This diff --git a/architecture/sandbox.md b/architecture/sandbox.md index 7be66e97e6..588bfa7a56 100644 --- a/architecture/sandbox.md +++ b/architecture/sandbox.md @@ -473,6 +473,44 @@ the structured 403 and authors the narrowest rule. Mechanistically mapping L7 would either over-broaden rules or require path-templating logic that rots quickly. +## Supervisor Configuration Delivery + +The gateway and supervisor must implement the same internal supervisor protocol +revision. The gateway includes a configuration bootstrap when it accepts a +`ConnectSupervisor` session and can send complete component replacements on the +same stream after policy, settings, or provider state changes. +Bootstrap construction does not gate the session while polling remains +authoritative. These payloads describe the latest effective state rather than +the mutation that produced it. The gateway assigns ordering sequences within +each session and component, while each snapshot retains its own content +revision. + +Bootstrap components are independent read projections, not one atomic database +snapshot. The sandbox configuration carries the provider-environment revision +it was built against. The gateway retries bootstrap construction when that +revision does not match the provider snapshot. Later component updates and +polling repair changes committed while the other projections were being built. + +Configuration delivery goes through a gateway-owned routing boundary rather +than exposing local supervisor channels to mutation handlers. The current +implementation routes only to a supervisor connected to the same gateway +process. The asynchronous router contract can resolve a remote owner later +without changing publishers. Provider payloads can contain +credentials, so the gateway does not persist or render complete stream +messages in logs. + +The supervisor currently parses and ignores stream-delivered configuration. +Polling remains the only path that changes runtime state and repairs dropped or +unavailable delivery. The gateway serializes construction per sandbox and +component, and coalesces repeated mutations into the latest full snapshot. An +enqueue result means only that the local stream queue accepted the message. A +bounded scope fanout scheduler coalesces repeated workspace and global changes. +Snapshot construction has a deadline, and the gateway rejects encoded stream +messages that approach the transport decoder limit. A +later migration will apply these payloads directly and acknowledge their exact +revisions before removing supervisor polling. At that point, the gateway will +require a valid bootstrap before marking a session ready. + ## Policy Revision Acknowledgement When the supervisor loads a sandbox-scoped policy from the gateway, it retains diff --git a/crates/openshell-core/src/proto/mod.rs b/crates/openshell-core/src/proto/mod.rs index 43d2bce267..d80325e65e 100644 --- a/crates/openshell-core/src/proto/mod.rs +++ b/crates/openshell-core/src/proto/mod.rs @@ -94,3 +94,10 @@ pub fn all_workspaces_selector() -> WorkspaceSelector { )), } } + +/// Exact protocol revision required between a gateway and its supervisor. +/// +/// The supervisor stream is an internal, version-locked deployment contract. +/// Bump this when either peer can no longer honor the previous stream +/// semantics. +pub const SUPERVISOR_PROTOCOL_REVISION: u32 = 1; diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index 70ffb5fe5d..de221f67db 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -989,6 +989,18 @@ impl ComputeRuntime { } })?; + if let Err(status) = Box::pin(crate::grpc::policy::initialize_policy_history( + self.store.as_ref(), + &sandbox, + crate::grpc::policy::InitialPolicyHistoryStatus::Pending, + )) + .await + { + let _ = self.store.delete(Sandbox::object_type(), &sandbox_id).await; + self.sandbox_index.remove_sandbox(&sandbox_id); + return Err(status); + } + if let Some(token) = sandbox_token && let Some(spec) = driver_sandbox.spec.as_mut() { @@ -1026,6 +1038,10 @@ impl ComputeRuntime { Ok(sandbox) } Err(status) if status.code() == Code::AlreadyExists => { + let _ = self + .store + .delete_by_scope(POLICY_OBJECT_TYPE, sandbox.object_id()) + .await; let _ = self .store .delete(Sandbox::object_type(), sandbox.object_id()) @@ -1034,6 +1050,10 @@ impl ComputeRuntime { Err(Status::already_exists("sandbox already exists")) } Err(status) if status.code() == Code::FailedPrecondition => { + let _ = self + .store + .delete_by_scope(POLICY_OBJECT_TYPE, sandbox.object_id()) + .await; let _ = self .store .delete(Sandbox::object_type(), sandbox.object_id()) @@ -1042,6 +1062,10 @@ impl ComputeRuntime { Err(Status::failed_precondition(status.message().to_string())) } Err(err) => { + let _ = self + .store + .delete_by_scope(POLICY_OBJECT_TYPE, sandbox.object_id()) + .await; let _ = self .store .delete(Sandbox::object_type(), sandbox.object_id()) @@ -4938,6 +4962,7 @@ pub async fn new_test_runtime_with_driver( #[cfg(test)] mod tests { use super::*; + use crate::policy_store::PolicyStoreExt; use futures::stream; use openshell_core::proto::compute::v1::{ CreateSandboxResponse, DeleteSandboxResponse, GetCapabilitiesResponse, GetSandboxRequest, @@ -11240,6 +11265,36 @@ mod tests { ); } + #[tokio::test] + async fn create_sandbox_persists_initial_policy_revision() { + let runtime = test_runtime(Arc::new(TestDriver::default())).await; + let mut sandbox = sandbox_record( + "sb-initial-policy", + "initial-policy", + SandboxPhase::Provisioning, + ); + let policy = openshell_core::proto::SandboxPolicy::default(); + sandbox.spec = Some(SandboxSpec { + policy: Some(policy.clone()), + ..Default::default() + }); + + runtime.create_sandbox(sandbox, None, false).await.unwrap(); + + let revision = runtime + .store + .get_latest_policy("sb-initial-policy") + .await + .unwrap() + .expect("initial policy revision"); + assert_eq!(revision.version, 1); + assert_eq!( + revision.policy_hash, + crate::grpc::policy::deterministic_policy_hash(&policy) + ); + assert_eq!(revision.status, "pending"); + } + #[tokio::test] async fn created_sandbox_is_immediately_visible_to_label_selectors() { let runtime = test_runtime(Arc::new(TestDriver::default())).await; diff --git a/crates/openshell-server/src/config_delivery.rs b/crates/openshell-server/src/config_delivery.rs new file mode 100644 index 0000000000..99470ef7bc --- /dev/null +++ b/crates/openshell-server/src/config_delivery.rs @@ -0,0 +1,661 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Build and route complete supervisor configuration snapshots. + +use std::collections::HashMap; +use std::collections::hash_map::Entry; +use std::fmt; +use std::sync::{Arc, Mutex}; +use std::time::Duration; + +use metrics::counter; +use openshell_core::proto::{ + ConfigBootstrap, ProviderEnvironmentSnapshot, Sandbox, SandboxConfigSnapshot, +}; +use tonic::{Code, Status}; +use tracing::warn; + +use crate::ServerState; +use crate::grpc::policy::{build_provider_environment_snapshot, build_sandbox_config_snapshot}; +use crate::persistence::ObjectWorkspace; +use crate::supervisor_session::SupervisorSessionRegistry; + +/// Leaves headroom below tonic's default 4 MiB decode limit for framing and +/// future envelope fields. +pub const MAX_SUPERVISOR_CONFIG_MESSAGE_BYTES: usize = 3 * 1024 * 1024; +const CONFIG_SNAPSHOT_BUILD_TIMEOUT: Duration = Duration::from_secs(45); +const MAX_ACTIVE_FANOUT_WORKERS: usize = 64; + +/// One complete configuration component awaiting delivery to a supervisor. +#[derive(Clone)] +pub enum SupervisorConfigMessage { + SandboxConfig(Box), + ProviderEnvironment(ProviderEnvironmentSnapshot), +} + +impl SupervisorConfigMessage { + pub(crate) fn component_name(&self) -> &'static str { + match self { + Self::SandboxConfig(_) => "sandbox_config", + Self::ProviderEnvironment(_) => "provider_environment", + } + } +} + +impl fmt::Debug for SupervisorConfigMessage { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str(match self { + Self::SandboxConfig(_) => "SandboxConfig()", + Self::ProviderEnvironment(_) => "ProviderEnvironment()", + }) + } +} + +/// Result of routing one configuration snapshot toward a supervisor session. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DeliveryDisposition { + Enqueued, + NoActiveSession, + QueueFull, + SessionClosed, + PayloadTooLarge, +} + +/// Transport boundary for configuration delivery. +#[tonic::async_trait] +pub trait SupervisorConfigRouter: fmt::Debug + Send + Sync { + async fn deliver( + &self, + sandbox_id: &str, + message: SupervisorConfigMessage, + ) -> DeliveryDisposition; + + async fn routable_sandbox_ids(&self) -> Vec; +} + +#[derive(Debug)] +pub struct LocalSupervisorConfigRouter { + sessions: Arc, +} + +impl LocalSupervisorConfigRouter { + #[must_use] + pub fn new(sessions: Arc) -> Self { + Self { sessions } + } +} + +#[tonic::async_trait] +impl SupervisorConfigRouter for LocalSupervisorConfigRouter { + async fn deliver( + &self, + sandbox_id: &str, + message: SupervisorConfigMessage, + ) -> DeliveryDisposition { + self.sessions.deliver_config(sandbox_id, message) + } + + async fn routable_sandbox_ids(&self) -> Vec { + self.sessions.connected_sandbox_ids() + } +} + +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] +pub struct ConfigComponents { + pub sandbox_config: bool, + pub provider_environment: bool, +} + +impl ConfigComponents { + pub const ALL: Self = Self { + sandbox_config: true, + provider_environment: true, + }; + + pub const SANDBOX_AND_PROVIDER: Self = Self { + sandbox_config: true, + provider_environment: true, + }; + + pub const SANDBOX_CONFIG: Self = Self { + sandbox_config: true, + provider_environment: false, + }; + + fn selected(self) -> impl Iterator { + [ + (self.sandbox_config, ConfigComponentKind::SandboxConfig), + ( + self.provider_environment, + ConfigComponentKind::ProviderEnvironment, + ), + ] + .into_iter() + .filter_map(|(selected, component)| selected.then_some(component)) + } + + fn only(component: ConfigComponentKind) -> Self { + Self { + sandbox_config: component == ConfigComponentKind::SandboxConfig, + provider_environment: component == ConfigComponentKind::ProviderEnvironment, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum ConfigComponentKind { + SandboxConfig, + ProviderEnvironment, +} + +impl ConfigComponentKind { + fn name(self) -> &'static str { + match self { + Self::SandboxConfig => "sandbox_config", + Self::ProviderEnvironment => "provider_environment", + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct DeliveryKey { + sandbox_id: String, + component: ConfigComponentKind, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum FanoutScope { + Workspace(String), + AllConnected, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct FanoutKey { + scope: FanoutScope, + component: ConfigComponentKind, +} + +/// Coalesces publications and runs one worker per sandbox and component. +/// +/// The map entry is also the worker lease. Its boolean is set when another +/// mutation arrives during a build or route operation. The worker then rebuilds +/// the current full snapshot once, regardless of how many mutations arrived. +#[derive(Debug, Default)] +pub struct ConfigDeliveryQueue { + pending: Mutex>, + fanout_pending: Mutex>, +} + +impl ConfigDeliveryQueue { + fn enqueue(&self, key: DeliveryKey) -> bool { + let mut pending = self.pending.lock().unwrap(); + match pending.entry(key) { + Entry::Occupied(mut entry) => { + *entry.get_mut() = true; + false + } + Entry::Vacant(entry) => { + entry.insert(true); + true + } + } + } + + fn take(&self, key: &DeliveryKey) { + let mut pending = self.pending.lock().unwrap(); + if let Some(changed) = pending.get_mut(key) { + *changed = false; + } + } + + fn finish_pass(&self, key: &DeliveryKey) -> bool { + let mut pending = self.pending.lock().unwrap(); + if pending.get(key).is_some_and(|changed| !changed) { + pending.remove(key); + false + } else { + pending.contains_key(key) + } + } + + fn enqueue_fanout(&self, key: FanoutKey) -> FanoutEnqueue { + let mut pending = self.fanout_pending.lock().unwrap(); + if let Some(changed) = pending.get_mut(&key) { + *changed = true; + return FanoutEnqueue::Coalesced; + } + if pending.len() >= MAX_ACTIVE_FANOUT_WORKERS { + FanoutEnqueue::Full + } else { + pending.insert(key, true); + FanoutEnqueue::StartWorker + } + } + + fn take_fanout(&self, key: &FanoutKey) { + let mut pending = self.fanout_pending.lock().unwrap(); + if let Some(changed) = pending.get_mut(key) { + *changed = false; + } + } + + fn finish_fanout_pass(&self, key: &FanoutKey) -> bool { + let mut pending = self.fanout_pending.lock().unwrap(); + if pending.get(key).is_some_and(|changed| !changed) { + pending.remove(key); + false + } else { + pending.contains_key(key) + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum FanoutEnqueue { + StartWorker, + Coalesced, + Full, +} + +pub async fn build_config_bootstrap( + state: &Arc, + sandbox: &Sandbox, +) -> Result { + tokio::time::timeout( + CONFIG_SNAPSHOT_BUILD_TIMEOUT, + build_consistent_config_bootstrap(state, sandbox), + ) + .await + .map_err(|_| Status::deadline_exceeded("supervisor configuration bootstrap timed out"))? +} + +async fn build_consistent_config_bootstrap( + state: &Arc, + sandbox: &Sandbox, +) -> Result { + const MAX_BUILD_ATTEMPTS: usize = 3; + for _ in 0..MAX_BUILD_ATTEMPTS { + // Components are independent projections. The provider revision is a + // fence for the only overlapping input between sandbox configuration + // and provider environment state. + let (sandbox_config, provider_environment) = tokio::join!( + build_sandbox_config_snapshot(state, sandbox), + build_provider_environment_snapshot(state, sandbox, true), + ); + let bootstrap = ConfigBootstrap { + sandbox_config: Some(sandbox_config?), + provider_environment: Some(provider_environment?), + }; + if bootstrap_revisions_match(&bootstrap) { + return Ok(bootstrap); + } + counter!("openshell_supervisor_config_bootstrap_revision_mismatches_total").increment(1); + } + Err(Status::aborted( + "configuration changed while building supervisor bootstrap", + )) +} + +fn bootstrap_revisions_match(bootstrap: &ConfigBootstrap) -> bool { + bootstrap + .sandbox_config + .as_ref() + .zip(bootstrap.provider_environment.as_ref()) + .is_some_and(|(sandbox, provider)| { + sandbox.provider_env_revision == provider.provider_env_revision + }) +} + +pub fn publish_sandbox_components( + state: &Arc, + sandbox_id: &str, + components: ConfigComponents, +) { + enqueue_sandbox(state, sandbox_id, components); +} + +fn enqueue_sandbox(state: &Arc, sandbox_id: &str, components: ConfigComponents) { + for component in components.selected() { + let key = DeliveryKey { + sandbox_id: sandbox_id.to_string(), + component, + }; + if state.config_delivery_queue.enqueue(key.clone()) { + let state = Arc::clone(state); + tokio::spawn(async move { + loop { + state.config_delivery_queue.take(&key); + publish_sandbox_component_now(&state, &key).await; + if !state.config_delivery_queue.finish_pass(&key) { + break; + } + } + }); + } + } +} + +async fn publish_sandbox_component_now(state: &Arc, key: &DeliveryKey) { + let sandbox = match state.store.get_message::(&key.sandbox_id).await { + Ok(Some(sandbox)) => sandbox, + Ok(None) => return, + Err(_) => { + record_build_failure(&key.sandbox_id, "sandbox", Code::Internal); + return; + } + }; + let component = key.component.name(); + let build = async { + match key.component { + ConfigComponentKind::SandboxConfig => build_sandbox_config_snapshot(state, &sandbox) + .await + .map(|snapshot| SupervisorConfigMessage::SandboxConfig(Box::new(snapshot))), + ConfigComponentKind::ProviderEnvironment => { + build_provider_environment_snapshot(state, &sandbox, true) + .await + .map(SupervisorConfigMessage::ProviderEnvironment) + } + } + }; + match tokio::time::timeout(CONFIG_SNAPSHOT_BUILD_TIMEOUT, build).await { + Ok(Ok(message)) => { + let disposition = state + .supervisor_config_router() + .deliver(&key.sandbox_id, message) + .await; + record_delivery(component, disposition); + } + Ok(Err(error)) => { + record_build_failure(&key.sandbox_id, component, error.code()); + } + Err(_) => { + record_build_failure(&key.sandbox_id, component, Code::DeadlineExceeded); + } + } +} + +pub fn publish_workspace_components( + state: &Arc, + workspace: &str, + components: ConfigComponents, +) { + enqueue_fanout( + state, + FanoutScope::Workspace(workspace.to_string()), + components, + ); +} + +pub fn publish_all_connected(state: &Arc, components: ConfigComponents) { + enqueue_fanout(state, FanoutScope::AllConnected, components); +} + +fn enqueue_fanout(state: &Arc, scope: FanoutScope, components: ConfigComponents) { + for component in components.selected() { + let key = FanoutKey { + scope: scope.clone(), + component, + }; + match state.config_delivery_queue.enqueue_fanout(key.clone()) { + FanoutEnqueue::StartWorker => { + let state = Arc::clone(state); + tokio::spawn(async move { + loop { + state.config_delivery_queue.take_fanout(&key); + publish_fanout_now(&state, &key).await; + if !state.config_delivery_queue.finish_fanout_pass(&key) { + break; + } + } + }); + } + FanoutEnqueue::Coalesced => {} + FanoutEnqueue::Full => { + counter!("openshell_supervisor_config_fanout_total", "outcome" => "queue_full") + .increment(1); + warn!( + component = component.name(), + "supervisor configuration fanout queue is full" + ); + } + } + } +} + +async fn publish_fanout_now(state: &Arc, key: &FanoutKey) { + let sandbox_ids = state + .supervisor_config_router() + .routable_sandbox_ids() + .await; + for sandbox_id in sandbox_ids { + if let FanoutScope::Workspace(workspace) = &key.scope { + let sandbox = match state.store.get_message::(&sandbox_id).await { + Ok(Some(sandbox)) => sandbox, + Ok(None) => continue, + Err(_) => { + record_build_failure(&sandbox_id, "sandbox", Code::Internal); + continue; + } + }; + if sandbox.object_workspace() != workspace { + continue; + } + } + enqueue_sandbox(state, &sandbox_id, ConfigComponents::only(key.component)); + } +} + +fn record_delivery(component: &'static str, disposition: DeliveryDisposition) { + let outcome = match disposition { + DeliveryDisposition::Enqueued => "enqueued", + DeliveryDisposition::NoActiveSession => "no_active_session", + DeliveryDisposition::QueueFull => "queue_full", + DeliveryDisposition::SessionClosed => "session_closed", + DeliveryDisposition::PayloadTooLarge => "payload_too_large", + }; + counter!( + "openshell_supervisor_config_deliveries_total", + "component" => component, + "outcome" => outcome, + ) + .increment(1); +} + +fn record_build_failure(sandbox_id: &str, component: &'static str, error_code: Code) { + counter!( + "openshell_supervisor_config_snapshot_failures_total", + "component" => component, + ) + .increment(1); + warn!( + sandbox_id = %sandbox_id, + component, + ?error_code, + "failed to build supervisor configuration snapshot" + ); +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::grpc::{OpenShellService, test_support::test_server_state}; + use openshell_core::proto::{ + GatewayMessage, ObjectMeta, SandboxSpec, SupervisorHello, SupervisorMessage, + gateway_message, open_shell_client::OpenShellClient, open_shell_server::OpenShellServer, + supervisor_message, + }; + use tokio::sync::mpsc; + use tokio_stream::wrappers::{ReceiverStream, TcpListenerStream}; + + fn key(sandbox_id: &str, component: ConfigComponentKind) -> DeliveryKey { + DeliveryKey { + sandbox_id: sandbox_id.to_string(), + component, + } + } + + #[test] + fn queue_coalesces_repeated_component_changes_while_worker_is_active() { + let queue = ConfigDeliveryQueue::default(); + let key = key("sb-1", ConfigComponentKind::SandboxConfig); + assert!(queue.enqueue(key.clone())); + queue.take(&key); + assert!(!queue.enqueue(key.clone())); + assert!(!queue.enqueue(key.clone())); + assert!(queue.finish_pass(&key)); + queue.take(&key); + assert!(!queue.finish_pass(&key)); + } + + #[test] + fn queue_runs_components_and_sandboxes_independently() { + let queue = ConfigDeliveryQueue::default(); + assert!(queue.enqueue(key("sb-1", ConfigComponentKind::SandboxConfig))); + assert!(queue.enqueue(key("sb-1", ConfigComponentKind::ProviderEnvironment))); + assert!(queue.enqueue(key("sb-2", ConfigComponentKind::SandboxConfig))); + } + + #[test] + fn fanout_queue_coalesces_and_bounds_distinct_scopes() { + let queue = ConfigDeliveryQueue::default(); + let first = FanoutKey { + scope: FanoutScope::Workspace("workspace-0".into()), + component: ConfigComponentKind::SandboxConfig, + }; + assert_eq!( + queue.enqueue_fanout(first.clone()), + FanoutEnqueue::StartWorker + ); + queue.take_fanout(&first); + assert_eq!( + queue.enqueue_fanout(first.clone()), + FanoutEnqueue::Coalesced + ); + assert!(queue.finish_fanout_pass(&first)); + + for index in 1..MAX_ACTIVE_FANOUT_WORKERS { + assert_eq!( + queue.enqueue_fanout(FanoutKey { + scope: FanoutScope::Workspace(format!("workspace-{index}")), + component: ConfigComponentKind::SandboxConfig, + }), + FanoutEnqueue::StartWorker + ); + } + assert_eq!( + queue.enqueue_fanout(FanoutKey { + scope: FanoutScope::Workspace("overflow".into()), + component: ConfigComponentKind::SandboxConfig, + }), + FanoutEnqueue::Full + ); + } + + #[test] + fn configuration_message_debug_output_redacts_payloads() { + let message = SupervisorConfigMessage::ProviderEnvironment(ProviderEnvironmentSnapshot { + values: vec![openshell_core::proto::ProviderEnvironmentValue { + name: "TOKEN".into(), + value: "secret-marker".into(), + ..Default::default() + }], + ..Default::default() + }); + assert!(!format!("{message:?}").contains("secret-marker")); + } + + #[tokio::test] + async fn session_acceptance_precedes_live_configuration_updates() { + let state = test_server_state().await; + state + .store + .put_message(&Sandbox { + metadata: Some(ObjectMeta { + id: "sandbox".into(), + name: "sandbox".into(), + workspace: "default".into(), + ..Default::default() + }), + spec: Some(SandboxSpec::default()), + ..Default::default() + }) + .await + .unwrap(); + + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let address = listener.local_addr().unwrap(); + let server = tokio::spawn( + tonic::transport::Server::builder() + .add_service(OpenShellServer::new(OpenShellService::new(Arc::clone( + &state, + )))) + .serve_with_incoming(TcpListenerStream::new(listener)), + ); + let mut client = OpenShellClient::connect(format!("http://{address}")) + .await + .unwrap(); + let (tx, rx) = mpsc::channel(4); + tx.send(SupervisorMessage { + payload: Some(supervisor_message::Payload::Hello(SupervisorHello { + sandbox_id: "sandbox".into(), + instance_id: "instance".into(), + protocol_revision: openshell_core::proto::SUPERVISOR_PROTOCOL_REVISION, + })), + }) + .await + .unwrap(); + let mut stream = client + .connect_supervisor(ReceiverStream::new(rx)) + .await + .unwrap() + .into_inner(); + + let first = tokio::time::timeout(Duration::from_secs(5), stream.message()) + .await + .unwrap() + .unwrap() + .unwrap(); + assert!(matches!( + first.payload, + Some(gateway_message::Payload::SessionAccepted(_)) + )); + + publish_sandbox_components(&state, "sandbox", ConfigComponents::SANDBOX_CONFIG); + let update = tokio::time::timeout(Duration::from_secs(5), stream.message()) + .await + .unwrap() + .unwrap() + .unwrap(); + assert!(matches!( + update, + GatewayMessage { + payload: Some(gateway_message::Payload::ConfigUpdate(_)) + } + )); + + drop(tx); + server.abort(); + } + + #[test] + fn bootstrap_requires_matching_provider_revision_fence() { + let mut bootstrap = ConfigBootstrap { + sandbox_config: Some(SandboxConfigSnapshot { + provider_env_revision: 7, + ..Default::default() + }), + provider_environment: Some(ProviderEnvironmentSnapshot { + provider_env_revision: 8, + ..Default::default() + }), + }; + assert!(!bootstrap_revisions_match(&bootstrap)); + bootstrap + .provider_environment + .as_mut() + .unwrap() + .provider_env_revision = 7; + assert!(bootstrap_revisions_match(&bootstrap)); + } +} diff --git a/crates/openshell-server/src/grpc/policy.rs b/crates/openshell-server/src/grpc/policy.rs index 814ee1b567..8df376d971 100644 --- a/crates/openshell-server/src/grpc/policy.rs +++ b/crates/openshell-server/src/grpc/policy.rs @@ -29,6 +29,8 @@ use crate::storage_proto::StoredProviderCredentialRefreshState; #[cfg(test)] use crate::storage_proto::StoredProviderProfile; use openshell_core::net::{is_always_blocked_ip, is_internal_ip}; +#[cfg(test)] +use openshell_core::proto::StaticCredentialBinding; use openshell_core::proto::policy_merge_operation; use openshell_core::proto::setting_value; use openshell_core::proto::{ @@ -42,11 +44,12 @@ use openshell_core::proto::{ GetSandboxPolicyStatusRequest, GetSandboxPolicyStatusResponse, GetSandboxProviderEnvironmentRequest, GetSandboxProviderEnvironmentResponse, ListSandboxPoliciesRequest, ListSandboxPoliciesResponse, PolicyChunk, PolicyMergeOperation, - PolicySource, PolicyStatus, PushSandboxLogsRequest, PushSandboxLogsResponse, + PolicySource, PolicyStatus, ProviderEnvironmentSnapshot, ProviderEnvironmentValue, + ProviderEnvironmentValueClassification, PushSandboxLogsRequest, PushSandboxLogsResponse, RejectDraftChunkRequest, RejectDraftChunkResponse, ReportPolicyStatusRequest, - ReportPolicyStatusResponse, SandboxLogLine, SandboxPolicyRevision, SettingScope, SettingValue, - SubmitPolicyAnalysisRequest, SubmitPolicyAnalysisResponse, UndoDraftChunkRequest, - UndoDraftChunkResponse, UpdateConfigRequest, UpdateConfigResponse, + ReportPolicyStatusResponse, SandboxConfigSnapshot, SandboxLogLine, SandboxPolicyRevision, + SettingScope, SettingValue, SubmitPolicyAnalysisRequest, SubmitPolicyAnalysisResponse, + UndoDraftChunkRequest, UndoDraftChunkResponse, UpdateConfigRequest, UpdateConfigResponse, }; use openshell_core::proto::{ L7DenyRule, L7Rule, NetworkBinary, NetworkEndpoint, NetworkPolicyRule, Provider, Sandbox, @@ -1538,6 +1541,11 @@ async fn auto_approve_chunk( return Err(status); } }; + crate::config_delivery::publish_sandbox_components( + state, + sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); let chunk_summary = summarize_draft_chunk_rule(&chunk)?; let now_ms = current_time_ms(); @@ -2374,6 +2382,18 @@ pub(super) async fn handle_get_sandbox_config( let sandbox = super::sandbox::fetch_and_authorize_sandbox(state, &principal, &sandbox_id).await?; + let snapshot = build_sandbox_config_snapshot(state, &sandbox).await?; + Ok(Response::new(sandbox_config_response(snapshot))) +} + +/// Build the complete effective configuration for one persisted sandbox. +/// +/// This is a read-only projection shared by polling and stream delivery. +pub async fn build_sandbox_config_snapshot( + state: &Arc, + sandbox: &Sandbox, +) -> Result { + let sandbox_id = sandbox.object_id().to_string(); let workspace = sandbox.object_workspace().to_string(); let sandbox_provider_names = sandbox .spec @@ -2398,87 +2418,49 @@ pub(super) async fn handle_get_sandbox_config( .await .map_err(|e| Status::internal(format!("fetch policy history failed: {e}")))?; - let (mut policy, version, mut policy_hash, policy_source) = if let Some(global_policy) = - global_policy - { - let version = latest - .as_ref() - .map(|record| u32::try_from(record.version).unwrap_or(0)) - .filter(|version| *version > 0) - .unwrap_or(1); - let hash = deterministic_policy_hash(&global_policy); - (Some(global_policy), version, hash, PolicySource::Global) - } else if let Some(record) = latest { - let (policy, hash) = canonical_policy_record_identity(&record)?; - debug!( - sandbox_id = %sandbox_id, - version = record.version, - "GetSandboxConfig served from policy history" - ); - ( - Some(policy), - u32::try_from(record.version).unwrap_or(0), - hash, - PolicySource::Sandbox, - ) - } else { - // Lazy backfill: no policy history exists yet. - let spec = sandbox - .spec - .as_ref() - .ok_or_else(|| Status::internal("sandbox has no spec"))?; - - match spec.policy.clone() { - None => { - debug!( - sandbox_id = %sandbox_id, - "GetSandboxConfig: no policy configured, returning empty response" - ); - (None, 0, String::new(), PolicySource::Sandbox) - } - Some(spec_policy) => { - // Stored specs may predate the current schema. Validate before - // creating policy history so malformed state is never copied or - // marked loaded, and hash the canonical representation. - let spec_policy = validate_and_canonicalize_stored_policy( - spec_policy, - STORED_POLICY_SOURCE_SPEC, - )?; - let hash = deterministic_policy_hash(&spec_policy); - let payload = spec_policy.encode_to_vec(); - let policy_id = uuid::Uuid::new_v4().to_string(); - - if let Err(e) = state - .store - .put_policy_revision(&policy_id, &sandbox_id, &workspace, 1, &payload, &hash) - .await - { - warn!( - sandbox_id = %sandbox_id, - error = %e, - "Failed to backfill policy version 1" - ); - } else if let Err(e) = state - .store - .update_policy_status(&sandbox_id, 1, "loaded", None, None) - .await - { - warn!( - sandbox_id = %sandbox_id, - error = %e, - "Failed to mark backfilled policy as loaded" - ); + let (mut policy, version, mut policy_hash, policy_source) = + if let Some(global_policy) = global_policy { + let version = latest + .as_ref() + .map(|record| u32::try_from(record.version).unwrap_or(0)) + .filter(|version| *version > 0) + .unwrap_or(1); + let hash = deterministic_policy_hash(&global_policy); + (Some(global_policy), version, hash, PolicySource::Global) + } else if let Some(record) = latest { + let (policy, hash) = canonical_policy_record_identity(&record)?; + debug!( + sandbox_id = %sandbox_id, + version = record.version, + "GetSandboxConfig served from policy history" + ); + ( + Some(policy), + u32::try_from(record.version).unwrap_or(0), + hash, + PolicySource::Sandbox, + ) + } else { + // Older sandboxes may have policy only in the sandbox spec. Reading a + // snapshot must not create policy history, so project that baseline as + // version 1 until the startup repair persists it. + let spec = sandbox + .spec + .as_ref() + .ok_or_else(|| Status::internal("sandbox has no spec"))?; + + match spec.policy.clone() { + None => (None, 0, String::new(), PolicySource::Sandbox), + Some(spec_policy) => { + let spec_policy = validate_and_canonicalize_stored_policy( + spec_policy, + STORED_POLICY_SOURCE_SPEC, + )?; + let hash = deterministic_policy_hash(&spec_policy); + (Some(spec_policy), 1, hash, PolicySource::Sandbox) } - - info!( - sandbox_id = %sandbox_id, - "GetSandboxConfig served from spec (backfilled version 1)" - ); - - (Some(spec_policy), 1, hash, PolicySource::Sandbox) } - } - }; + }; let global_settings = load_global_settings(state.store.as_ref()).await?; let sandbox_settings = @@ -2585,7 +2567,7 @@ pub(super) async fn handle_get_sandbox_config( ) .await?; - Ok(Response::new(GetSandboxConfigResponse { + Ok(SandboxConfigSnapshot { policy, version, policy_hash, @@ -2602,7 +2584,112 @@ pub(super) async fn handle_get_sandbox_config( .as_str() .to_string(), extension_authentication_enabled: state.sandbox_jwt_issuer.is_some(), - })) + }) +} + +fn sandbox_config_response(snapshot: SandboxConfigSnapshot) -> GetSandboxConfigResponse { + GetSandboxConfigResponse { + policy: snapshot.policy, + version: snapshot.version, + policy_hash: snapshot.policy_hash, + settings: snapshot.settings, + config_revision: snapshot.config_revision, + policy_source: snapshot.policy_source, + global_policy_version: snapshot.global_policy_version, + provider_env_revision: snapshot.provider_env_revision, + supervisor_middleware_services: snapshot.supervisor_middleware_services, + workspace: snapshot.workspace, + policy_validation_failure_mode: snapshot.policy_validation_failure_mode, + extension_authentication_enabled: snapshot.extension_authentication_enabled, + } +} + +#[derive(Clone, Copy)] +pub enum InitialPolicyHistoryStatus { + Pending, + Loaded, +} + +impl InitialPolicyHistoryStatus { + fn as_str(self) -> &'static str { + match self { + Self::Pending => "pending", + Self::Loaded => "loaded", + } + } +} + +/// Insert the version-one policy baseline if this sandbox still has no policy +/// history. This never modifies an existing revision or apply result. +pub async fn initialize_policy_history( + store: &Store, + sandbox: &Sandbox, + status: InitialPolicyHistoryStatus, +) -> Result<(), Status> { + let Some(policy) = sandbox.spec.as_ref().and_then(|spec| spec.policy.as_ref()) else { + return Ok(()); + }; + if store + .get_latest_policy(sandbox.object_id()) + .await + .map_err(|error| Status::internal(format!("read policy history failed: {error}")))? + .is_some() + { + return Ok(()); + } + let policy = + validate_and_canonicalize_stored_policy(policy.clone(), STORED_POLICY_SOURCE_SPEC)?; + store + .put_initial_policy_revision( + &PolicyRecord { + id: uuid::Uuid::new_v4().to_string(), + sandbox_id: sandbox.object_id().to_string(), + version: 1, + policy_payload: policy.encode_to_vec(), + policy_hash: deterministic_policy_hash(&policy), + status: status.as_str().to_string(), + load_error: None, + created_at_ms: current_time_ms(), + loaded_at_ms: None, + provenance: HashMap::new(), + }, + sandbox.object_workspace(), + ) + .await + .map_err(|error| Status::internal(format!("initialize policy history failed: {error}"))) +} + +/// Create policy-history baselines for sandboxes written by older gateways. +/// +/// Snapshot reads stay pure once this startup repair has completed. +pub async fn backfill_legacy_policy_history(state: &Arc) -> Result<(), Status> { + const PAGE_SIZE: u32 = 1000; + let mut offset = 0; + loop { + let sandboxes = state + .store + .list_all_messages::(PAGE_SIZE, offset) + .await + .map_err(|error| { + Status::internal(format!("list sandboxes for policy repair failed: {error}")) + })?; + if sandboxes.is_empty() { + return Ok(()); + } + let count = u32::try_from(sandboxes.len()).unwrap_or(PAGE_SIZE); + for sandbox in sandboxes { + initialize_policy_history( + state.store.as_ref(), + &sandbox, + InitialPolicyHistoryStatus::Loaded, + ) + .await?; + } + if count < PAGE_SIZE { + return Ok(()); + } + offset = offset.saturating_add(count); + } } #[cfg(test)] @@ -3105,6 +3192,19 @@ pub(super) async fn handle_get_sandbox_provider_environment( .await .map_err(|e| Status::internal(format!("fetch sandbox failed: {e}")))? .ok_or_else(|| Status::not_found("sandbox not found"))?; + let snapshot = + build_provider_environment_snapshot(state, &sandbox, supports_static_credential_bindings) + .await?; + Ok(Response::new(provider_environment_response(snapshot))) +} + +/// Build the complete provider environment for one persisted sandbox. +pub async fn build_provider_environment_snapshot( + state: &Arc, + sandbox: &Sandbox, + supports_static_credential_bindings: bool, +) -> Result { + let sandbox_id = sandbox.object_id().to_string(); let workspace = sandbox.object_workspace().to_string(); let spec = sandbox @@ -3127,7 +3227,7 @@ pub(super) async fn handle_get_sandbox_provider_environment( state.as_ref(), &provider_profile_catalog, &workspace, - &sandbox, + sandbox, &sandbox_id, ) .await?; @@ -3192,21 +3292,81 @@ pub(super) async fn handle_get_sandbox_provider_environment( "GetSandboxProviderEnvironment request completed successfully" ); - let non_secret_environment_keys = provider_environment + let mut keys = provider_environment .environment .keys() - .filter(|key| !provider_environment.static_credential_keys.contains(*key)) .cloned() - .collect(); + .collect::>(); + keys.sort(); + let mut values = Vec::with_capacity(keys.len()); + for name in keys { + let value = provider_environment + .environment + .remove(&name) + .expect("provider environment key came from the same map"); + let is_static_credential = provider_environment.static_credential_keys.contains(&name); + let static_credential_binding = provider_environment + .static_credential_bindings + .remove(&name); + if is_static_credential && static_credential_binding.is_none() { + return Err(Status::failed_precondition(format!( + "static provider credential '{name}' has no endpoint binding" + ))); + } + values.push(ProviderEnvironmentValue { + name: name.clone(), + value, + expires_at_ms: provider_environment.credential_expires_at_ms.remove(&name), + classification: if is_static_credential { + ProviderEnvironmentValueClassification::StaticCredential.into() + } else { + ProviderEnvironmentValueClassification::NonSecret.into() + }, + static_credential_binding, + }); + } - Ok(Response::new(GetSandboxProviderEnvironmentResponse { - environment: provider_environment.environment, + Ok(ProviderEnvironmentSnapshot { provider_env_revision, - credential_expires_at_ms: provider_environment.credential_expires_at_ms, + values, dynamic_credentials: provider_environment.dynamic_credentials, - static_credential_bindings: provider_environment.static_credential_bindings, + }) +} + +fn provider_environment_response( + snapshot: ProviderEnvironmentSnapshot, +) -> GetSandboxProviderEnvironmentResponse { + let mut environment = HashMap::with_capacity(snapshot.values.len()); + let mut credential_expires_at_ms = HashMap::new(); + let mut static_credential_bindings = HashMap::new(); + let mut non_secret_environment_keys = Vec::new(); + for value in snapshot.values { + environment.insert(value.name.clone(), value.value); + if let Some(expires_at_ms) = value.expires_at_ms { + credential_expires_at_ms.insert(value.name.clone(), expires_at_ms); + } + match ProviderEnvironmentValueClassification::try_from(value.classification) + .unwrap_or_default() + { + ProviderEnvironmentValueClassification::NonSecret => { + non_secret_environment_keys.push(value.name); + } + ProviderEnvironmentValueClassification::StaticCredential => { + if let Some(binding) = value.static_credential_binding { + static_credential_bindings.insert(value.name, binding); + } + } + ProviderEnvironmentValueClassification::Unspecified => {} + } + } + GetSandboxProviderEnvironmentResponse { + environment, + provider_env_revision: snapshot.provider_env_revision, + credential_expires_at_ms, + dynamic_credentials: snapshot.dynamic_credentials, + static_credential_bindings, non_secret_environment_keys, - })) + } } // --------------------------------------------------------------------------- @@ -3358,6 +3518,10 @@ async fn handle_update_config_inner( if changed { global_settings.revision = global_settings.revision.wrapping_add(1); save_global_settings(state.store.as_ref(), &global_settings).await?; + crate::config_delivery::publish_all_connected( + state, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); } return Ok(update_config_response( u32::try_from(current.version).unwrap_or(0), @@ -3414,6 +3578,10 @@ async fn handle_update_config_inner( if changed { global_settings.revision = global_settings.revision.wrapping_add(1); save_global_settings(state.store.as_ref(), &global_settings).await?; + crate::config_delivery::publish_all_connected( + state, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); } return Ok(update_config_response( @@ -3458,6 +3626,10 @@ async fn handle_update_config_inner( global_settings.revision = global_settings.revision.wrapping_add(1); save_global_settings(state.store.as_ref(), &global_settings).await?; + crate::config_delivery::publish_all_connected( + state, + crate::config_delivery::ConfigComponents::SANDBOX_CONFIG, + ); if req.delete_setting && key == POLICY_SETTING_KEY @@ -3530,6 +3702,11 @@ async fn handle_update_config_inner( &sandbox_settings, ) .await?; + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_CONFIG, + ); } response_annotations = persist_update_config_annotations( @@ -3574,6 +3751,11 @@ async fn handle_update_config_inner( &sandbox_settings, ) .await?; + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_CONFIG, + ); } response_annotations = persist_update_config_annotations( @@ -3632,6 +3814,11 @@ async fn handle_update_config_inner( Some(&atomic_context), ) .await?; + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); response_annotations = if let Some(updated_sandbox) = updated_sandbox { sandbox_metadata_annotations(&updated_sandbox) } else { @@ -3851,6 +4038,11 @@ async fn handle_update_config_inner( })? }; response_annotations = committed_annotations; + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); state.sandbox_watch_bus.notify(&sandbox_id); if backfill_policy.is_some() { @@ -3897,6 +4089,12 @@ async fn handle_update_config_inner( .await .map_err(|e| Status::internal(format!("persist policy revision failed: {e}")))?; + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); + let _ = state .store .supersede_older_policies(&sandbox_id, next_version) @@ -4891,6 +5089,11 @@ async fn handle_approve_draft_chunk_inner( return Err(status); } }; + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); let chunk_summary = summarize_draft_chunk_rule(&chunk)?; let now_ms = current_time_ms(); @@ -5015,6 +5218,11 @@ async fn handle_reject_draft_chunk_inner( require_no_global_policy(state).await?; let (version, hash) = remove_chunk_from_policy(state, &sandbox_id, &workspace, &chunk).await?; + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); emit_gateway_policy_audit_log( &sandbox_id, sandbox.object_name(), @@ -5306,6 +5514,14 @@ async fn handle_approve_all_draft_chunks_inner( } }; + if !accepted.is_empty() { + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); + } + for (chunk, _, chunk_summary) in &accepted { let now_ms = current_time_ms(); clear_pending_application_error(state, &chunk.id).await; @@ -5507,6 +5723,11 @@ async fn handle_undo_draft_chunk_inner( ); let (version, hash) = remove_chunk_from_policy(state, &sandbox_id, &workspace, &chunk).await?; + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); // Clear any prior rejection_reason on the way back to "pending" so an // agent reading the chunk via policy.local cannot see a stale guidance @@ -5862,7 +6083,7 @@ fn canonical_policy_bytes(policy: &ProtoSandboxPolicy) -> Vec { /// Compute a deterministic SHA-256 hash of a `SandboxPolicy`, recursively /// sorting every protobuf map while preserving repeated-field order. -fn deterministic_policy_hash(policy: &ProtoSandboxPolicy) -> String { +pub fn deterministic_policy_hash(policy: &ProtoSandboxPolicy) -> String { hex::encode(Sha256::digest(canonical_policy_bytes(policy))) } @@ -7438,7 +7659,7 @@ mod tests { } #[tokio::test] - async fn get_sandbox_config_backfills_canonical_spec_policy_bytes_and_hash() { + async fn startup_repair_backfills_canonical_spec_policy_bytes_and_hash() { let state = test_server_state().await; let sandbox_id = "stored-canonical-backfill"; let raw = mcp_policy_with_versions(&["2025-11-25", "2025-03-26", "2025-06-18"]); @@ -7473,6 +7694,15 @@ mod tests { assert_eq!(response.policy_hash, canonical_hash); assert_eq!(response.version, 1); + assert!( + state + .store + .get_latest_policy(sandbox_id) + .await + .unwrap() + .is_none() + ); + backfill_legacy_policy_history(&state).await.unwrap(); let persisted = state .store .get_latest_policy(sandbox_id) @@ -7485,7 +7715,7 @@ mod tests { } #[tokio::test] - async fn get_sandbox_config_backfills_defaulted_mcp_policy_as_canonical_bytes_and_hash() { + async fn startup_repair_backfills_defaulted_mcp_policy_as_canonical_bytes_and_hash() { let state = test_server_state().await; let canonical = validate_and_canonicalize_policy(mcp_policy_with_versions(&["2025-11-25"])) .expect("explicit default MCP policy must canonicalize"); @@ -7531,6 +7761,15 @@ mod tests { "{case}" ); + assert!( + state + .store + .get_latest_policy(&sandbox_id) + .await + .unwrap() + .is_none() + ); + backfill_legacy_policy_history(&state).await.unwrap(); let persisted = state .store .get_latest_policy(&sandbox_id) @@ -10594,6 +10833,114 @@ mod tests { ); } + #[tokio::test] + async fn rejected_policy_update_does_not_publish_configuration() { + let state = test_server_state().await; + let mut sandbox = test_sandbox( + "sb-rejected-policy", + "rejected-policy", + ProtoSandboxPolicy::default(), + Vec::new(), + ); + sandbox.spec.as_mut().unwrap().policy = None; + state.store.put_message(&sandbox).await.unwrap(); + + let (tx, mut rx) = tokio::sync::mpsc::channel(1); + let (shutdown_tx, _shutdown_rx) = tokio::sync::oneshot::channel(); + state.supervisor_sessions.register( + "sb-rejected-policy".to_string(), + "session-1".to_string(), + tx, + shutdown_tx, + ); + + let error = handle_update_config( + &state, + with_user(Request::new(UpdateConfigRequest { + name: "rejected-policy".to_string(), + workspace: "default".to_string(), + policy: Some(test_policy_with_rule("rejected", "api.example.com")), + expected_resource_version: u64::MAX, + ..Default::default() + })), + ) + .await + .expect_err("stale resource version must reject the update"); + + assert_eq!(error.code(), Code::Aborted); + assert!(rx.try_recv().is_err()); + assert!( + state + .store + .get_latest_policy("sb-rejected-policy") + .await + .unwrap() + .is_none() + ); + } + + #[tokio::test] + async fn committed_policy_update_publishes_complete_snapshot() { + let state = test_server_state().await; + let mut sandbox = test_sandbox( + "sb-published-policy", + "published-policy", + ProtoSandboxPolicy::default(), + Vec::new(), + ); + sandbox.spec.as_mut().unwrap().policy = None; + state.store.put_message(&sandbox).await.unwrap(); + + let (tx, mut rx) = tokio::sync::mpsc::channel(4); + let (shutdown_tx, _shutdown_rx) = tokio::sync::oneshot::channel(); + state.supervisor_sessions.register( + "sb-published-policy".to_string(), + "session-1".to_string(), + tx, + shutdown_tx, + ); + + handle_update_config( + &state, + with_user(Request::new(UpdateConfigRequest { + name: "published-policy".to_string(), + workspace: "default".to_string(), + policy: Some(test_policy_with_rule("published", "api.example.com")), + ..Default::default() + })), + ) + .await + .unwrap(); + + let persisted = state + .store + .get_latest_policy("sb-published-policy") + .await + .unwrap() + .expect("committed policy"); + let snapshot = tokio::time::timeout(std::time::Duration::from_secs(2), async { + loop { + let message = rx.recv().await.expect("configuration channel closed"); + let Some(openshell_core::proto::gateway_message::Payload::ConfigUpdate(update)) = + message.payload + else { + panic!("expected ConfigUpdate"); + }; + if let Some(openshell_core::proto::config_update::Component::SandboxConfig( + snapshot, + )) = update.component + { + break snapshot; + } + } + }) + .await + .expect("configuration publication timed out"); + assert_eq!(snapshot.version, u32::try_from(persisted.version).unwrap()); + assert_eq!(snapshot.policy_hash, persisted.policy_hash); + assert!(snapshot.policy.is_some()); + } + #[tokio::test] async fn update_config_accepts_sigv4_covered_by_endpointful_aws_profile() { let state = test_server_state().await; @@ -10921,23 +11268,68 @@ mod tests { .contains_key("_provider_work_github") ); - let persisted = state + assert!( + state + .store + .get_latest_policy("sb-jit") + .await + .unwrap() + .is_none(), + "snapshot reads must not create policy history" + ); + } + + #[tokio::test] + async fn legacy_policy_history_repair_is_idempotent() { + let state = test_server_state().await; + let policy = test_policy_with_rule("legacy", "legacy.example.com"); + state + .store + .put_message(&test_sandbox( + "sb-legacy-policy", + "legacy-policy", + policy.clone(), + Vec::new(), + )) + .await + .unwrap(); + + backfill_legacy_policy_history(&state).await.unwrap(); + let initial = state .store - .get_latest_policy("sb-jit") + .get_latest_policy("sb-legacy-policy") .await .unwrap() - .expect("sandbox policy should be lazily backfilled"); - let persisted_policy = ProtoSandboxPolicy::decode(persisted.policy_payload.as_slice()) - .expect("persisted sandbox policy should decode"); - assert!( - persisted_policy - .network_policies - .contains_key("sandbox_only") + .expect("legacy policy baseline"); + assert_eq!(initial.status, "loaded"); + state + .store + .update_policy_status("sb-legacy-policy", 1, "failed", Some("apply failed"), None) + .await + .unwrap(); + + backfill_legacy_policy_history(&state).await.unwrap(); + let repaired_again = state + .store + .get_latest_policy("sb-legacy-policy") + .await + .unwrap() + .expect("legacy policy baseline"); + assert_eq!(repaired_again.version, 1); + assert_eq!( + repaired_again.policy_hash, + deterministic_policy_hash(&policy) ); - assert!( - !persisted_policy - .network_policies - .contains_key("_provider_work_github") + assert_eq!(repaired_again.status, "failed"); + assert_eq!(repaired_again.load_error.as_deref(), Some("apply failed")); + assert_eq!( + state + .store + .list_policies("sb-legacy-policy", 10, 0) + .await + .unwrap() + .len(), + 1 ); } @@ -11062,24 +11454,14 @@ mod tests { assert_eq!(persisted_provider.r#type, provider.r#type); assert_eq!(persisted_provider.credentials, provider.credentials); - let persisted_policy = state - .store - .get_latest_policy("sb-custom-policy-update") - .await - .unwrap() - .expect("sandbox policy should be lazily backfilled"); - let persisted_policy = - ProtoSandboxPolicy::decode(persisted_policy.policy_payload.as_slice()) - .expect("persisted sandbox policy should decode"); - assert!( - persisted_policy - .network_policies - .contains_key("sandbox_only") - ); assert!( - !persisted_policy - .network_policies - .contains_key("_provider_work_custom") + state + .store + .get_latest_policy("sb-custom-policy-update") + .await + .unwrap() + .is_none(), + "config and profile reads must not create policy history" ); } @@ -20869,4 +21251,34 @@ mod tests { response.unwrap_err() ); } + + #[test] + fn provider_stream_values_expand_to_legacy_polling_response() { + let response = provider_environment_response(ProviderEnvironmentSnapshot { + provider_env_revision: 9, + values: vec![ + ProviderEnvironmentValue { + name: "REGION".into(), + value: "west".into(), + classification: ProviderEnvironmentValueClassification::NonSecret.into(), + ..Default::default() + }, + ProviderEnvironmentValue { + name: "TOKEN".into(), + value: "secret".into(), + expires_at_ms: Some(123), + classification: ProviderEnvironmentValueClassification::StaticCredential.into(), + static_credential_binding: Some(StaticCredentialBinding::default()), + }, + ], + dynamic_credentials: HashMap::new(), + }); + + assert_eq!(response.provider_env_revision, 9); + assert_eq!(response.environment["REGION"], "west"); + assert_eq!(response.environment["TOKEN"], "secret"); + assert_eq!(response.credential_expires_at_ms["TOKEN"], 123); + assert_eq!(response.non_secret_environment_keys, ["REGION"]); + assert!(response.static_credential_bindings.contains_key("TOKEN")); + } } diff --git a/crates/openshell-server/src/grpc/provider.rs b/crates/openshell-server/src/grpc/provider.rs index 0500b668e8..b0e9b70bc6 100644 --- a/crates/openshell-server/src/grpc/provider.rs +++ b/crates/openshell-server/src/grpc/provider.rs @@ -2434,6 +2434,21 @@ async fn authorize_and_resolve_profile_workspace( } } +fn publish_provider_change(state: &Arc, workspace: &str) { + if workspace.is_empty() { + crate::config_delivery::publish_all_connected( + state, + crate::config_delivery::ConfigComponents::ALL, + ); + } else { + crate::config_delivery::publish_workspace_components( + state, + workspace, + crate::config_delivery::ConfigComponents::ALL, + ); + } +} + pub(super) async fn handle_create_provider( state: &Arc, request: Request, @@ -2493,6 +2508,7 @@ pub(super) async fn handle_create_provider( LifecycleOperation::Create, TelemetryOutcome::Success, ); + publish_provider_change(state, &workspace); Ok(Response::new(ProviderResponse { provider: Some(provider), })) @@ -2755,6 +2771,7 @@ pub(super) async fn handle_import_provider_profiles( stored.profile.unwrap_or_default(), resource_version, )); + publish_provider_change(state, &workspace); } Ok(Response::new(ImportProviderProfilesResponse { @@ -2885,6 +2902,7 @@ pub(super) async fn handle_update_provider_profiles( } let resource_version = stored_profile_resource_version(&stored); let profile = profile_response_payload(stored.profile.unwrap_or_default(), resource_version); + publish_provider_change(state, &workspace); Ok(Response::new(UpdateProviderProfilesResponse { diagnostics: Vec::new(), @@ -2974,6 +2992,9 @@ pub(super) async fn handle_delete_provider_profile( .delete_by_name(StoredProviderProfile::object_type(), &workspace, &id) .await .map_err(|e| Status::internal(format!("delete provider profile failed: {e}")))?; + if deleted { + publish_provider_change(state, &workspace); + } Ok(Response::new(DeleteProviderProfileResponse { deleted })) } @@ -3754,6 +3775,7 @@ pub(super) async fn handle_update_provider( LifecycleOperation::Update, TelemetryOutcome::Success, ); + publish_provider_change(state, &workspace); Ok(Response::new(ProviderResponse { provider: Some(provider), })) @@ -4673,8 +4695,17 @@ pub(super) async fn handle_configure_provider_refresh( profile_workspace: String::new(), credential_handles: HashMap::new(), }; - update_provider_record_with_catalog(state.store.as_ref(), &catalog, &workspace, updated) - .await?; + let result = update_provider_record_with_catalog( + state.store.as_ref(), + &catalog, + &workspace, + updated, + ) + .await; + publish_provider_change(state, &workspace); + result?; + } else { + publish_provider_change(state, &workspace); } Ok(Response::new(ConfigureProviderRefreshResponse { @@ -4718,6 +4749,7 @@ pub(super) async fn handle_rotate_provider_credential( credential_key, ) .await?; + publish_provider_change(state, &workspace); Ok(Response::new(RotateProviderCredentialResponse { status: Some(crate::provider_refresh::refresh_status_from_state( @@ -4800,14 +4832,13 @@ pub(super) async fn handle_delete_provider_refresh( credential_key, ) .await?; - // A refresh co-manages the expiry of its primary credential and every pinned // additional output. Clear each expiry this refresh still owns, leaving // independently updated ones in place. The equality check and removal run // inside the CAS closure so they see the current stored provider — deciding // from the snapshot read above would let a concurrent rotation or provider // update land between the read and the write and then be clobbered (CWE-362). - if let Some(refresh_state) = existing_refresh_state + let expiry_cleanup = if let Some(refresh_state) = existing_refresh_state && refresh_state.expires_at_ms > 0 { let refresh_expires_at_ms = refresh_state.expires_at_ms; @@ -4824,8 +4855,15 @@ pub(super) async fn handle_delete_provider_refresh( Status::internal(format!( "clear refresh-owned credential expiries failed: {e}" )) - })?; + }) + .map(|_| ()) + } else { + Ok(()) + }; + if deleted_refresh_state { + publish_provider_change(state, &workspace); } + expiry_cleanup?; Ok(Response::new(DeleteProviderRefreshResponse { deleted: deleted_refresh_state, @@ -4866,6 +4904,9 @@ pub(super) async fn handle_delete_provider( LifecycleOperation::Delete, outcome, ); + if deleted { + publish_provider_change(state, &workspace); + } Ok(Response::new(DeleteProviderResponse { deleted })) } Err(err) => { diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index d428e64569..6353acd563 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -1175,6 +1175,14 @@ pub(super) async fn handle_attach_sandbox_provider( .map_err(|e| super::persistence_error_to_status(e, "attach sandbox provider"))?; let attached = attached.load(Ordering::Relaxed); + if attached { + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); + state.sandbox_watch_bus.notify(&sandbox_id); + } info!( sandbox_name = %request.sandbox_name, @@ -1274,6 +1282,14 @@ pub(super) async fn handle_detach_sandbox_provider( .map_err(|e| super::persistence_error_to_status(e, "detach sandbox provider"))?; let detached = detached.load(Ordering::Relaxed); + if detached { + crate::config_delivery::publish_sandbox_components( + state, + &sandbox_id, + crate::config_delivery::ConfigComponents::SANDBOX_AND_PROVIDER, + ); + state.sandbox_watch_bus.notify(&sandbox_id); + } info!( sandbox_name = %request.sandbox_name, diff --git a/crates/openshell-server/src/lib.rs b/crates/openshell-server/src/lib.rs index 6bea00e6a0..dee5260eb6 100644 --- a/crates/openshell-server/src/lib.rs +++ b/crates/openshell-server/src/lib.rs @@ -17,6 +17,7 @@ mod auth; pub mod certgen; pub mod cli; mod compute; +mod config_delivery; pub mod config_file; mod credentials; mod defaults; @@ -301,6 +302,11 @@ pub struct ServerState { /// Set once graceful gateway shutdown begins so stream handlers can /// distinguish expected transport closes from runtime failures. pub(crate) gateway_shutting_down: AtomicBool, + /// Per-sandbox scheduler for coalesced supervisor configuration delivery. + pub(crate) config_delivery_queue: config_delivery::ConfigDeliveryQueue, + + /// Routing boundary for local or remote supervisor configuration delivery. + pub(crate) supervisor_config_router: Arc, /// Validated built-in and operator-registered supervisor middleware. pub middleware_registry: Arc, @@ -356,6 +362,12 @@ fn is_benign_connection_close(error: &(dyn std::error::Error + 'static)) -> bool } impl ServerState { + /// Return the configuration delivery boundary for supervisor sessions. + #[must_use] + pub fn supervisor_config_router(&self) -> Arc { + Arc::clone(&self.supervisor_config_router) + } + /// Create new server state. #[must_use] #[allow(clippy::too_many_arguments)] @@ -404,6 +416,9 @@ impl ServerState { .oidc .as_ref() .map_or_else(String::new, |oidc| oidc.admin_role.clone()); + let supervisor_config_router: Arc = Arc::new( + config_delivery::LocalSupervisorConfigRouter::new(Arc::clone(&supervisor_sessions)), + ); Self { config, store, @@ -418,6 +433,8 @@ impl ServerState { settings_mutex: tokio::sync::Mutex::new(()), supervisor_sessions, gateway_shutting_down: AtomicBool::new(false), + config_delivery_queue: config_delivery::ConfigDeliveryQueue::default(), + supervisor_config_router, extension_mint_limiter: auth::extension_mint_limit::ExtensionMintLimiter::default(), middleware_registry: Arc::new(MiddlewareRegistry::default()), oidc_cache, @@ -680,6 +697,10 @@ pub(crate) async fn run_server( let state = Arc::new(state); + grpc::policy::backfill_legacy_policy_history(&state) + .await + .map_err(|error| Error::execution(error.to_string()))?; + // Reconcile local-driver running intent before watchers spawn so their // first snapshots observe the post-start backend state. Explicitly stopped // sandboxes remain stopped. diff --git a/crates/openshell-server/src/persistence/postgres.rs b/crates/openshell-server/src/persistence/postgres.rs index 3fa54151b5..2402a8e2df 100644 --- a/crates/openshell-server/src/persistence/postgres.rs +++ b/crates/openshell-server/src/persistence/postgres.rs @@ -945,6 +945,50 @@ VALUES ($1, $2, $3, $4, $5, $6, $7, $7, $8) Ok(()) } + pub async fn put_initial_policy_revision( + &self, + record: &PolicyRecord, + workspace: &str, + ) -> PersistenceResult<()> { + let wrapped_payload = policy_payload_from_record(record)?; + let mut tx = self.pool.begin().await.map_err(|e| map_db_error(&e))?; + + let sandbox_exists = sqlx::query( + "SELECT id FROM objects WHERE object_type = 'sandbox' AND id = $1 FOR UPDATE", + ) + .bind(&record.sandbox_id) + .fetch_optional(&mut *tx) + .await + .map_err(|e| map_db_error(&e))? + .is_some(); + + if sandbox_exists { + sqlx::query( + r" +INSERT INTO objects ( + object_type, id, scope, version, status, payload, created_at_ms, updated_at_ms, workspace +) +SELECT $1, $2, $3, 1, $4, $5, $6, $6, $7 +WHERE NOT EXISTS (SELECT 1 FROM objects WHERE object_type = $1 AND scope = $3) +ON CONFLICT DO NOTHING +", + ) + .bind(POLICY_OBJECT_TYPE) + .bind(&record.id) + .bind(&record.sandbox_id) + .bind(&record.status) + .bind(wrapped_payload) + .bind(record.created_at_ms) + .bind(workspace) + .execute(&mut *tx) + .await + .map_err(|e| map_db_error(&e))?; + } + + tx.commit().await.map_err(|e| map_db_error(&e))?; + Ok(()) + } + pub async fn put_policy_revision_atomic( &self, write: &AtomicPolicyRevisionWrite, diff --git a/crates/openshell-server/src/persistence/sqlite.rs b/crates/openshell-server/src/persistence/sqlite.rs index 4c274386ca..d8feafc60e 100644 --- a/crates/openshell-server/src/persistence/sqlite.rs +++ b/crates/openshell-server/src/persistence/sqlite.rs @@ -1084,6 +1084,36 @@ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?7, ?8) Ok(()) } + pub async fn put_initial_policy_revision( + &self, + record: &PolicyRecord, + workspace: &str, + ) -> PersistenceResult<()> { + let wrapped_payload = policy_payload_from_record(record)?; + sqlx::query( + r#" +INSERT INTO "objects" ( + "object_type", "id", "scope", "version", "status", "payload", "created_at_ms", "updated_at_ms", "workspace" +) +SELECT ?1, ?2, ?3, 1, ?4, ?5, ?6, ?6, ?7 +WHERE EXISTS (SELECT 1 FROM "objects" WHERE "object_type" = 'sandbox' AND "id" = ?3) + AND NOT EXISTS (SELECT 1 FROM "objects" WHERE "object_type" = ?1 AND "scope" = ?3) +ON CONFLICT DO NOTHING +"#, + ) + .bind(POLICY_OBJECT_TYPE) + .bind(&record.id) + .bind(&record.sandbox_id) + .bind(&record.status) + .bind(wrapped_payload) + .bind(record.created_at_ms) + .bind(workspace) + .execute(&self.pool) + .await + .map_err(|e| map_db_error(&e))?; + Ok(()) + } + pub async fn put_policy_revision_atomic( &self, write: &AtomicPolicyRevisionWrite, diff --git a/crates/openshell-server/src/persistence/tests.rs b/crates/openshell-server/src/persistence/tests.rs index a292926270..1a149ed7ce 100644 --- a/crates/openshell-server/src/persistence/tests.rs +++ b/crates/openshell-server/src/persistence/tests.rs @@ -1,7 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -use super::{ObjectListQuery, ObjectType, PersistenceError, Store, generate_name, test_store}; +use super::{ + ObjectListQuery, ObjectType, PersistenceError, PolicyRecord, Store, generate_name, test_store, +}; use crate::policy_store::{AtomicPolicyRevisionWrite, PolicyStoreExt}; use openshell_core::proto::datamodel::v1::ObjectMeta as ProtoObjectMeta; use openshell_core::proto::{ObjectForTest, Sandbox, SandboxPolicy, SandboxSpec}; @@ -1091,6 +1093,85 @@ fn policy_test_sandbox(id: &str, name: &str) -> Sandbox { } } +#[tokio::test] +async fn initial_policy_history_is_insert_only() { + assert_initial_policy_history_is_insert_only(&test_store().await).await; +} + +#[tokio::test] +#[ignore = "requires OPENSHELL_TEST_POSTGRES_URL pointing to a test database"] +async fn postgres_initial_policy_history_is_insert_only() { + let url = std::env::var("OPENSHELL_TEST_POSTGRES_URL").expect("test database URL"); + let store = Store::connect(&url).await.unwrap(); + assert_initial_policy_history_is_insert_only(&store).await; +} + +async fn assert_initial_policy_history_is_insert_only(store: &Store) { + let id = uuid::Uuid::new_v4().to_string(); + let sandbox = policy_test_sandbox(&id, &id); + let record = PolicyRecord { + id: uuid::Uuid::new_v4().to_string(), + sandbox_id: id.clone(), + version: 1, + policy_payload: SandboxPolicy::default().encode_to_vec(), + policy_hash: "initial-hash".into(), + status: "loaded".into(), + load_error: None, + created_at_ms: 1, + loaded_at_ms: None, + provenance: StdHashMap::new(), + }; + + store + .put_initial_policy_revision(&record, "default") + .await + .unwrap(); + assert!(store.get_latest_policy(&id).await.unwrap().is_none()); + + store.put_message(&sandbox).await.unwrap(); + let (first, second) = tokio::join!( + store.put_initial_policy_revision(&record, "default"), + store.put_initial_policy_revision(&record, "default"), + ); + first.unwrap(); + second.unwrap(); + let initial = store.get_latest_policy(&id).await.unwrap().unwrap(); + assert_eq!(initial.status, "loaded"); + assert_eq!(initial.policy_hash, record.policy_hash); + assert_eq!(store.list_policies(&id, 10, 0).await.unwrap().len(), 1); + + store + .update_policy_status(&id, 1, "failed", Some("apply failed"), None) + .await + .unwrap(); + store + .put_initial_policy_revision(&record, "default") + .await + .unwrap(); + let failed = store.get_latest_policy(&id).await.unwrap().unwrap(); + assert_eq!(failed.status, "failed"); + assert_eq!(failed.load_error.as_deref(), Some("apply failed")); + + store + .put_policy_revision( + &uuid::Uuid::new_v4().to_string(), + &id, + "default", + 2, + &record.policy_payload, + "new-hash", + ) + .await + .unwrap(); + store + .put_initial_policy_revision(&record, "default") + .await + .unwrap(); + let latest = store.get_latest_policy(&id).await.unwrap().unwrap(); + assert_eq!(latest.version, 2); + assert_eq!(store.list_policies(&id, 10, 0).await.unwrap().len(), 2); +} + #[tokio::test] async fn policy_atomic_write_commits_revision_provenance_and_sandbox_projection() { let store = test_store().await; diff --git a/crates/openshell-server/src/policy_store.rs b/crates/openshell-server/src/policy_store.rs index 8538e72205..4f9ba9a62e 100644 --- a/crates/openshell-server/src/policy_store.rs +++ b/crates/openshell-server/src/policy_store.rs @@ -94,6 +94,14 @@ pub fn project_policy_revision_onto_sandbox( } pub trait PolicyStoreExt { + /// Insert version-one policy history when the sandbox still has no policy + /// revisions. Existing history and apply status are left untouched. + async fn put_initial_policy_revision( + &self, + record: &PolicyRecord, + workspace: &str, + ) -> PersistenceResult<()>; + async fn put_policy_revision( &self, id: &str, @@ -217,6 +225,17 @@ pub trait PolicyStoreExt { } impl PolicyStoreExt for Store { + async fn put_initial_policy_revision( + &self, + record: &PolicyRecord, + workspace: &str, + ) -> PersistenceResult<()> { + match self { + Self::Postgres(store) => store.put_initial_policy_revision(record, workspace).await, + Self::Sqlite(store) => store.put_initial_policy_revision(record, workspace).await, + } + } + async fn put_policy_revision( &self, id: &str, diff --git a/crates/openshell-server/src/provider_refresh.rs b/crates/openshell-server/src/provider_refresh.rs index f322be0dd0..369749f1e2 100644 --- a/crates/openshell-server/src/provider_refresh.rs +++ b/crates/openshell-server/src/provider_refresh.rs @@ -1809,14 +1809,25 @@ pub fn spawn_refresh_worker(state: std::sync::Arc, interval: ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay); loop { ticker.tick().await; - if let Err(err) = run_refresh_worker_tick( + match run_refresh_worker_tick( state.store.as_ref(), Some(&state.credentials), Some(&state.compute), ) .await { - warn!(error = %err, "provider credential refresh worker tick failed"); + Ok(workspaces) => { + for workspace in workspaces { + crate::config_delivery::publish_workspace_components( + &state, + &workspace, + crate::config_delivery::ConfigComponents::ALL, + ); + } + } + Err(err) => { + warn!(error = %err, "provider credential refresh worker tick failed"); + } } } }); @@ -1835,7 +1846,8 @@ async fn run_refresh_worker_tick( store: &Store, credentials: Option<&crate::credentials::CredentialRuntime>, compute: Option<&crate::compute::ComputeRuntime>, -) -> Result<(), Status> { +) -> Result, Status> { + let mut changed_workspaces = std::collections::HashSet::new(); let now_ms = current_time_ms(); let states = list_all_refresh_states(store).await.inspect_err(|_| { crate::otel_tracing::mark_error(&tracing::Span::current()); @@ -1885,6 +1897,8 @@ async fn run_refresh_worker_tick( error = %err, "failed to finalize tombstoned provider refresh; retrying on the next sweep" ); + } else { + changed_workspaces.insert(state.object_workspace().to_string()); } continue; } @@ -1968,9 +1982,11 @@ async fn run_refresh_worker_tick( error = %err, "provider credential refresh failed" ); + } else { + changed_workspaces.insert(state.object_workspace().to_string()); } } - Ok(()) + Ok(changed_workspaces) } #[cfg(test)] diff --git a/crates/openshell-server/src/supervisor_session.rs b/crates/openshell-server/src/supervisor_session.rs index 24413f0f1b..c5668cc41e 100644 --- a/crates/openshell-server/src/supervisor_session.rs +++ b/crates/openshell-server/src/supervisor_session.rs @@ -7,21 +7,29 @@ use std::sync::atomic::Ordering; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; +use metrics::counter; +use prost::Message; use tokio::sync::{mpsc, oneshot}; use tokio_stream::wrappers::ReceiverStream; use tonic::{Request, Response, Status}; use tracing::{debug, info, warn}; use uuid::Uuid; +use openshell_core::proto::SUPERVISOR_PROTOCOL_REVISION; use openshell_core::proto::{ - GatewayMessage, RelayFrame, RelayInit, RelayOpen, ReportMainProcessExitRequest, + ConfigUpdate, GatewayMessage, RelayFrame, RelayInit, RelayOpen, ReportMainProcessExitRequest, ReportMainProcessExitResponse, Sandbox, SandboxPhase, SessionAccepted, SshRelayTarget, - SupervisorMessage, gateway_message, relay_open, supervisor_message, + SupervisorMessage, config_update, gateway_message, relay_open, supervisor_message, }; use openshell_core::transport_errors::is_expected_transport_close_status; use crate::ServerState; use crate::auth::principal::Principal; +use crate::config_delivery::{ + DeliveryDisposition, MAX_SUPERVISOR_CONFIG_MESSAGE_BYTES, SupervisorConfigMessage, +}; +#[cfg(test)] +use crate::config_delivery::{LocalSupervisorConfigRouter, SupervisorConfigRouter}; const HEARTBEAT_INTERVAL_SECS: u32 = 15; const RELAY_PENDING_TIMEOUT: Duration = Duration::from_secs(10); @@ -52,6 +60,7 @@ struct LiveSession { /// removing a session that has since been superseded by a reconnect. session_id: String, tx: mpsc::Sender, + config_sequences: ConfigSequences, /// Fires when this session is superseded by a reconnect so the old session /// task can exit promptly — dropping its own `tx` clone and closing the /// outbound stream. Without this, a concurrent `open_relay` that grabbed @@ -65,6 +74,12 @@ struct LiveSession { connected_at: Instant, } +#[derive(Debug, Default)] +struct ConfigSequences { + sandbox_config: u64, + provider_environment: u64, +} + /// Holds a oneshot sender that will deliver the upgraded relay stream or a /// target-open failure reported by the supervisor. type RelayStreamSender = oneshot::Sender>; @@ -127,6 +142,7 @@ impl SupervisorSessionRegistry { sandbox_id, session_id, tx, + config_sequences: ConfigSequences::default(), shutdown, terminal_delivery_finalized: false, connected_at: Instant::now(), @@ -233,6 +249,65 @@ impl SupervisorSessionRegistry { true } + pub(crate) fn connected_sandbox_ids(&self) -> Vec { + self.sessions.lock().unwrap().keys().cloned().collect() + } + + pub(crate) fn deliver_config( + &self, + sandbox_id: &str, + message: SupervisorConfigMessage, + ) -> DeliveryDisposition { + let component_name = message.component_name(); + let mut sessions = self.sessions.lock().unwrap(); + let Some(session) = sessions.get_mut(sandbox_id) else { + return DeliveryDisposition::NoActiveSession; + }; + let sequence = match &message { + SupervisorConfigMessage::SandboxConfig(_) => { + &mut session.config_sequences.sandbox_config + } + SupervisorConfigMessage::ProviderEnvironment(_) => { + &mut session.config_sequences.provider_environment + } + }; + *sequence = sequence.saturating_add(1); + let component_sequence = *sequence; + + let component = match message { + SupervisorConfigMessage::SandboxConfig(snapshot) => { + config_update::Component::SandboxConfig(*snapshot) + } + SupervisorConfigMessage::ProviderEnvironment(snapshot) => { + config_update::Component::ProviderEnvironment(snapshot) + } + }; + let gateway_message = GatewayMessage { + payload: Some(gateway_message::Payload::ConfigUpdate(ConfigUpdate { + update_id: Uuid::new_v4().to_string(), + component_sequence, + component: Some(component), + })), + }; + + if gateway_message.encoded_len() > MAX_SUPERVISOR_CONFIG_MESSAGE_BYTES { + return DeliveryDisposition::PayloadTooLarge; + } + + match session.tx.try_send(gateway_message) { + Ok(()) => DeliveryDisposition::Enqueued, + Err(mpsc::error::TrySendError::Full(_)) => { + warn!( + sandbox_id = %sandbox_id, + component = component_name, + "supervisor configuration queue is full" + ); + DeliveryDisposition::QueueFull + } + Err(mpsc::error::TrySendError::Closed(_)) => DeliveryDisposition::SessionClosed, + } + } + pub fn is_current_session(&self, sandbox_id: &str, session_id: &str) -> bool { self.sessions .lock() @@ -480,17 +555,13 @@ pub fn spawn_relay_reaper(state: Arc, interval: Duration) { async fn require_persisted_sandbox( store: &Arc, sandbox_id: &str, -) -> Result<(), Status> { +) -> Result { let sandbox = store .get_message::(sandbox_id) .await .map_err(|err| Status::internal(format!("failed to load sandbox: {err}")))?; - if sandbox.is_none() { - return Err(Status::not_found("sandbox not found")); - } - - Ok(()) + sandbox.ok_or_else(|| Status::not_found("sandbox not found")) } // --------------------------------------------------------------------------- @@ -739,10 +810,35 @@ pub async fn handle_connect_supervisor( if sandbox_id.is_empty() { return Err(Status::invalid_argument("sandbox_id is required")); } + validate_protocol_revision(hello.protocol_revision)?; if let Some(principal) = principal.as_ref() { crate::auth::guard::ensure_sandbox_principal_scope(principal, &sandbox_id)?; } - require_persisted_sandbox(&state.store, &sandbox_id).await?; + let sandbox = require_persisted_sandbox(&state.store, &sandbox_id).await?; + + let bootstrap = match crate::config_delivery::build_config_bootstrap(state, &sandbox).await { + Ok(bootstrap) => { + counter!( + "openshell_supervisor_config_bootstrap_total", + "outcome" => "built" + ) + .increment(1); + Some(bootstrap) + } + Err(error) => { + counter!( + "openshell_supervisor_config_bootstrap_total", + "outcome" => "build_failed" + ) + .increment(1); + warn!( + sandbox_id = %sandbox_id, + error_code = ?error.code(), + "failed to build supervisor configuration bootstrap" + ); + None + } + }; let session_id = Uuid::new_v4().to_string(); info!( @@ -752,9 +848,35 @@ pub async fn handle_connect_supervisor( "supervisor session: accepted" ); - // Step 2: Create and register the outbound channel. + // Step 2: Queue SessionAccepted before the session becomes routable. This + // keeps a concurrent ConfigUpdate from becoming the first stream message. let (tx, rx) = mpsc::channel::(64); let (shutdown_tx, shutdown_rx) = oneshot::channel::<()>(); + let mut accepted = GatewayMessage { + payload: Some(gateway_message::Payload::SessionAccepted(SessionAccepted { + session_id: session_id.clone(), + heartbeat_interval_secs: HEARTBEAT_INTERVAL_SECS, + bootstrap, + protocol_revision: SUPERVISOR_PROTOCOL_REVISION, + })), + }; + if accepted.encoded_len() > MAX_SUPERVISOR_CONFIG_MESSAGE_BYTES { + counter!( + "openshell_supervisor_config_bootstrap_total", + "outcome" => "payload_too_large" + ) + .increment(1); + let Some(gateway_message::Payload::SessionAccepted(accepted_payload)) = + accepted.payload.as_mut() + else { + unreachable!("constructed SessionAccepted payload") + }; + accepted_payload.bootstrap = None; + } + if tx.send(accepted).await.is_err() { + return Err(Status::internal("failed to send session accepted")); + } + let superseded = state.supervisor_sessions.register( sandbox_id.clone(), session_id.clone(), @@ -769,22 +891,6 @@ pub async fn handle_connect_supervisor( ); } - // Step 3: Send SessionAccepted. - let accepted = GatewayMessage { - payload: Some(gateway_message::Payload::SessionAccepted(SessionAccepted { - session_id: session_id.clone(), - heartbeat_interval_secs: HEARTBEAT_INTERVAL_SECS, - })), - }; - if tx.send(accepted).await.is_err() { - // Only evict ourselves — a faster reconnect may already have - // superseded this registration. - state - .supervisor_sessions - .remove_if_current(&sandbox_id, &session_id); - return Err(Status::internal("failed to send session accepted")); - } - if superseded { state .supervisor_sessions @@ -854,6 +960,16 @@ pub async fn handle_connect_supervisor( Ok(Response::new(stream)) } +fn validate_protocol_revision(supervisor_revision: u32) -> Result<(), Status> { + if supervisor_revision == SUPERVISOR_PROTOCOL_REVISION { + Ok(()) + } else { + Err(Status::failed_precondition(format!( + "supervisor protocol revision mismatch: gateway requires {SUPERVISOR_PROTOCOL_REVISION}, supervisor offered {supervisor_revision}" + ))) + } +} + pub async fn handle_report_main_process_exit( state: &Arc, request: Request, @@ -1016,6 +1132,22 @@ fn handle_supervisor_message( "supervisor session: relay closed by supervisor" ); } + Some(supervisor_message::Payload::ConfigUpdateResult(result)) => { + debug!( + sandbox_id = %sandbox_id, + session_id = %session_id, + component_sequence = result.component_sequence, + "supervisor session: ignoring configuration result while polling remains authoritative" + ); + } + Some(supervisor_message::Payload::ConfigBootstrapResult(result)) => { + debug!( + sandbox_id = %sandbox_id, + session_id = %session_id, + result_count = result.results.len(), + "supervisor session: ignoring bootstrap result while polling remains authoritative" + ); + } _ => { warn!( sandbox_id = %sandbox_id, @@ -1036,6 +1168,256 @@ mod tests { use crate::auth::identity::{Identity, IdentityProvider}; use crate::auth::principal::{SandboxIdentitySource, SandboxPrincipal, UserPrincipal}; use crate::persistence::Store; + use openshell_core::proto::{ + ProviderEnvironmentSnapshot, ProviderEnvironmentValue, SandboxConfigRevision, + SandboxConfigSnapshot, + }; + use prost::Message; + + #[test] + fn configuration_stream_messages_round_trip() { + let bootstrap = GatewayMessage { + payload: Some(gateway_message::Payload::SessionAccepted(SessionAccepted { + session_id: "session-1".into(), + heartbeat_interval_secs: 15, + bootstrap: Some(openshell_core::proto::ConfigBootstrap { + sandbox_config: Some(SandboxConfigSnapshot::default()), + provider_environment: Some(ProviderEnvironmentSnapshot::default()), + }), + protocol_revision: SUPERVISOR_PROTOCOL_REVISION, + })), + }; + let updates = [ + config_update::Component::SandboxConfig(SandboxConfigSnapshot::default()), + config_update::Component::ProviderEnvironment(ProviderEnvironmentSnapshot::default()), + ] + .into_iter() + .enumerate() + .map(|(index, component)| GatewayMessage { + payload: Some(gateway_message::Payload::ConfigUpdate(ConfigUpdate { + update_id: format!("update-{index}"), + component_sequence: u64::try_from(index + 1).unwrap(), + component: Some(component), + })), + }); + + for original in std::iter::once(bootstrap).chain(updates) { + let decoded = GatewayMessage::decode(original.encode_to_vec().as_slice()).unwrap(); + assert_eq!(decoded, original); + } + + let result = SupervisorMessage { + payload: Some(supervisor_message::Payload::ConfigUpdateResult( + openshell_core::proto::ConfigUpdateResult { + update_id: "update-1".into(), + component_sequence: 4, + result: Some(openshell_core::proto::ConfigComponentApplyResult { + component: openshell_core::proto::ConfigComponent::SandboxConfig.into(), + requested_revision: Some(openshell_core::proto::ConfigSnapshotRevision { + component: Some( + openshell_core::proto::config_snapshot_revision::Component::SandboxConfig( + SandboxConfigRevision { + config_revision: 7, + policy_version: 3, + ..Default::default() + }, + ), + ), + }), + applied_revision: Some(openshell_core::proto::ConfigSnapshotRevision { + component: Some( + openshell_core::proto::config_snapshot_revision::Component::SandboxConfig( + SandboxConfigRevision { + config_revision: 7, + policy_version: 3, + ..Default::default() + }, + ), + ), + }), + outcome: openshell_core::proto::ConfigApplyOutcome::Applied.into(), + failure: None, + }), + }, + )), + }; + let decoded = SupervisorMessage::decode(result.encode_to_vec().as_slice()).unwrap(); + assert_eq!(decoded, result); + } + + #[test] + fn supervisor_protocol_revision_must_match_exactly() { + assert!(validate_protocol_revision(SUPERVISOR_PROTOCOL_REVISION).is_ok()); + let error = validate_protocol_revision(SUPERVISOR_PROTOCOL_REVISION + 1).unwrap_err(); + assert_eq!(error.code(), tonic::Code::FailedPrecondition); + assert!(error.message().contains("revision mismatch")); + } + + #[tokio::test] + async fn config_router_reports_missing_session() { + let router = LocalSupervisorConfigRouter::new(Arc::new(SupervisorSessionRegistry::new())); + assert_eq!( + router + .deliver( + "missing", + SupervisorConfigMessage::SandboxConfig(Box::default()), + ) + .await, + DeliveryDisposition::NoActiveSession + ); + } + + #[tokio::test] + async fn config_router_assigns_sequences_per_component() { + let registry = Arc::new(SupervisorSessionRegistry::new()); + let router = LocalSupervisorConfigRouter::new(Arc::clone(®istry)); + let (tx, mut rx) = mpsc::channel(4); + let (shutdown_tx, _shutdown_rx) = oneshot::channel(); + registry.register("sb-1".into(), "session-1".into(), tx, shutdown_tx); + + assert_eq!( + router + .deliver( + "sb-1", + SupervisorConfigMessage::SandboxConfig(Box::default()), + ) + .await, + DeliveryDisposition::Enqueued + ); + assert_eq!( + router + .deliver( + "sb-1", + SupervisorConfigMessage::SandboxConfig(Box::default()), + ) + .await, + DeliveryDisposition::Enqueued + ); + assert_eq!( + router + .deliver( + "sb-1", + SupervisorConfigMessage::ProviderEnvironment( + ProviderEnvironmentSnapshot::default(), + ), + ) + .await, + DeliveryDisposition::Enqueued + ); + + let first = rx.recv().await.expect("first config update"); + let second = rx.recv().await.expect("second config update"); + let third = rx.recv().await.expect("provider config update"); + let sequence = |message: GatewayMessage| match message.payload { + Some(gateway_message::Payload::ConfigUpdate(update)) => update.component_sequence, + other => panic!("expected config update, got {other:?}"), + }; + assert_eq!(sequence(first), 1); + assert_eq!(sequence(second), 2); + assert_eq!(sequence(third), 1); + } + + #[tokio::test] + async fn config_router_uses_replacement_session() { + let registry = Arc::new(SupervisorSessionRegistry::new()); + let router = LocalSupervisorConfigRouter::new(Arc::clone(®istry)); + let (old_tx, mut old_rx) = mpsc::channel(2); + let (old_shutdown_tx, _old_shutdown_rx) = oneshot::channel(); + registry.register("sb-1".into(), "old-session".into(), old_tx, old_shutdown_tx); + + assert_eq!( + router + .deliver( + "sb-1", + SupervisorConfigMessage::SandboxConfig(Box::default()), + ) + .await, + DeliveryDisposition::Enqueued + ); + let old_update = old_rx.recv().await.expect("old-session config update"); + let Some(gateway_message::Payload::ConfigUpdate(old_update)) = old_update.payload else { + panic!("expected config update"); + }; + assert_eq!(old_update.component_sequence, 1); + + let (new_tx, mut new_rx) = mpsc::channel(1); + let (new_shutdown_tx, _new_shutdown_rx) = oneshot::channel(); + assert!(registry.register("sb-1".into(), "new-session".into(), new_tx, new_shutdown_tx,)); + + assert_eq!( + router + .deliver( + "sb-1", + SupervisorConfigMessage::SandboxConfig(Box::default()), + ) + .await, + DeliveryDisposition::Enqueued + ); + assert!(old_rx.try_recv().is_err()); + let new_update = new_rx.try_recv().expect("new-session config update"); + let Some(gateway_message::Payload::ConfigUpdate(new_update)) = new_update.payload else { + panic!("expected config update"); + }; + assert_eq!(new_update.component_sequence, 1); + } + + #[tokio::test] + async fn config_router_reports_full_and_closed_queues() { + let registry = Arc::new(SupervisorSessionRegistry::new()); + let router = LocalSupervisorConfigRouter::new(Arc::clone(®istry)); + let (tx, rx) = mpsc::channel(1); + tx.try_send(GatewayMessage::default()).unwrap(); + let (shutdown_tx, _shutdown_rx) = oneshot::channel(); + registry.register("sb-1".into(), "session-1".into(), tx, shutdown_tx); + assert_eq!( + router + .deliver( + "sb-1", + SupervisorConfigMessage::SandboxConfig(Box::default()), + ) + .await, + DeliveryDisposition::QueueFull + ); + + drop(rx); + assert_eq!( + router + .deliver( + "sb-1", + SupervisorConfigMessage::SandboxConfig(Box::default()), + ) + .await, + DeliveryDisposition::SessionClosed + ); + } + + #[tokio::test] + async fn config_router_rejects_oversized_messages() { + let registry = Arc::new(SupervisorSessionRegistry::new()); + let router = LocalSupervisorConfigRouter::new(Arc::clone(®istry)); + let (tx, mut rx) = mpsc::channel(1); + let (shutdown_tx, _shutdown_rx) = oneshot::channel(); + registry.register("sb-1".into(), "session-1".into(), tx, shutdown_tx); + + let snapshot = ProviderEnvironmentSnapshot { + values: vec![ProviderEnvironmentValue { + name: "TOKEN".into(), + value: "x".repeat(MAX_SUPERVISOR_CONFIG_MESSAGE_BYTES), + ..Default::default() + }], + ..Default::default() + }; + assert_eq!( + router + .deliver( + "sb-1", + SupervisorConfigMessage::ProviderEnvironment(snapshot), + ) + .await, + DeliveryDisposition::PayloadTooLarge + ); + assert!(rx.try_recv().is_err()); + } use tokio::io::{AsyncReadExt, AsyncWriteExt}; async fn test_store() -> Arc { diff --git a/crates/openshell-supervisor-process/src/supervisor_session.rs b/crates/openshell-supervisor-process/src/supervisor_session.rs index a8f60a5681..9b6882f84c 100644 --- a/crates/openshell-supervisor-process/src/supervisor_session.rs +++ b/crates/openshell-supervisor-process/src/supervisor_session.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; +use openshell_core::proto::SUPERVISOR_PROTOCOL_REVISION; use openshell_core::proto::open_shell_client::OpenShellClient; use openshell_core::proto::{ FinalizeMainProcessExitRequest, GatewayMessage, RelayFrame, RelayInit, RelayOpen, @@ -354,6 +355,7 @@ async fn run_single_session( payload: Some(supervisor_message::Payload::Hello(SupervisorHello { sandbox_id: config.sandbox_id.clone(), instance_id: config.instance_id.clone(), + protocol_revision: SUPERVISOR_PROTOCOL_REVISION, })), }) .await @@ -381,6 +383,7 @@ async fn run_single_session( }; let heartbeat_secs = accepted.heartbeat_interval_secs.max(5); + validate_gateway_protocol_revision(accepted.protocol_revision)?; let event = session_established_event( openshell_ocsf::ctx::ctx(), &config.endpoint, @@ -388,6 +391,15 @@ async fn run_single_session( heartbeat_secs, ); ocsf_emit!(event); + + if accepted.bootstrap.is_some() { + debug!( + sandbox_id = %config.sandbox_id, + session_id = %accepted.session_id, + "supervisor session: ignoring configuration bootstrap while polling remains active" + ); + } + // Main loop: receive gateway messages + send heartbeats. let mut heartbeat_interval = tokio::time::interval(Duration::from_secs(u64::from(heartbeat_secs))); @@ -432,6 +444,19 @@ async fn run_single_session( } } +fn validate_gateway_protocol_revision( + gateway_revision: u32, +) -> Result<(), Box> { + if gateway_revision == SUPERVISOR_PROTOCOL_REVISION { + Ok(()) + } else { + Err(format!( + "supervisor protocol revision mismatch: supervisor requires {SUPERVISOR_PROTOCOL_REVISION}, gateway offered {gateway_revision}" + ) + .into()) + } +} + /// Report the canonical process result and wait for durable handling. pub async fn report_main_process_exit( endpoint: &str, @@ -487,6 +512,15 @@ fn handle_gateway_message(msg: &GatewayMessage, context: &GatewayMessageContext< Some(gateway_message::Payload::Heartbeat(_)) => { // Gateway heartbeat — nothing to do. } + Some(gateway_message::Payload::ConfigUpdate(update)) => { + // Stage 1 accepts pushed configuration but leaves polling as the + // only path that changes runtime state. + debug!( + sandbox_id = %context.sandbox_id, + component_sequence = update.component_sequence, + "supervisor session: ignoring configuration update while polling remains active" + ); + } Some(gateway_message::Payload::RelayOpen(open)) => { let channel_id = open.channel_id.clone(); let relay_open = open.clone(); @@ -828,6 +862,14 @@ fn normalize_tcp_target_host(target: &TcpRelayTarget) -> Result mod target_tests { use super::*; + #[test] + fn gateway_protocol_revision_must_match_exactly() { + assert!(validate_gateway_protocol_revision(SUPERVISOR_PROTOCOL_REVISION).is_ok()); + let error = validate_gateway_protocol_revision(SUPERVISOR_PROTOCOL_REVISION + 1) + .expect_err("version skew must be rejected"); + assert!(error.to_string().contains("revision mismatch")); + } + fn tcp(host: &str, port: u32) -> TcpRelayTarget { TcpRelayTarget { host: host.to_string(), diff --git a/docs/reference/gateway-config.mdx b/docs/reference/gateway-config.mdx index 14cdb05ece..8aeb2281eb 100644 --- a/docs/reference/gateway-config.mdx +++ b/docs/reference/gateway-config.mdx @@ -106,7 +106,8 @@ disable_tls = false # Shared driver defaults. These inherit into [openshell.drivers.] tables # when the driver-specific table does not override them. default_image = "ghcr.io/nvidia/openshell-community/sandboxes/base:latest" -# Defaults to the gateway version; override to pin a specific build. +# Defaults to the gateway version. Custom builds must match the gateway's +# internal supervisor protocol revision; mismatched peers reject the session. # supervisor_image = "ghcr.io/nvidia/openshell/supervisor:" client_tls_secret_name = "openshell-client-tls" service_account_name = "openshell-sandbox" diff --git a/proto/openshell.proto b/proto/openshell.proto index def6d7c473..9e1a3e7f9a 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -512,9 +512,10 @@ service OpenShell { // // The supervisor opens this stream at startup and keeps it alive for the // sandbox lifetime. The gateway uses it to coordinate relay channels for - // SSH connect, ExecSandbox, and targetable sandbox services. Raw service - // bytes flow over RelayStream calls (separate HTTP/2 streams on the same - // connection), not over this stream. + // SSH connect, ExecSandbox, targetable sandbox services, and configuration + // delivery. Peers must report the same exact protocol_revision during the + // handshake. Raw service bytes flow over RelayStream calls (separate HTTP/2 + // streams on the same connection), not over this stream. rpc ConnectSupervisor(stream SupervisorMessage) returns (stream GatewayMessage) { option (openshell.options.v1.authorization) = { auth_mode: "sandbox" @@ -2180,6 +2181,30 @@ message GetSandboxProviderEnvironmentResponse { repeated string non_secret_environment_keys = 6; } +enum ProviderEnvironmentValueClassification { + PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_UNSPECIFIED = 0; + PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_NON_SECRET = 1; + PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_STATIC_CREDENTIAL = 2; +} + +// One environment value and all metadata that shares its key. +message ProviderEnvironmentValue { + string name = 1; + string value = 2 [(openshell.options.v1.secret) = true]; + optional int64 expires_at_ms = 3; + ProviderEnvironmentValueClassification classification = 4; + StaticCredentialBinding static_credential_binding = 5; +} + +// Complete provider environment state delivered to a supervisor. Dynamic +// credentials are endpoint selectors rather than environment values and stay +// in their own collection. +message ProviderEnvironmentSnapshot { + uint64 provider_env_revision = 1; + repeated ProviderEnvironmentValue values = 2; + map dynamic_credentials = 3; +} + message ExchangeProviderSubjectTokenRequest { // The sandbox ID. Must match the authenticated sandbox principal. string sandbox_id = 1; @@ -2458,6 +2483,9 @@ message GetSandboxLogsResponse { // Supervisor session messages // --------------------------------------------------------------------------- +// These messages form an internal, version-locked deployment protocol between +// the gateway and the supervisor. They are not a public sandbox client API. + // Envelope for supervisor-to-gateway messages on the ConnectSupervisor stream. message SupervisorMessage { oneof payload { @@ -2465,6 +2493,8 @@ message SupervisorMessage { SupervisorHeartbeat heartbeat = 2; RelayOpenResult relay_open_result = 3; RelayClose relay_close = 4; + ConfigUpdateResult config_update_result = 5; + ConfigBootstrapResult config_bootstrap_result = 6; } } @@ -2476,6 +2506,7 @@ message GatewayMessage { GatewayHeartbeat heartbeat = 3; RelayOpen relay_open = 4; RelayClose relay_close = 5; + ConfigUpdate config_update = 6; } } @@ -2485,6 +2516,8 @@ message SupervisorHello { string sandbox_id = 1; // Supervisor instance ID (e.g. boot id or process epoch). string instance_id = 2; + // Exact internal stream protocol revision implemented by this supervisor. + uint32 protocol_revision = 3; } // Gateway accepts the supervisor session. @@ -2493,6 +2526,99 @@ message SessionAccepted { string session_id = 1; // Recommended heartbeat interval in seconds. uint32 heartbeat_interval_secs = 2; + // Complete gateway-owned configuration. During the staged rollout this may + // be omitted only when the gateway cannot build the projection. + ConfigBootstrap bootstrap = 3; + // Exact internal stream protocol revision implemented by this gateway. + uint32 protocol_revision = 4; +} + +// Complete gateway-owned configuration for a supervisor session. +message ConfigBootstrap { + openshell.sandbox.v1.SandboxConfigSnapshot sandbox_config = 1; + ProviderEnvironmentSnapshot provider_environment = 2; +} + +// A complete replacement snapshot for exactly one configuration component. +message ConfigUpdate { + // Opaque non-empty identifier scoped to the active supervisor session. + string update_id = 1; + // Monotonic within one session and component. Snapshot revisions are + // content identities and must only be compared for equality. + uint64 component_sequence = 2; + oneof component { + openshell.sandbox.v1.SandboxConfigSnapshot sandbox_config = 3; + ProviderEnvironmentSnapshot provider_environment = 4; + } +} + +enum ConfigComponent { + CONFIG_COMPONENT_UNSPECIFIED = 0; + CONFIG_COMPONENT_SANDBOX_CONFIG = 1; + CONFIG_COMPONENT_PROVIDER_ENVIRONMENT = 2; +} + +// Identifies one component snapshot revision. Revisions are equality tokens, +// not members of one shared ordering domain. +message ConfigSnapshotRevision { + oneof component { + SandboxConfigRevision sandbox_config = 1; + uint64 provider_environment = 2; + } +} + +// Identity needed to correlate effective sandbox configuration with the +// policy-history row whose apply status the gateway records. +message SandboxConfigRevision { + uint64 config_revision = 1; + uint32 policy_version = 2; + openshell.sandbox.v1.PolicySource policy_source = 3; + uint32 global_policy_version = 4; +} + +enum ConfigApplyOutcome { + CONFIG_APPLY_OUTCOME_UNSPECIFIED = 0; + CONFIG_APPLY_OUTCOME_APPLIED = 1; + CONFIG_APPLY_OUTCOME_IGNORED_DUPLICATE = 2; + CONFIG_APPLY_OUTCOME_IGNORED_STALE = 3; + CONFIG_APPLY_OUTCOME_RETAINED_LOCAL_OVERRIDE = 4; + CONFIG_APPLY_OUTCOME_DEGRADED = 5; + CONFIG_APPLY_OUTCOME_FAILED_RETAINED_LAST_KNOWN_GOOD = 6; + CONFIG_APPLY_OUTCOME_FAILED_CLOSED = 7; + CONFIG_APPLY_OUTCOME_UNSUPPORTED = 8; +} + +// Sanitized application failure. Messages must not contain configuration +// payloads, credentials, or provider values. +message ConfigApplyFailure { + string code = 1; + string message = 2; + bool retryable = 3; +} + +message ConfigComponentApplyResult { + ConfigComponent component = 1; + // Revision extracted from the received snapshot. + ConfigSnapshotRevision requested_revision = 2; + // Revision active after this attempt. Omitted when the received snapshot + // was not installed or a local override has no gateway revision. + ConfigSnapshotRevision applied_revision = 3; + ConfigApplyOutcome outcome = 4; + ConfigApplyFailure failure = 5; +} + +// Application result for one ConfigUpdate. +message ConfigUpdateResult { + // Echoes ConfigUpdate.update_id for session-local correlation. + string update_id = 1; + // Echoes ConfigUpdate.component_sequence. + uint64 component_sequence = 2; + ConfigComponentApplyResult result = 3; +} + +// Aggregate application result for the SessionAccepted bootstrap. +message ConfigBootstrapResult { + repeated ConfigComponentApplyResult results = 1; } // Gateway rejects the supervisor session. diff --git a/proto/sandbox.proto b/proto/sandbox.proto index c2b61d0b3a..620c973798 100644 --- a/proto/sandbox.proto +++ b/proto/sandbox.proto @@ -356,13 +356,29 @@ message EffectiveSetting { SettingScope scope = 2; } -// Source used for the policy payload in GetSandboxConfigResponse. +// Source used for a sandbox configuration payload. enum PolicySource { POLICY_SOURCE_UNSPECIFIED = 0; POLICY_SOURCE_SANDBOX = 1; POLICY_SOURCE_GLOBAL = 2; } +// Complete effective sandbox configuration delivered to a supervisor. +message SandboxConfigSnapshot { + SandboxPolicy policy = 1; + uint32 version = 2; + string policy_hash = 3; + map settings = 4; + uint64 config_revision = 5; + PolicySource policy_source = 6; + uint32 global_policy_version = 7; + uint64 provider_env_revision = 8; + repeated SupervisorMiddlewareService supervisor_middleware_services = 9; + string workspace = 10; + string policy_validation_failure_mode = 11; + bool extension_authentication_enabled = 12; +} + // Response containing effective sandbox settings and policy. message GetSandboxConfigResponse { // The sandbox policy configuration. diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index 735c17bc88..de2aadfafa 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -281,6 +281,55 @@ func (ProviderProfileCategory) EnumDescriptor() ([]byte, []int) { return file_openshell_proto_rawDescGZIP(), []int{3} } +type ProviderEnvironmentValueClassification int32 + +const ( + ProviderEnvironmentValueClassification_PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_UNSPECIFIED ProviderEnvironmentValueClassification = 0 + ProviderEnvironmentValueClassification_PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_NON_SECRET ProviderEnvironmentValueClassification = 1 + ProviderEnvironmentValueClassification_PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_STATIC_CREDENTIAL ProviderEnvironmentValueClassification = 2 +) + +// Enum value maps for ProviderEnvironmentValueClassification. +var ( + ProviderEnvironmentValueClassification_name = map[int32]string{ + 0: "PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_UNSPECIFIED", + 1: "PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_NON_SECRET", + 2: "PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_STATIC_CREDENTIAL", + } + ProviderEnvironmentValueClassification_value = map[string]int32{ + "PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_UNSPECIFIED": 0, + "PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_NON_SECRET": 1, + "PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_STATIC_CREDENTIAL": 2, + } +) + +func (x ProviderEnvironmentValueClassification) Enum() *ProviderEnvironmentValueClassification { + p := new(ProviderEnvironmentValueClassification) + *p = x + return p +} + +func (x ProviderEnvironmentValueClassification) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ProviderEnvironmentValueClassification) Descriptor() protoreflect.EnumDescriptor { + return file_openshell_proto_enumTypes[4].Descriptor() +} + +func (ProviderEnvironmentValueClassification) Type() protoreflect.EnumType { + return &file_openshell_proto_enumTypes[4] +} + +func (x ProviderEnvironmentValueClassification) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ProviderEnvironmentValueClassification.Descriptor instead. +func (ProviderEnvironmentValueClassification) EnumDescriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{4} +} + // Policy load status. type PolicyStatus int32 @@ -327,11 +376,11 @@ func (x PolicyStatus) String() string { } func (PolicyStatus) Descriptor() protoreflect.EnumDescriptor { - return file_openshell_proto_enumTypes[4].Descriptor() + return file_openshell_proto_enumTypes[5].Descriptor() } func (PolicyStatus) Type() protoreflect.EnumType { - return &file_openshell_proto_enumTypes[4] + return &file_openshell_proto_enumTypes[5] } func (x PolicyStatus) Number() protoreflect.EnumNumber { @@ -340,7 +389,123 @@ func (x PolicyStatus) Number() protoreflect.EnumNumber { // Deprecated: Use PolicyStatus.Descriptor instead. func (PolicyStatus) EnumDescriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{4} + return file_openshell_proto_rawDescGZIP(), []int{5} +} + +type ConfigComponent int32 + +const ( + ConfigComponent_CONFIG_COMPONENT_UNSPECIFIED ConfigComponent = 0 + ConfigComponent_CONFIG_COMPONENT_SANDBOX_CONFIG ConfigComponent = 1 + ConfigComponent_CONFIG_COMPONENT_PROVIDER_ENVIRONMENT ConfigComponent = 2 +) + +// Enum value maps for ConfigComponent. +var ( + ConfigComponent_name = map[int32]string{ + 0: "CONFIG_COMPONENT_UNSPECIFIED", + 1: "CONFIG_COMPONENT_SANDBOX_CONFIG", + 2: "CONFIG_COMPONENT_PROVIDER_ENVIRONMENT", + } + ConfigComponent_value = map[string]int32{ + "CONFIG_COMPONENT_UNSPECIFIED": 0, + "CONFIG_COMPONENT_SANDBOX_CONFIG": 1, + "CONFIG_COMPONENT_PROVIDER_ENVIRONMENT": 2, + } +) + +func (x ConfigComponent) Enum() *ConfigComponent { + p := new(ConfigComponent) + *p = x + return p +} + +func (x ConfigComponent) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ConfigComponent) Descriptor() protoreflect.EnumDescriptor { + return file_openshell_proto_enumTypes[6].Descriptor() +} + +func (ConfigComponent) Type() protoreflect.EnumType { + return &file_openshell_proto_enumTypes[6] +} + +func (x ConfigComponent) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ConfigComponent.Descriptor instead. +func (ConfigComponent) EnumDescriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{6} +} + +type ConfigApplyOutcome int32 + +const ( + ConfigApplyOutcome_CONFIG_APPLY_OUTCOME_UNSPECIFIED ConfigApplyOutcome = 0 + ConfigApplyOutcome_CONFIG_APPLY_OUTCOME_APPLIED ConfigApplyOutcome = 1 + ConfigApplyOutcome_CONFIG_APPLY_OUTCOME_IGNORED_DUPLICATE ConfigApplyOutcome = 2 + ConfigApplyOutcome_CONFIG_APPLY_OUTCOME_IGNORED_STALE ConfigApplyOutcome = 3 + ConfigApplyOutcome_CONFIG_APPLY_OUTCOME_RETAINED_LOCAL_OVERRIDE ConfigApplyOutcome = 4 + ConfigApplyOutcome_CONFIG_APPLY_OUTCOME_DEGRADED ConfigApplyOutcome = 5 + ConfigApplyOutcome_CONFIG_APPLY_OUTCOME_FAILED_RETAINED_LAST_KNOWN_GOOD ConfigApplyOutcome = 6 + ConfigApplyOutcome_CONFIG_APPLY_OUTCOME_FAILED_CLOSED ConfigApplyOutcome = 7 + ConfigApplyOutcome_CONFIG_APPLY_OUTCOME_UNSUPPORTED ConfigApplyOutcome = 8 +) + +// Enum value maps for ConfigApplyOutcome. +var ( + ConfigApplyOutcome_name = map[int32]string{ + 0: "CONFIG_APPLY_OUTCOME_UNSPECIFIED", + 1: "CONFIG_APPLY_OUTCOME_APPLIED", + 2: "CONFIG_APPLY_OUTCOME_IGNORED_DUPLICATE", + 3: "CONFIG_APPLY_OUTCOME_IGNORED_STALE", + 4: "CONFIG_APPLY_OUTCOME_RETAINED_LOCAL_OVERRIDE", + 5: "CONFIG_APPLY_OUTCOME_DEGRADED", + 6: "CONFIG_APPLY_OUTCOME_FAILED_RETAINED_LAST_KNOWN_GOOD", + 7: "CONFIG_APPLY_OUTCOME_FAILED_CLOSED", + 8: "CONFIG_APPLY_OUTCOME_UNSUPPORTED", + } + ConfigApplyOutcome_value = map[string]int32{ + "CONFIG_APPLY_OUTCOME_UNSPECIFIED": 0, + "CONFIG_APPLY_OUTCOME_APPLIED": 1, + "CONFIG_APPLY_OUTCOME_IGNORED_DUPLICATE": 2, + "CONFIG_APPLY_OUTCOME_IGNORED_STALE": 3, + "CONFIG_APPLY_OUTCOME_RETAINED_LOCAL_OVERRIDE": 4, + "CONFIG_APPLY_OUTCOME_DEGRADED": 5, + "CONFIG_APPLY_OUTCOME_FAILED_RETAINED_LAST_KNOWN_GOOD": 6, + "CONFIG_APPLY_OUTCOME_FAILED_CLOSED": 7, + "CONFIG_APPLY_OUTCOME_UNSUPPORTED": 8, + } +) + +func (x ConfigApplyOutcome) Enum() *ConfigApplyOutcome { + p := new(ConfigApplyOutcome) + *p = x + return p +} + +func (x ConfigApplyOutcome) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ConfigApplyOutcome) Descriptor() protoreflect.EnumDescriptor { + return file_openshell_proto_enumTypes[7].Descriptor() +} + +func (ConfigApplyOutcome) Type() protoreflect.EnumType { + return &file_openshell_proto_enumTypes[7] +} + +func (x ConfigApplyOutcome) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ConfigApplyOutcome.Descriptor instead. +func (ConfigApplyOutcome) EnumDescriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{7} } // Service status enum. @@ -380,11 +545,11 @@ func (x ServiceStatus) String() string { } func (ServiceStatus) Descriptor() protoreflect.EnumDescriptor { - return file_openshell_proto_enumTypes[5].Descriptor() + return file_openshell_proto_enumTypes[8].Descriptor() } func (ServiceStatus) Type() protoreflect.EnumType { - return &file_openshell_proto_enumTypes[5] + return &file_openshell_proto_enumTypes[8] } func (x ServiceStatus) Number() protoreflect.EnumNumber { @@ -393,7 +558,7 @@ func (x ServiceStatus) Number() protoreflect.EnumNumber { // Deprecated: Use ServiceStatus.Descriptor instead. func (ServiceStatus) EnumDescriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{5} + return file_openshell_proto_rawDescGZIP(), []int{8} } // Workspace-scoped role for members. @@ -430,11 +595,11 @@ func (x WorkspaceRole) String() string { } func (WorkspaceRole) Descriptor() protoreflect.EnumDescriptor { - return file_openshell_proto_enumTypes[6].Descriptor() + return file_openshell_proto_enumTypes[9].Descriptor() } func (WorkspaceRole) Type() protoreflect.EnumType { - return &file_openshell_proto_enumTypes[6] + return &file_openshell_proto_enumTypes[9] } func (x WorkspaceRole) Number() protoreflect.EnumNumber { @@ -443,7 +608,7 @@ func (x WorkspaceRole) Number() protoreflect.EnumNumber { // Deprecated: Use WorkspaceRole.Descriptor instead. func (WorkspaceRole) EnumDescriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{6} + return file_openshell_proto_rawDescGZIP(), []int{9} } // Stable recovery action for the most recent provider credential refresh @@ -489,11 +654,11 @@ func (x ProviderCredentialRefreshRecoveryAction) String() string { } func (ProviderCredentialRefreshRecoveryAction) Descriptor() protoreflect.EnumDescriptor { - return file_openshell_proto_enumTypes[7].Descriptor() + return file_openshell_proto_enumTypes[10].Descriptor() } func (ProviderCredentialRefreshRecoveryAction) Type() protoreflect.EnumType { - return &file_openshell_proto_enumTypes[7] + return &file_openshell_proto_enumTypes[10] } func (x ProviderCredentialRefreshRecoveryAction) Number() protoreflect.EnumNumber { @@ -502,7 +667,7 @@ func (x ProviderCredentialRefreshRecoveryAction) Number() protoreflect.EnumNumbe // Deprecated: Use ProviderCredentialRefreshRecoveryAction.Descriptor instead. func (ProviderCredentialRefreshRecoveryAction) EnumDescriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{7} + return file_openshell_proto_rawDescGZIP(), []int{10} } // IssueSandboxToken request. Empty body; identity is established by the @@ -8808,6 +8973,146 @@ func (x *GetSandboxProviderEnvironmentResponse) GetNonSecretEnvironmentKeys() [] return nil } +// One environment value and all metadata that shares its key. +type ProviderEnvironmentValue struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + ExpiresAtMs *int64 `protobuf:"varint,3,opt,name=expires_at_ms,json=expiresAtMs,proto3,oneof" json:"expires_at_ms,omitempty"` + Classification ProviderEnvironmentValueClassification `protobuf:"varint,4,opt,name=classification,proto3,enum=openshell.v1.ProviderEnvironmentValueClassification" json:"classification,omitempty"` + StaticCredentialBinding *StaticCredentialBinding `protobuf:"bytes,5,opt,name=static_credential_binding,json=staticCredentialBinding,proto3" json:"static_credential_binding,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProviderEnvironmentValue) Reset() { + *x = ProviderEnvironmentValue{} + mi := &file_openshell_proto_msgTypes[125] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProviderEnvironmentValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProviderEnvironmentValue) ProtoMessage() {} + +func (x *ProviderEnvironmentValue) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[125] + 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 ProviderEnvironmentValue.ProtoReflect.Descriptor instead. +func (*ProviderEnvironmentValue) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{125} +} + +func (x *ProviderEnvironmentValue) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ProviderEnvironmentValue) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *ProviderEnvironmentValue) GetExpiresAtMs() int64 { + if x != nil && x.ExpiresAtMs != nil { + return *x.ExpiresAtMs + } + return 0 +} + +func (x *ProviderEnvironmentValue) GetClassification() ProviderEnvironmentValueClassification { + if x != nil { + return x.Classification + } + return ProviderEnvironmentValueClassification_PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_UNSPECIFIED +} + +func (x *ProviderEnvironmentValue) GetStaticCredentialBinding() *StaticCredentialBinding { + if x != nil { + return x.StaticCredentialBinding + } + return nil +} + +// Complete provider environment state delivered to a supervisor. Dynamic +// credentials are endpoint selectors rather than environment values and stay +// in their own collection. +type ProviderEnvironmentSnapshot struct { + state protoimpl.MessageState `protogen:"open.v1"` + ProviderEnvRevision uint64 `protobuf:"varint,1,opt,name=provider_env_revision,json=providerEnvRevision,proto3" json:"provider_env_revision,omitempty"` + Values []*ProviderEnvironmentValue `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"` + DynamicCredentials map[string]*ProviderProfileCredential `protobuf:"bytes,3,rep,name=dynamic_credentials,json=dynamicCredentials,proto3" json:"dynamic_credentials,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProviderEnvironmentSnapshot) Reset() { + *x = ProviderEnvironmentSnapshot{} + mi := &file_openshell_proto_msgTypes[126] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProviderEnvironmentSnapshot) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProviderEnvironmentSnapshot) ProtoMessage() {} + +func (x *ProviderEnvironmentSnapshot) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[126] + 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 ProviderEnvironmentSnapshot.ProtoReflect.Descriptor instead. +func (*ProviderEnvironmentSnapshot) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{126} +} + +func (x *ProviderEnvironmentSnapshot) GetProviderEnvRevision() uint64 { + if x != nil { + return x.ProviderEnvRevision + } + return 0 +} + +func (x *ProviderEnvironmentSnapshot) GetValues() []*ProviderEnvironmentValue { + if x != nil { + return x.Values + } + return nil +} + +func (x *ProviderEnvironmentSnapshot) GetDynamicCredentials() map[string]*ProviderProfileCredential { + if x != nil { + return x.DynamicCredentials + } + return nil +} + type ExchangeProviderSubjectTokenRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // The sandbox ID. Must match the authenticated sandbox principal. @@ -8825,7 +9130,7 @@ type ExchangeProviderSubjectTokenRequest struct { func (x *ExchangeProviderSubjectTokenRequest) Reset() { *x = ExchangeProviderSubjectTokenRequest{} - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8837,7 +9142,7 @@ func (x *ExchangeProviderSubjectTokenRequest) String() string { func (*ExchangeProviderSubjectTokenRequest) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenRequest) 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 { @@ -8850,7 +9155,7 @@ func (x *ExchangeProviderSubjectTokenRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use ExchangeProviderSubjectTokenRequest.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{125} + return file_openshell_proto_rawDescGZIP(), []int{127} } func (x *ExchangeProviderSubjectTokenRequest) GetSandboxId() string { @@ -8892,7 +9197,7 @@ type ExchangeProviderSubjectTokenResponse struct { func (x *ExchangeProviderSubjectTokenResponse) Reset() { *x = ExchangeProviderSubjectTokenResponse{} - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8904,7 +9209,7 @@ func (x *ExchangeProviderSubjectTokenResponse) String() string { func (*ExchangeProviderSubjectTokenResponse) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenResponse) 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 { @@ -8917,7 +9222,7 @@ func (x *ExchangeProviderSubjectTokenResponse) ProtoReflect() protoreflect.Messa // Deprecated: Use ExchangeProviderSubjectTokenResponse.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{126} + return file_openshell_proto_rawDescGZIP(), []int{128} } func (x *ExchangeProviderSubjectTokenResponse) GetAccessToken() string { @@ -8989,7 +9294,7 @@ type UpdateConfigRequest struct { func (x *UpdateConfigRequest) Reset() { *x = UpdateConfigRequest{} - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9001,7 +9306,7 @@ func (x *UpdateConfigRequest) String() string { func (*UpdateConfigRequest) ProtoMessage() {} func (x *UpdateConfigRequest) 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 { @@ -9014,7 +9319,7 @@ func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigRequest.ProtoReflect.Descriptor instead. func (*UpdateConfigRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{127} + return file_openshell_proto_rawDescGZIP(), []int{129} } func (x *UpdateConfigRequest) GetName() string { @@ -9104,7 +9409,7 @@ type PolicyMergeOperation struct { func (x *PolicyMergeOperation) Reset() { *x = PolicyMergeOperation{} - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9116,7 +9421,7 @@ func (x *PolicyMergeOperation) String() string { func (*PolicyMergeOperation) ProtoMessage() {} func (x *PolicyMergeOperation) 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 { @@ -9129,7 +9434,7 @@ func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyMergeOperation.ProtoReflect.Descriptor instead. func (*PolicyMergeOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{128} + return file_openshell_proto_rawDescGZIP(), []int{130} } func (x *PolicyMergeOperation) GetOperation() isPolicyMergeOperation_Operation { @@ -9243,7 +9548,7 @@ type AddNetworkRule struct { func (x *AddNetworkRule) Reset() { *x = AddNetworkRule{} - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9255,7 +9560,7 @@ func (x *AddNetworkRule) String() string { func (*AddNetworkRule) ProtoMessage() {} func (x *AddNetworkRule) 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 { @@ -9268,7 +9573,7 @@ func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use AddNetworkRule.ProtoReflect.Descriptor instead. func (*AddNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{129} + return file_openshell_proto_rawDescGZIP(), []int{131} } func (x *AddNetworkRule) GetRuleName() string { @@ -9296,7 +9601,7 @@ type RemoveNetworkEndpoint struct { func (x *RemoveNetworkEndpoint) Reset() { *x = RemoveNetworkEndpoint{} - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9308,7 +9613,7 @@ func (x *RemoveNetworkEndpoint) String() string { func (*RemoveNetworkEndpoint) ProtoMessage() {} func (x *RemoveNetworkEndpoint) 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 { @@ -9321,7 +9626,7 @@ func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkEndpoint.ProtoReflect.Descriptor instead. func (*RemoveNetworkEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{130} + return file_openshell_proto_rawDescGZIP(), []int{132} } func (x *RemoveNetworkEndpoint) GetRuleName() string { @@ -9354,7 +9659,7 @@ type RemoveNetworkRule struct { func (x *RemoveNetworkRule) Reset() { *x = RemoveNetworkRule{} - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9366,7 +9671,7 @@ func (x *RemoveNetworkRule) String() string { func (*RemoveNetworkRule) ProtoMessage() {} func (x *RemoveNetworkRule) 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 { @@ -9379,7 +9684,7 @@ func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkRule.ProtoReflect.Descriptor instead. func (*RemoveNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{131} + return file_openshell_proto_rawDescGZIP(), []int{133} } func (x *RemoveNetworkRule) GetRuleName() string { @@ -9400,7 +9705,7 @@ type AddDenyRules struct { func (x *AddDenyRules) Reset() { *x = AddDenyRules{} - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9412,7 +9717,7 @@ func (x *AddDenyRules) String() string { func (*AddDenyRules) ProtoMessage() {} func (x *AddDenyRules) 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 { @@ -9425,7 +9730,7 @@ func (x *AddDenyRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddDenyRules.ProtoReflect.Descriptor instead. func (*AddDenyRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{132} + return file_openshell_proto_rawDescGZIP(), []int{134} } func (x *AddDenyRules) GetHost() string { @@ -9460,7 +9765,7 @@ type AddAllowRules struct { func (x *AddAllowRules) Reset() { *x = AddAllowRules{} - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9472,7 +9777,7 @@ func (x *AddAllowRules) String() string { func (*AddAllowRules) ProtoMessage() {} func (x *AddAllowRules) 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 { @@ -9485,7 +9790,7 @@ func (x *AddAllowRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAllowRules.ProtoReflect.Descriptor instead. func (*AddAllowRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{133} + return file_openshell_proto_rawDescGZIP(), []int{135} } func (x *AddAllowRules) GetHost() string { @@ -9519,7 +9824,7 @@ type RemoveNetworkBinary struct { func (x *RemoveNetworkBinary) Reset() { *x = RemoveNetworkBinary{} - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9531,7 +9836,7 @@ func (x *RemoveNetworkBinary) String() string { func (*RemoveNetworkBinary) ProtoMessage() {} func (x *RemoveNetworkBinary) 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 { @@ -9544,7 +9849,7 @@ func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkBinary.ProtoReflect.Descriptor instead. func (*RemoveNetworkBinary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{134} + return file_openshell_proto_rawDescGZIP(), []int{136} } func (x *RemoveNetworkBinary) GetRuleName() string { @@ -9580,7 +9885,7 @@ type UpdateConfigResponse struct { func (x *UpdateConfigResponse) Reset() { *x = UpdateConfigResponse{} - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9592,7 +9897,7 @@ func (x *UpdateConfigResponse) String() string { func (*UpdateConfigResponse) ProtoMessage() {} func (x *UpdateConfigResponse) 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 { @@ -9605,7 +9910,7 @@ func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigResponse.ProtoReflect.Descriptor instead. func (*UpdateConfigResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{135} + return file_openshell_proto_rawDescGZIP(), []int{137} } func (x *UpdateConfigResponse) GetVersion() uint32 { @@ -9661,7 +9966,7 @@ type GetSandboxPolicyStatusRequest struct { func (x *GetSandboxPolicyStatusRequest) Reset() { *x = GetSandboxPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9673,7 +9978,7 @@ func (x *GetSandboxPolicyStatusRequest) String() string { func (*GetSandboxPolicyStatusRequest) ProtoMessage() {} func (x *GetSandboxPolicyStatusRequest) 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 { @@ -9686,7 +9991,7 @@ func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{136} + return file_openshell_proto_rawDescGZIP(), []int{138} } func (x *GetSandboxPolicyStatusRequest) GetName() string { @@ -9730,7 +10035,7 @@ type GetSandboxPolicyStatusResponse struct { func (x *GetSandboxPolicyStatusResponse) Reset() { *x = GetSandboxPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9742,7 +10047,7 @@ func (x *GetSandboxPolicyStatusResponse) String() string { func (*GetSandboxPolicyStatusResponse) ProtoMessage() {} func (x *GetSandboxPolicyStatusResponse) 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 { @@ -9755,7 +10060,7 @@ func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{137} + return file_openshell_proto_rawDescGZIP(), []int{139} } func (x *GetSandboxPolicyStatusResponse) GetRevision() *SandboxPolicyRevision { @@ -9794,7 +10099,7 @@ type ListSandboxPoliciesRequest struct { func (x *ListSandboxPoliciesRequest) Reset() { *x = ListSandboxPoliciesRequest{} - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[140] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9806,7 +10111,7 @@ func (x *ListSandboxPoliciesRequest) String() string { func (*ListSandboxPoliciesRequest) ProtoMessage() {} func (x *ListSandboxPoliciesRequest) 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 { @@ -9819,7 +10124,7 @@ func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{138} + return file_openshell_proto_rawDescGZIP(), []int{140} } func (x *ListSandboxPoliciesRequest) GetName() string { @@ -9871,7 +10176,7 @@ type ListSandboxPoliciesResponse struct { func (x *ListSandboxPoliciesResponse) Reset() { *x = ListSandboxPoliciesResponse{} - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9883,7 +10188,7 @@ func (x *ListSandboxPoliciesResponse) String() string { func (*ListSandboxPoliciesResponse) ProtoMessage() {} func (x *ListSandboxPoliciesResponse) 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 { @@ -9896,7 +10201,7 @@ func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{139} + return file_openshell_proto_rawDescGZIP(), []int{141} } func (x *ListSandboxPoliciesResponse) GetRevisions() []*SandboxPolicyRevision { @@ -9930,7 +10235,7 @@ type ReportPolicyStatusRequest struct { func (x *ReportPolicyStatusRequest) Reset() { *x = ReportPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[142] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9942,7 +10247,7 @@ func (x *ReportPolicyStatusRequest) String() string { func (*ReportPolicyStatusRequest) ProtoMessage() {} func (x *ReportPolicyStatusRequest) 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 { @@ -9955,7 +10260,7 @@ func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{140} + return file_openshell_proto_rawDescGZIP(), []int{142} } func (x *ReportPolicyStatusRequest) GetSandboxId() string { @@ -9995,7 +10300,7 @@ type ReportPolicyStatusResponse struct { func (x *ReportPolicyStatusResponse) Reset() { *x = ReportPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[143] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10007,7 +10312,7 @@ func (x *ReportPolicyStatusResponse) String() string { func (*ReportPolicyStatusResponse) ProtoMessage() {} func (x *ReportPolicyStatusResponse) 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 { @@ -10020,7 +10325,7 @@ func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{141} + return file_openshell_proto_rawDescGZIP(), []int{143} } // A versioned policy revision with metadata. @@ -10053,7 +10358,7 @@ type SandboxPolicyRevision struct { func (x *SandboxPolicyRevision) Reset() { *x = SandboxPolicyRevision{} - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[144] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10065,7 +10370,7 @@ func (x *SandboxPolicyRevision) String() string { func (*SandboxPolicyRevision) ProtoMessage() {} func (x *SandboxPolicyRevision) 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 { @@ -10078,7 +10383,7 @@ func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxPolicyRevision.ProtoReflect.Descriptor instead. func (*SandboxPolicyRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{142} + return file_openshell_proto_rawDescGZIP(), []int{144} } func (x *SandboxPolicyRevision) GetVersion() uint32 { @@ -10158,7 +10463,7 @@ type GetSandboxLogsRequest struct { func (x *GetSandboxLogsRequest) Reset() { *x = GetSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10170,7 +10475,7 @@ func (x *GetSandboxLogsRequest) String() string { func (*GetSandboxLogsRequest) ProtoMessage() {} func (x *GetSandboxLogsRequest) 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 { @@ -10183,7 +10488,7 @@ func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*GetSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{143} + return file_openshell_proto_rawDescGZIP(), []int{145} } func (x *GetSandboxLogsRequest) GetSandboxId() string { @@ -10241,7 +10546,7 @@ type PushSandboxLogsRequest struct { func (x *PushSandboxLogsRequest) Reset() { *x = PushSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10253,7 +10558,7 @@ func (x *PushSandboxLogsRequest) String() string { func (*PushSandboxLogsRequest) ProtoMessage() {} func (x *PushSandboxLogsRequest) 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 { @@ -10266,7 +10571,7 @@ func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*PushSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{144} + return file_openshell_proto_rawDescGZIP(), []int{146} } func (x *PushSandboxLogsRequest) GetSandboxId() string { @@ -10292,7 +10597,7 @@ type PushSandboxLogsResponse struct { func (x *PushSandboxLogsResponse) Reset() { *x = PushSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[147] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10304,7 +10609,7 @@ func (x *PushSandboxLogsResponse) String() string { func (*PushSandboxLogsResponse) ProtoMessage() {} func (x *PushSandboxLogsResponse) 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 { @@ -10317,7 +10622,7 @@ func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*PushSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{145} + return file_openshell_proto_rawDescGZIP(), []int{147} } // Get sandbox logs response. @@ -10333,7 +10638,7 @@ type GetSandboxLogsResponse struct { func (x *GetSandboxLogsResponse) Reset() { *x = GetSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10345,7 +10650,7 @@ func (x *GetSandboxLogsResponse) String() string { func (*GetSandboxLogsResponse) ProtoMessage() {} func (x *GetSandboxLogsResponse) 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 { @@ -10358,7 +10663,7 @@ func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*GetSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{146} + return file_openshell_proto_rawDescGZIP(), []int{148} } func (x *GetSandboxLogsResponse) GetLogs() []*SandboxLogLine { @@ -10384,6 +10689,8 @@ type SupervisorMessage struct { // *SupervisorMessage_Heartbeat // *SupervisorMessage_RelayOpenResult // *SupervisorMessage_RelayClose + // *SupervisorMessage_ConfigUpdateResult + // *SupervisorMessage_ConfigBootstrapResult Payload isSupervisorMessage_Payload `protobuf_oneof:"payload"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -10391,7 +10698,7 @@ type SupervisorMessage struct { func (x *SupervisorMessage) Reset() { *x = SupervisorMessage{} - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10403,7 +10710,7 @@ func (x *SupervisorMessage) String() string { func (*SupervisorMessage) ProtoMessage() {} func (x *SupervisorMessage) 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 { @@ -10416,7 +10723,7 @@ func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMessage.ProtoReflect.Descriptor instead. func (*SupervisorMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{147} + return file_openshell_proto_rawDescGZIP(), []int{149} } func (x *SupervisorMessage) GetPayload() isSupervisorMessage_Payload { @@ -10462,6 +10769,24 @@ func (x *SupervisorMessage) GetRelayClose() *RelayClose { return nil } +func (x *SupervisorMessage) GetConfigUpdateResult() *ConfigUpdateResult { + if x != nil { + if x, ok := x.Payload.(*SupervisorMessage_ConfigUpdateResult); ok { + return x.ConfigUpdateResult + } + } + return nil +} + +func (x *SupervisorMessage) GetConfigBootstrapResult() *ConfigBootstrapResult { + if x != nil { + if x, ok := x.Payload.(*SupervisorMessage_ConfigBootstrapResult); ok { + return x.ConfigBootstrapResult + } + } + return nil +} + type isSupervisorMessage_Payload interface { isSupervisorMessage_Payload() } @@ -10482,6 +10807,14 @@ type SupervisorMessage_RelayClose struct { RelayClose *RelayClose `protobuf:"bytes,4,opt,name=relay_close,json=relayClose,proto3,oneof"` } +type SupervisorMessage_ConfigUpdateResult struct { + ConfigUpdateResult *ConfigUpdateResult `protobuf:"bytes,5,opt,name=config_update_result,json=configUpdateResult,proto3,oneof"` +} + +type SupervisorMessage_ConfigBootstrapResult struct { + ConfigBootstrapResult *ConfigBootstrapResult `protobuf:"bytes,6,opt,name=config_bootstrap_result,json=configBootstrapResult,proto3,oneof"` +} + func (*SupervisorMessage_Hello) isSupervisorMessage_Payload() {} func (*SupervisorMessage_Heartbeat) isSupervisorMessage_Payload() {} @@ -10490,6 +10823,10 @@ func (*SupervisorMessage_RelayOpenResult) isSupervisorMessage_Payload() {} func (*SupervisorMessage_RelayClose) isSupervisorMessage_Payload() {} +func (*SupervisorMessage_ConfigUpdateResult) isSupervisorMessage_Payload() {} + +func (*SupervisorMessage_ConfigBootstrapResult) isSupervisorMessage_Payload() {} + // Envelope for gateway-to-supervisor messages on the ConnectSupervisor stream. type GatewayMessage struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -10500,6 +10837,7 @@ type GatewayMessage struct { // *GatewayMessage_Heartbeat // *GatewayMessage_RelayOpen // *GatewayMessage_RelayClose + // *GatewayMessage_ConfigUpdate Payload isGatewayMessage_Payload `protobuf_oneof:"payload"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -10507,7 +10845,7 @@ type GatewayMessage struct { func (x *GatewayMessage) Reset() { *x = GatewayMessage{} - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10519,7 +10857,7 @@ func (x *GatewayMessage) String() string { func (*GatewayMessage) ProtoMessage() {} func (x *GatewayMessage) 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 { @@ -10532,7 +10870,7 @@ func (x *GatewayMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayMessage.ProtoReflect.Descriptor instead. func (*GatewayMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{148} + return file_openshell_proto_rawDescGZIP(), []int{150} } func (x *GatewayMessage) GetPayload() isGatewayMessage_Payload { @@ -10587,6 +10925,15 @@ func (x *GatewayMessage) GetRelayClose() *RelayClose { return nil } +func (x *GatewayMessage) GetConfigUpdate() *ConfigUpdate { + if x != nil { + if x, ok := x.Payload.(*GatewayMessage_ConfigUpdate); ok { + return x.ConfigUpdate + } + } + return nil +} + type isGatewayMessage_Payload interface { isGatewayMessage_Payload() } @@ -10611,6 +10958,10 @@ type GatewayMessage_RelayClose struct { RelayClose *RelayClose `protobuf:"bytes,5,opt,name=relay_close,json=relayClose,proto3,oneof"` } +type GatewayMessage_ConfigUpdate struct { + ConfigUpdate *ConfigUpdate `protobuf:"bytes,6,opt,name=config_update,json=configUpdate,proto3,oneof"` +} + func (*GatewayMessage_SessionAccepted) isGatewayMessage_Payload() {} func (*GatewayMessage_SessionRejected) isGatewayMessage_Payload() {} @@ -10621,20 +10972,24 @@ func (*GatewayMessage_RelayOpen) isGatewayMessage_Payload() {} func (*GatewayMessage_RelayClose) isGatewayMessage_Payload() {} +func (*GatewayMessage_ConfigUpdate) isGatewayMessage_Payload() {} + // Supervisor identifies itself and the sandbox it manages. type SupervisorHello struct { state protoimpl.MessageState `protogen:"open.v1"` // Sandbox ID this supervisor manages. SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` // Supervisor instance ID (e.g. boot id or process epoch). - InstanceId string `protobuf:"bytes,2,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + InstanceId string `protobuf:"bytes,2,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` + // Exact internal stream protocol revision implemented by this supervisor. + ProtocolRevision uint32 `protobuf:"varint,3,opt,name=protocol_revision,json=protocolRevision,proto3" json:"protocol_revision,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SupervisorHello) Reset() { *x = SupervisorHello{} - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10646,7 +11001,7 @@ func (x *SupervisorHello) String() string { func (*SupervisorHello) ProtoMessage() {} func (x *SupervisorHello) 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 { @@ -10659,7 +11014,7 @@ func (x *SupervisorHello) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHello.ProtoReflect.Descriptor instead. func (*SupervisorHello) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{149} + return file_openshell_proto_rawDescGZIP(), []int{151} } func (x *SupervisorHello) GetSandboxId() string { @@ -10676,6 +11031,13 @@ func (x *SupervisorHello) GetInstanceId() string { return "" } +func (x *SupervisorHello) GetProtocolRevision() uint32 { + if x != nil { + return x.ProtocolRevision + } + return 0 +} + // Gateway accepts the supervisor session. type SessionAccepted struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -10683,13 +11045,18 @@ type SessionAccepted struct { SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` // Recommended heartbeat interval in seconds. HeartbeatIntervalSecs uint32 `protobuf:"varint,2,opt,name=heartbeat_interval_secs,json=heartbeatIntervalSecs,proto3" json:"heartbeat_interval_secs,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Complete gateway-owned configuration. During the staged rollout this may + // be omitted only when the gateway cannot build the projection. + Bootstrap *ConfigBootstrap `protobuf:"bytes,3,opt,name=bootstrap,proto3" json:"bootstrap,omitempty"` + // Exact internal stream protocol revision implemented by this gateway. + ProtocolRevision uint32 `protobuf:"varint,4,opt,name=protocol_revision,json=protocolRevision,proto3" json:"protocol_revision,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SessionAccepted) Reset() { *x = SessionAccepted{} - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10701,7 +11068,7 @@ func (x *SessionAccepted) String() string { func (*SessionAccepted) ProtoMessage() {} func (x *SessionAccepted) 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 { @@ -10714,7 +11081,7 @@ func (x *SessionAccepted) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionAccepted.ProtoReflect.Descriptor instead. func (*SessionAccepted) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{150} + return file_openshell_proto_rawDescGZIP(), []int{152} } func (x *SessionAccepted) GetSessionId() string { @@ -10731,30 +11098,44 @@ func (x *SessionAccepted) GetHeartbeatIntervalSecs() uint32 { return 0 } -// Gateway rejects the supervisor session. -type SessionRejected struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Human-readable rejection reason. - Reason string `protobuf:"bytes,1,opt,name=reason,proto3" json:"reason,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +func (x *SessionAccepted) GetBootstrap() *ConfigBootstrap { + if x != nil { + return x.Bootstrap + } + return nil } -func (x *SessionRejected) Reset() { - *x = SessionRejected{} - mi := &file_openshell_proto_msgTypes[151] +func (x *SessionAccepted) GetProtocolRevision() uint32 { + if x != nil { + return x.ProtocolRevision + } + return 0 +} + +// Complete gateway-owned configuration for a supervisor session. +type ConfigBootstrap struct { + state protoimpl.MessageState `protogen:"open.v1"` + SandboxConfig *sandboxv1.SandboxConfigSnapshot `protobuf:"bytes,1,opt,name=sandbox_config,json=sandboxConfig,proto3" json:"sandbox_config,omitempty"` + ProviderEnvironment *ProviderEnvironmentSnapshot `protobuf:"bytes,2,opt,name=provider_environment,json=providerEnvironment,proto3" json:"provider_environment,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConfigBootstrap) Reset() { + *x = ConfigBootstrap{} + mi := &file_openshell_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SessionRejected) String() string { +func (x *ConfigBootstrap) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SessionRejected) ProtoMessage() {} +func (*ConfigBootstrap) ProtoMessage() {} -func (x *SessionRejected) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[151] +func (x *ConfigBootstrap) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[153] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10765,40 +11146,57 @@ func (x *SessionRejected) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SessionRejected.ProtoReflect.Descriptor instead. -func (*SessionRejected) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{151} +// Deprecated: Use ConfigBootstrap.ProtoReflect.Descriptor instead. +func (*ConfigBootstrap) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{153} } -func (x *SessionRejected) GetReason() string { +func (x *ConfigBootstrap) GetSandboxConfig() *sandboxv1.SandboxConfigSnapshot { if x != nil { - return x.Reason + return x.SandboxConfig } - return "" + return nil } -// Supervisor heartbeat. -type SupervisorHeartbeat struct { - state protoimpl.MessageState `protogen:"open.v1"` +func (x *ConfigBootstrap) GetProviderEnvironment() *ProviderEnvironmentSnapshot { + if x != nil { + return x.ProviderEnvironment + } + return nil +} + +// A complete replacement snapshot for exactly one configuration component. +type ConfigUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Opaque non-empty identifier scoped to the active supervisor session. + UpdateId string `protobuf:"bytes,1,opt,name=update_id,json=updateId,proto3" json:"update_id,omitempty"` + // Monotonic within one session and component. Snapshot revisions are + // content identities and must only be compared for equality. + ComponentSequence uint64 `protobuf:"varint,2,opt,name=component_sequence,json=componentSequence,proto3" json:"component_sequence,omitempty"` + // Types that are valid to be assigned to Component: + // + // *ConfigUpdate_SandboxConfig + // *ConfigUpdate_ProviderEnvironment + Component isConfigUpdate_Component `protobuf_oneof:"component"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *SupervisorHeartbeat) Reset() { - *x = SupervisorHeartbeat{} - mi := &file_openshell_proto_msgTypes[152] +func (x *ConfigUpdate) Reset() { + *x = ConfigUpdate{} + mi := &file_openshell_proto_msgTypes[154] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SupervisorHeartbeat) String() string { +func (x *ConfigUpdate) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SupervisorHeartbeat) ProtoMessage() {} +func (*ConfigUpdate) ProtoMessage() {} -func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[152] +func (x *ConfigUpdate) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[154] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10809,75 +11207,616 @@ func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SupervisorHeartbeat.ProtoReflect.Descriptor instead. -func (*SupervisorHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{152} +// Deprecated: Use ConfigUpdate.ProtoReflect.Descriptor instead. +func (*ConfigUpdate) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{154} } -// Gateway heartbeat. -type GatewayHeartbeat struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +func (x *ConfigUpdate) GetUpdateId() string { + if x != nil { + return x.UpdateId + } + return "" } -func (x *GatewayHeartbeat) Reset() { - *x = GatewayHeartbeat{} - mi := &file_openshell_proto_msgTypes[153] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) +func (x *ConfigUpdate) GetComponentSequence() uint64 { + if x != nil { + return x.ComponentSequence + } + return 0 } -func (x *GatewayHeartbeat) String() string { - return protoimpl.X.MessageStringOf(x) +func (x *ConfigUpdate) GetComponent() isConfigUpdate_Component { + if x != nil { + return x.Component + } + return nil } -func (*GatewayHeartbeat) ProtoMessage() {} +func (x *ConfigUpdate) GetSandboxConfig() *sandboxv1.SandboxConfigSnapshot { + if x != nil { + if x, ok := x.Component.(*ConfigUpdate_SandboxConfig); ok { + return x.SandboxConfig + } + } + return nil +} -func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[153] +func (x *ConfigUpdate) GetProviderEnvironment() *ProviderEnvironmentSnapshot { if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) + if x, ok := x.Component.(*ConfigUpdate_ProviderEnvironment); ok { + return x.ProviderEnvironment } - return ms } - return mi.MessageOf(x) + return nil } -// Deprecated: Use GatewayHeartbeat.ProtoReflect.Descriptor instead. -func (*GatewayHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{153} +type isConfigUpdate_Component interface { + isConfigUpdate_Component() } -// Terminal result reported before the supervisor shuts down. A successful RPC -// response confirms that the result was durably handled by the gateway. -type ReportMainProcessExitRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` - InstanceId string `protobuf:"bytes,2,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` - // Normalized process result. Signal exits use 128 + signal number. - ExitCode int32 `protobuf:"varint,3,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"` +type ConfigUpdate_SandboxConfig struct { + SandboxConfig *sandboxv1.SandboxConfigSnapshot `protobuf:"bytes,3,opt,name=sandbox_config,json=sandboxConfig,proto3,oneof"` +} + +type ConfigUpdate_ProviderEnvironment struct { + ProviderEnvironment *ProviderEnvironmentSnapshot `protobuf:"bytes,4,opt,name=provider_environment,json=providerEnvironment,proto3,oneof"` +} + +func (*ConfigUpdate_SandboxConfig) isConfigUpdate_Component() {} + +func (*ConfigUpdate_ProviderEnvironment) isConfigUpdate_Component() {} + +// Identifies one component snapshot revision. Revisions are equality tokens, +// not members of one shared ordering domain. +type ConfigSnapshotRevision struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Component: + // + // *ConfigSnapshotRevision_SandboxConfig + // *ConfigSnapshotRevision_ProviderEnvironment + Component isConfigSnapshotRevision_Component `protobuf_oneof:"component"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *ReportMainProcessExitRequest) Reset() { - *x = ReportMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[154] +func (x *ConfigSnapshotRevision) Reset() { + *x = ConfigSnapshotRevision{} + mi := &file_openshell_proto_msgTypes[155] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ReportMainProcessExitRequest) String() string { +func (x *ConfigSnapshotRevision) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfigSnapshotRevision) ProtoMessage() {} + +func (x *ConfigSnapshotRevision) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[155] + 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 ConfigSnapshotRevision.ProtoReflect.Descriptor instead. +func (*ConfigSnapshotRevision) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{155} +} + +func (x *ConfigSnapshotRevision) GetComponent() isConfigSnapshotRevision_Component { + if x != nil { + return x.Component + } + return nil +} + +func (x *ConfigSnapshotRevision) GetSandboxConfig() *SandboxConfigRevision { + if x != nil { + if x, ok := x.Component.(*ConfigSnapshotRevision_SandboxConfig); ok { + return x.SandboxConfig + } + } + return nil +} + +func (x *ConfigSnapshotRevision) GetProviderEnvironment() uint64 { + if x != nil { + if x, ok := x.Component.(*ConfigSnapshotRevision_ProviderEnvironment); ok { + return x.ProviderEnvironment + } + } + return 0 +} + +type isConfigSnapshotRevision_Component interface { + isConfigSnapshotRevision_Component() +} + +type ConfigSnapshotRevision_SandboxConfig struct { + SandboxConfig *SandboxConfigRevision `protobuf:"bytes,1,opt,name=sandbox_config,json=sandboxConfig,proto3,oneof"` +} + +type ConfigSnapshotRevision_ProviderEnvironment struct { + ProviderEnvironment uint64 `protobuf:"varint,2,opt,name=provider_environment,json=providerEnvironment,proto3,oneof"` +} + +func (*ConfigSnapshotRevision_SandboxConfig) isConfigSnapshotRevision_Component() {} + +func (*ConfigSnapshotRevision_ProviderEnvironment) isConfigSnapshotRevision_Component() {} + +// Identity needed to correlate effective sandbox configuration with the +// policy-history row whose apply status the gateway records. +type SandboxConfigRevision struct { + state protoimpl.MessageState `protogen:"open.v1"` + ConfigRevision uint64 `protobuf:"varint,1,opt,name=config_revision,json=configRevision,proto3" json:"config_revision,omitempty"` + PolicyVersion uint32 `protobuf:"varint,2,opt,name=policy_version,json=policyVersion,proto3" json:"policy_version,omitempty"` + PolicySource sandboxv1.PolicySource `protobuf:"varint,3,opt,name=policy_source,json=policySource,proto3,enum=openshell.sandbox.v1.PolicySource" json:"policy_source,omitempty"` + GlobalPolicyVersion uint32 `protobuf:"varint,4,opt,name=global_policy_version,json=globalPolicyVersion,proto3" json:"global_policy_version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxConfigRevision) Reset() { + *x = SandboxConfigRevision{} + mi := &file_openshell_proto_msgTypes[156] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxConfigRevision) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxConfigRevision) ProtoMessage() {} + +func (x *SandboxConfigRevision) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[156] + 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 SandboxConfigRevision.ProtoReflect.Descriptor instead. +func (*SandboxConfigRevision) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{156} +} + +func (x *SandboxConfigRevision) GetConfigRevision() uint64 { + if x != nil { + return x.ConfigRevision + } + return 0 +} + +func (x *SandboxConfigRevision) GetPolicyVersion() uint32 { + if x != nil { + return x.PolicyVersion + } + return 0 +} + +func (x *SandboxConfigRevision) GetPolicySource() sandboxv1.PolicySource { + if x != nil { + return x.PolicySource + } + return sandboxv1.PolicySource(0) +} + +func (x *SandboxConfigRevision) GetGlobalPolicyVersion() uint32 { + if x != nil { + return x.GlobalPolicyVersion + } + return 0 +} + +// Sanitized application failure. Messages must not contain configuration +// payloads, credentials, or provider values. +type ConfigApplyFailure struct { + state protoimpl.MessageState `protogen:"open.v1"` + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + Retryable bool `protobuf:"varint,3,opt,name=retryable,proto3" json:"retryable,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConfigApplyFailure) Reset() { + *x = ConfigApplyFailure{} + mi := &file_openshell_proto_msgTypes[157] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConfigApplyFailure) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfigApplyFailure) ProtoMessage() {} + +func (x *ConfigApplyFailure) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[157] + 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 ConfigApplyFailure.ProtoReflect.Descriptor instead. +func (*ConfigApplyFailure) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{157} +} + +func (x *ConfigApplyFailure) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *ConfigApplyFailure) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *ConfigApplyFailure) GetRetryable() bool { + if x != nil { + return x.Retryable + } + return false +} + +type ConfigComponentApplyResult struct { + state protoimpl.MessageState `protogen:"open.v1"` + Component ConfigComponent `protobuf:"varint,1,opt,name=component,proto3,enum=openshell.v1.ConfigComponent" json:"component,omitempty"` + // Revision extracted from the received snapshot. + RequestedRevision *ConfigSnapshotRevision `protobuf:"bytes,2,opt,name=requested_revision,json=requestedRevision,proto3" json:"requested_revision,omitempty"` + // Revision active after this attempt. Omitted when the received snapshot + // was not installed or a local override has no gateway revision. + AppliedRevision *ConfigSnapshotRevision `protobuf:"bytes,3,opt,name=applied_revision,json=appliedRevision,proto3" json:"applied_revision,omitempty"` + Outcome ConfigApplyOutcome `protobuf:"varint,4,opt,name=outcome,proto3,enum=openshell.v1.ConfigApplyOutcome" json:"outcome,omitempty"` + Failure *ConfigApplyFailure `protobuf:"bytes,5,opt,name=failure,proto3" json:"failure,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConfigComponentApplyResult) Reset() { + *x = ConfigComponentApplyResult{} + mi := &file_openshell_proto_msgTypes[158] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConfigComponentApplyResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfigComponentApplyResult) ProtoMessage() {} + +func (x *ConfigComponentApplyResult) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[158] + 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 ConfigComponentApplyResult.ProtoReflect.Descriptor instead. +func (*ConfigComponentApplyResult) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{158} +} + +func (x *ConfigComponentApplyResult) GetComponent() ConfigComponent { + if x != nil { + return x.Component + } + return ConfigComponent_CONFIG_COMPONENT_UNSPECIFIED +} + +func (x *ConfigComponentApplyResult) GetRequestedRevision() *ConfigSnapshotRevision { + if x != nil { + return x.RequestedRevision + } + return nil +} + +func (x *ConfigComponentApplyResult) GetAppliedRevision() *ConfigSnapshotRevision { + if x != nil { + return x.AppliedRevision + } + return nil +} + +func (x *ConfigComponentApplyResult) GetOutcome() ConfigApplyOutcome { + if x != nil { + return x.Outcome + } + return ConfigApplyOutcome_CONFIG_APPLY_OUTCOME_UNSPECIFIED +} + +func (x *ConfigComponentApplyResult) GetFailure() *ConfigApplyFailure { + if x != nil { + return x.Failure + } + return nil +} + +// Application result for one ConfigUpdate. +type ConfigUpdateResult struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Echoes ConfigUpdate.update_id for session-local correlation. + UpdateId string `protobuf:"bytes,1,opt,name=update_id,json=updateId,proto3" json:"update_id,omitempty"` + // Echoes ConfigUpdate.component_sequence. + ComponentSequence uint64 `protobuf:"varint,2,opt,name=component_sequence,json=componentSequence,proto3" json:"component_sequence,omitempty"` + Result *ConfigComponentApplyResult `protobuf:"bytes,3,opt,name=result,proto3" json:"result,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConfigUpdateResult) Reset() { + *x = ConfigUpdateResult{} + mi := &file_openshell_proto_msgTypes[159] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConfigUpdateResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfigUpdateResult) ProtoMessage() {} + +func (x *ConfigUpdateResult) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[159] + 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 ConfigUpdateResult.ProtoReflect.Descriptor instead. +func (*ConfigUpdateResult) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{159} +} + +func (x *ConfigUpdateResult) GetUpdateId() string { + if x != nil { + return x.UpdateId + } + return "" +} + +func (x *ConfigUpdateResult) GetComponentSequence() uint64 { + if x != nil { + return x.ComponentSequence + } + return 0 +} + +func (x *ConfigUpdateResult) GetResult() *ConfigComponentApplyResult { + if x != nil { + return x.Result + } + return nil +} + +// Aggregate application result for the SessionAccepted bootstrap. +type ConfigBootstrapResult struct { + state protoimpl.MessageState `protogen:"open.v1"` + Results []*ConfigComponentApplyResult `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConfigBootstrapResult) Reset() { + *x = ConfigBootstrapResult{} + mi := &file_openshell_proto_msgTypes[160] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConfigBootstrapResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfigBootstrapResult) ProtoMessage() {} + +func (x *ConfigBootstrapResult) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[160] + 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 ConfigBootstrapResult.ProtoReflect.Descriptor instead. +func (*ConfigBootstrapResult) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{160} +} + +func (x *ConfigBootstrapResult) GetResults() []*ConfigComponentApplyResult { + if x != nil { + return x.Results + } + return nil +} + +// Gateway rejects the supervisor session. +type SessionRejected struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Human-readable rejection reason. + Reason string `protobuf:"bytes,1,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SessionRejected) Reset() { + *x = SessionRejected{} + mi := &file_openshell_proto_msgTypes[161] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SessionRejected) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SessionRejected) ProtoMessage() {} + +func (x *SessionRejected) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[161] + 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 SessionRejected.ProtoReflect.Descriptor instead. +func (*SessionRejected) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{161} +} + +func (x *SessionRejected) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +// Supervisor heartbeat. +type SupervisorHeartbeat struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SupervisorHeartbeat) Reset() { + *x = SupervisorHeartbeat{} + mi := &file_openshell_proto_msgTypes[162] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SupervisorHeartbeat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SupervisorHeartbeat) ProtoMessage() {} + +func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[162] + 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 SupervisorHeartbeat.ProtoReflect.Descriptor instead. +func (*SupervisorHeartbeat) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{162} +} + +// Gateway heartbeat. +type GatewayHeartbeat struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GatewayHeartbeat) Reset() { + *x = GatewayHeartbeat{} + mi := &file_openshell_proto_msgTypes[163] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GatewayHeartbeat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GatewayHeartbeat) ProtoMessage() {} + +func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[163] + 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 GatewayHeartbeat.ProtoReflect.Descriptor instead. +func (*GatewayHeartbeat) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{163} +} + +// Terminal result reported before the supervisor shuts down. A successful RPC +// response confirms that the result was durably handled by the gateway. +type ReportMainProcessExitRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + InstanceId string `protobuf:"bytes,2,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` + // Normalized process result. Signal exits use 128 + signal number. + ExitCode int32 `protobuf:"varint,3,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReportMainProcessExitRequest) Reset() { + *x = ReportMainProcessExitRequest{} + mi := &file_openshell_proto_msgTypes[164] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReportMainProcessExitRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*ReportMainProcessExitRequest) ProtoMessage() {} func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[164] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10890,7 +11829,7 @@ func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{154} + return file_openshell_proto_rawDescGZIP(), []int{164} } func (x *ReportMainProcessExitRequest) GetSandboxId() string { @@ -10922,7 +11861,7 @@ type ReportMainProcessExitResponse struct { func (x *ReportMainProcessExitResponse) Reset() { *x = ReportMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[165] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10934,7 +11873,7 @@ func (x *ReportMainProcessExitResponse) String() string { func (*ReportMainProcessExitResponse) ProtoMessage() {} func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[165] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10947,7 +11886,7 @@ func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{155} + return file_openshell_proto_rawDescGZIP(), []int{165} } // Terminal-delivery completion reported after all expected foreground SSH @@ -10962,7 +11901,7 @@ type FinalizeMainProcessExitRequest struct { func (x *FinalizeMainProcessExitRequest) Reset() { *x = FinalizeMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[166] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10974,7 +11913,7 @@ func (x *FinalizeMainProcessExitRequest) String() string { func (*FinalizeMainProcessExitRequest) ProtoMessage() {} func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[166] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10987,7 +11926,7 @@ func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{156} + return file_openshell_proto_rawDescGZIP(), []int{166} } func (x *FinalizeMainProcessExitRequest) GetSandboxId() string { @@ -11012,7 +11951,7 @@ type FinalizeMainProcessExitResponse struct { func (x *FinalizeMainProcessExitResponse) Reset() { *x = FinalizeMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[167] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11024,7 +11963,7 @@ func (x *FinalizeMainProcessExitResponse) String() string { func (*FinalizeMainProcessExitResponse) ProtoMessage() {} func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[167] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11037,7 +11976,7 @@ func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{157} + return file_openshell_proto_rawDescGZIP(), []int{167} } // Gateway requests the supervisor to open a relay channel. @@ -11066,7 +12005,7 @@ type RelayOpen struct { func (x *RelayOpen) Reset() { *x = RelayOpen{} - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[168] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11078,7 +12017,7 @@ func (x *RelayOpen) String() string { func (*RelayOpen) ProtoMessage() {} func (x *RelayOpen) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[168] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11091,7 +12030,7 @@ func (x *RelayOpen) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpen.ProtoReflect.Descriptor instead. func (*RelayOpen) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{158} + return file_openshell_proto_rawDescGZIP(), []int{168} } func (x *RelayOpen) GetChannelId() string { @@ -11158,7 +12097,7 @@ type SshRelayTarget struct { func (x *SshRelayTarget) Reset() { *x = SshRelayTarget{} - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[169] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11170,7 +12109,7 @@ func (x *SshRelayTarget) String() string { func (*SshRelayTarget) ProtoMessage() {} func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[169] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11183,7 +12122,7 @@ func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use SshRelayTarget.ProtoReflect.Descriptor instead. func (*SshRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{159} + return file_openshell_proto_rawDescGZIP(), []int{169} } // TCP target dialed by the supervisor from inside the sandbox. @@ -11199,7 +12138,7 @@ type TcpRelayTarget struct { func (x *TcpRelayTarget) Reset() { *x = TcpRelayTarget{} - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[170] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11211,7 +12150,7 @@ func (x *TcpRelayTarget) String() string { func (*TcpRelayTarget) ProtoMessage() {} func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[170] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11224,7 +12163,7 @@ func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpRelayTarget.ProtoReflect.Descriptor instead. func (*TcpRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{160} + return file_openshell_proto_rawDescGZIP(), []int{170} } func (x *TcpRelayTarget) GetHost() string { @@ -11252,7 +12191,7 @@ type RelayInit struct { func (x *RelayInit) Reset() { *x = RelayInit{} - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[171] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11264,7 +12203,7 @@ func (x *RelayInit) String() string { func (*RelayInit) ProtoMessage() {} func (x *RelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[171] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11277,7 +12216,7 @@ func (x *RelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayInit.ProtoReflect.Descriptor instead. func (*RelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{161} + return file_openshell_proto_rawDescGZIP(), []int{171} } func (x *RelayInit) GetChannelId() string { @@ -11304,7 +12243,7 @@ type RelayFrame struct { func (x *RelayFrame) Reset() { *x = RelayFrame{} - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[172] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11316,7 +12255,7 @@ func (x *RelayFrame) String() string { func (*RelayFrame) ProtoMessage() {} func (x *RelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[172] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11329,7 +12268,7 @@ func (x *RelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayFrame.ProtoReflect.Descriptor instead. func (*RelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{162} + return file_openshell_proto_rawDescGZIP(), []int{172} } func (x *RelayFrame) GetPayload() isRelayFrame_Payload { @@ -11388,7 +12327,7 @@ type RelayOpenResult struct { func (x *RelayOpenResult) Reset() { *x = RelayOpenResult{} - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[173] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11400,7 +12339,7 @@ func (x *RelayOpenResult) String() string { func (*RelayOpenResult) ProtoMessage() {} func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[173] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11413,7 +12352,7 @@ func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpenResult.ProtoReflect.Descriptor instead. func (*RelayOpenResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{163} + return file_openshell_proto_rawDescGZIP(), []int{173} } func (x *RelayOpenResult) GetChannelId() string { @@ -11450,7 +12389,7 @@ type RelayClose struct { func (x *RelayClose) Reset() { *x = RelayClose{} - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[174] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11462,7 +12401,7 @@ func (x *RelayClose) String() string { func (*RelayClose) ProtoMessage() {} func (x *RelayClose) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[174] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11475,7 +12414,7 @@ func (x *RelayClose) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayClose.ProtoReflect.Descriptor instead. func (*RelayClose) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{164} + return file_openshell_proto_rawDescGZIP(), []int{174} } func (x *RelayClose) GetChannelId() string { @@ -11509,7 +12448,7 @@ type L7RequestSample struct { func (x *L7RequestSample) Reset() { *x = L7RequestSample{} - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[175] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11521,7 +12460,7 @@ func (x *L7RequestSample) String() string { func (*L7RequestSample) ProtoMessage() {} func (x *L7RequestSample) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[175] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11534,7 +12473,7 @@ func (x *L7RequestSample) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RequestSample.ProtoReflect.Descriptor instead. func (*L7RequestSample) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{165} + return file_openshell_proto_rawDescGZIP(), []int{175} } func (x *L7RequestSample) GetMethod() string { @@ -11608,7 +12547,7 @@ type DenialSummary struct { func (x *DenialSummary) Reset() { *x = DenialSummary{} - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[176] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11620,7 +12559,7 @@ func (x *DenialSummary) String() string { func (*DenialSummary) ProtoMessage() {} func (x *DenialSummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[176] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11633,7 +12572,7 @@ func (x *DenialSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialSummary.ProtoReflect.Descriptor instead. func (*DenialSummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{166} + return file_openshell_proto_rawDescGZIP(), []int{176} } func (x *DenialSummary) GetSandboxId() string { @@ -11768,7 +12707,7 @@ type DenialGroupCount struct { func (x *DenialGroupCount) Reset() { *x = DenialGroupCount{} - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[177] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11780,7 +12719,7 @@ func (x *DenialGroupCount) String() string { func (*DenialGroupCount) ProtoMessage() {} func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[177] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11793,7 +12732,7 @@ func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialGroupCount.ProtoReflect.Descriptor instead. func (*DenialGroupCount) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{167} + return file_openshell_proto_rawDescGZIP(), []int{177} } func (x *DenialGroupCount) GetDenyGroup() string { @@ -11826,7 +12765,7 @@ type NetworkActivitySummary struct { func (x *NetworkActivitySummary) Reset() { *x = NetworkActivitySummary{} - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[178] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11838,7 +12777,7 @@ func (x *NetworkActivitySummary) String() string { func (*NetworkActivitySummary) ProtoMessage() {} func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[178] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11851,7 +12790,7 @@ func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkActivitySummary.ProtoReflect.Descriptor instead. func (*NetworkActivitySummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{168} + return file_openshell_proto_rawDescGZIP(), []int{178} } func (x *NetworkActivitySummary) GetNetworkActivityCount() uint32 { @@ -11939,7 +12878,7 @@ type PolicyChunk struct { func (x *PolicyChunk) Reset() { *x = PolicyChunk{} - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[179] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11951,7 +12890,7 @@ func (x *PolicyChunk) String() string { func (*PolicyChunk) ProtoMessage() {} func (x *PolicyChunk) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[179] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11964,7 +12903,7 @@ func (x *PolicyChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyChunk.ProtoReflect.Descriptor instead. func (*PolicyChunk) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{169} + return file_openshell_proto_rawDescGZIP(), []int{179} } func (x *PolicyChunk) GetId() string { @@ -12152,7 +13091,7 @@ type DraftPolicyUpdate struct { func (x *DraftPolicyUpdate) Reset() { *x = DraftPolicyUpdate{} - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[180] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12164,7 +13103,7 @@ func (x *DraftPolicyUpdate) String() string { func (*DraftPolicyUpdate) ProtoMessage() {} func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[180] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12177,7 +13116,7 @@ func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftPolicyUpdate.ProtoReflect.Descriptor instead. func (*DraftPolicyUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{170} + return file_openshell_proto_rawDescGZIP(), []int{180} } func (x *DraftPolicyUpdate) GetDraftVersion() uint64 { @@ -12235,7 +13174,7 @@ type SubmitPolicyAnalysisRequest struct { func (x *SubmitPolicyAnalysisRequest) Reset() { *x = SubmitPolicyAnalysisRequest{} - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[181] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12247,7 +13186,7 @@ func (x *SubmitPolicyAnalysisRequest) String() string { func (*SubmitPolicyAnalysisRequest) ProtoMessage() {} func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[181] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12260,7 +13199,7 @@ func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisRequest.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{171} + return file_openshell_proto_rawDescGZIP(), []int{181} } func (x *SubmitPolicyAnalysisRequest) GetSummaries() []*DenialSummary { @@ -12323,7 +13262,7 @@ type SubmitPolicyAnalysisResponse struct { func (x *SubmitPolicyAnalysisResponse) Reset() { *x = SubmitPolicyAnalysisResponse{} - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[182] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12335,7 +13274,7 @@ func (x *SubmitPolicyAnalysisResponse) String() string { func (*SubmitPolicyAnalysisResponse) ProtoMessage() {} func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[182] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12348,7 +13287,7 @@ func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisResponse.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{172} + return file_openshell_proto_rawDescGZIP(), []int{182} } func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunks() uint32 { @@ -12394,7 +13333,7 @@ type GetDraftPolicyRequest struct { func (x *GetDraftPolicyRequest) Reset() { *x = GetDraftPolicyRequest{} - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[183] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12406,7 +13345,7 @@ func (x *GetDraftPolicyRequest) String() string { func (*GetDraftPolicyRequest) ProtoMessage() {} func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[183] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12419,7 +13358,7 @@ func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyRequest.ProtoReflect.Descriptor instead. func (*GetDraftPolicyRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{173} + return file_openshell_proto_rawDescGZIP(), []int{183} } func (x *GetDraftPolicyRequest) GetName() string { @@ -12459,7 +13398,7 @@ type GetDraftPolicyResponse struct { func (x *GetDraftPolicyResponse) Reset() { *x = GetDraftPolicyResponse{} - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[184] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12471,7 +13410,7 @@ func (x *GetDraftPolicyResponse) String() string { func (*GetDraftPolicyResponse) ProtoMessage() {} func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[184] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12484,7 +13423,7 @@ func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyResponse.ProtoReflect.Descriptor instead. func (*GetDraftPolicyResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{174} + return file_openshell_proto_rawDescGZIP(), []int{184} } func (x *GetDraftPolicyResponse) GetChunks() []*PolicyChunk { @@ -12533,7 +13472,7 @@ type ApproveDraftChunkRequest struct { func (x *ApproveDraftChunkRequest) Reset() { *x = ApproveDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[185] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12545,7 +13484,7 @@ func (x *ApproveDraftChunkRequest) String() string { func (*ApproveDraftChunkRequest) ProtoMessage() {} func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[185] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12558,7 +13497,7 @@ func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkRequest.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{175} + return file_openshell_proto_rawDescGZIP(), []int{185} } func (x *ApproveDraftChunkRequest) GetName() string { @@ -12601,7 +13540,7 @@ type ApproveDraftChunkResponse struct { func (x *ApproveDraftChunkResponse) Reset() { *x = ApproveDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[186] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12613,7 +13552,7 @@ func (x *ApproveDraftChunkResponse) String() string { func (*ApproveDraftChunkResponse) ProtoMessage() {} func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[186] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12626,7 +13565,7 @@ func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkResponse.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{176} + return file_openshell_proto_rawDescGZIP(), []int{186} } func (x *ApproveDraftChunkResponse) GetPolicyVersion() uint32 { @@ -12660,7 +13599,7 @@ type RejectDraftChunkRequest struct { func (x *RejectDraftChunkRequest) Reset() { *x = RejectDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[187] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12672,7 +13611,7 @@ func (x *RejectDraftChunkRequest) String() string { func (*RejectDraftChunkRequest) ProtoMessage() {} func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[187] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12685,7 +13624,7 @@ func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkRequest.ProtoReflect.Descriptor instead. func (*RejectDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{177} + return file_openshell_proto_rawDescGZIP(), []int{187} } func (x *RejectDraftChunkRequest) GetName() string { @@ -12724,7 +13663,7 @@ type RejectDraftChunkResponse struct { func (x *RejectDraftChunkResponse) Reset() { *x = RejectDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[188] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12736,7 +13675,7 @@ func (x *RejectDraftChunkResponse) String() string { func (*RejectDraftChunkResponse) ProtoMessage() {} func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[188] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12749,7 +13688,7 @@ func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkResponse.ProtoReflect.Descriptor instead. func (*RejectDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{178} + return file_openshell_proto_rawDescGZIP(), []int{188} } // Approve all pending chunks. @@ -12763,7 +13702,7 @@ type DraftChunkApproval struct { func (x *DraftChunkApproval) Reset() { *x = DraftChunkApproval{} - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[189] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12775,7 +13714,7 @@ func (x *DraftChunkApproval) String() string { func (*DraftChunkApproval) ProtoMessage() {} func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[189] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12788,7 +13727,7 @@ func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftChunkApproval.ProtoReflect.Descriptor instead. func (*DraftChunkApproval) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{179} + return file_openshell_proto_rawDescGZIP(), []int{189} } func (x *DraftChunkApproval) GetChunkId() string { @@ -12822,7 +13761,7 @@ type ApproveAllDraftChunksRequest struct { func (x *ApproveAllDraftChunksRequest) Reset() { *x = ApproveAllDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[190] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12834,7 +13773,7 @@ func (x *ApproveAllDraftChunksRequest) String() string { func (*ApproveAllDraftChunksRequest) ProtoMessage() {} func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[190] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12847,7 +13786,7 @@ func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{180} + return file_openshell_proto_rawDescGZIP(), []int{190} } func (x *ApproveAllDraftChunksRequest) GetName() string { @@ -12895,7 +13834,7 @@ type ApproveAllDraftChunksResponse struct { func (x *ApproveAllDraftChunksResponse) Reset() { *x = ApproveAllDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[191] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12907,7 +13846,7 @@ func (x *ApproveAllDraftChunksResponse) String() string { func (*ApproveAllDraftChunksResponse) ProtoMessage() {} func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[191] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12920,7 +13859,7 @@ func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{181} + return file_openshell_proto_rawDescGZIP(), []int{191} } func (x *ApproveAllDraftChunksResponse) GetPolicyVersion() uint32 { @@ -12968,7 +13907,7 @@ type EditDraftChunkRequest struct { func (x *EditDraftChunkRequest) Reset() { *x = EditDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[192] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12980,7 +13919,7 @@ func (x *EditDraftChunkRequest) String() string { func (*EditDraftChunkRequest) ProtoMessage() {} func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[192] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12993,7 +13932,7 @@ func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkRequest.ProtoReflect.Descriptor instead. func (*EditDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{182} + return file_openshell_proto_rawDescGZIP(), []int{192} } func (x *EditDraftChunkRequest) GetName() string { @@ -13032,7 +13971,7 @@ type EditDraftChunkResponse struct { func (x *EditDraftChunkResponse) Reset() { *x = EditDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13044,7 +13983,7 @@ func (x *EditDraftChunkResponse) String() string { func (*EditDraftChunkResponse) ProtoMessage() {} func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[193] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13057,7 +13996,7 @@ func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkResponse.ProtoReflect.Descriptor instead. func (*EditDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{183} + return file_openshell_proto_rawDescGZIP(), []int{193} } // Reverse an approval (remove merged rule from active policy). @@ -13075,7 +14014,7 @@ type UndoDraftChunkRequest struct { func (x *UndoDraftChunkRequest) Reset() { *x = UndoDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13087,7 +14026,7 @@ func (x *UndoDraftChunkRequest) String() string { func (*UndoDraftChunkRequest) ProtoMessage() {} func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[194] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13100,7 +14039,7 @@ func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkRequest.ProtoReflect.Descriptor instead. func (*UndoDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{184} + return file_openshell_proto_rawDescGZIP(), []int{194} } func (x *UndoDraftChunkRequest) GetName() string { @@ -13136,7 +14075,7 @@ type UndoDraftChunkResponse struct { func (x *UndoDraftChunkResponse) Reset() { *x = UndoDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13148,7 +14087,7 @@ func (x *UndoDraftChunkResponse) String() string { func (*UndoDraftChunkResponse) ProtoMessage() {} func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[195] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13161,7 +14100,7 @@ func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkResponse.ProtoReflect.Descriptor instead. func (*UndoDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{185} + return file_openshell_proto_rawDescGZIP(), []int{195} } func (x *UndoDraftChunkResponse) GetPolicyVersion() uint32 { @@ -13191,7 +14130,7 @@ type ClearDraftChunksRequest struct { func (x *ClearDraftChunksRequest) Reset() { *x = ClearDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13203,7 +14142,7 @@ func (x *ClearDraftChunksRequest) String() string { func (*ClearDraftChunksRequest) ProtoMessage() {} func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[196] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13216,7 +14155,7 @@ func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ClearDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{186} + return file_openshell_proto_rawDescGZIP(), []int{196} } func (x *ClearDraftChunksRequest) GetName() string { @@ -13243,7 +14182,7 @@ type ClearDraftChunksResponse struct { func (x *ClearDraftChunksResponse) Reset() { *x = ClearDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13255,7 +14194,7 @@ func (x *ClearDraftChunksResponse) String() string { func (*ClearDraftChunksResponse) ProtoMessage() {} func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[197] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13268,7 +14207,7 @@ func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ClearDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{187} + return file_openshell_proto_rawDescGZIP(), []int{197} } func (x *ClearDraftChunksResponse) GetChunksCleared() uint32 { @@ -13291,7 +14230,7 @@ type GetDraftHistoryRequest struct { func (x *GetDraftHistoryRequest) Reset() { *x = GetDraftHistoryRequest{} - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13303,7 +14242,7 @@ func (x *GetDraftHistoryRequest) String() string { func (*GetDraftHistoryRequest) ProtoMessage() {} func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[198] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13316,7 +14255,7 @@ func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryRequest.ProtoReflect.Descriptor instead. func (*GetDraftHistoryRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{188} + return file_openshell_proto_rawDescGZIP(), []int{198} } func (x *GetDraftHistoryRequest) GetName() string { @@ -13350,7 +14289,7 @@ type DraftHistoryEntry struct { func (x *DraftHistoryEntry) Reset() { *x = DraftHistoryEntry{} - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13362,7 +14301,7 @@ func (x *DraftHistoryEntry) String() string { func (*DraftHistoryEntry) ProtoMessage() {} func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[199] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13375,7 +14314,7 @@ func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftHistoryEntry.ProtoReflect.Descriptor instead. func (*DraftHistoryEntry) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{189} + return file_openshell_proto_rawDescGZIP(), []int{199} } func (x *DraftHistoryEntry) GetTimestampMs() int64 { @@ -13416,7 +14355,7 @@ type GetDraftHistoryResponse struct { func (x *GetDraftHistoryResponse) Reset() { *x = GetDraftHistoryResponse{} - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[200] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13428,7 +14367,7 @@ func (x *GetDraftHistoryResponse) String() string { func (*GetDraftHistoryResponse) ProtoMessage() {} func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[200] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13441,7 +14380,7 @@ func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryResponse.ProtoReflect.Descriptor instead. func (*GetDraftHistoryResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{190} + return file_openshell_proto_rawDescGZIP(), []int{200} } func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry { @@ -13464,7 +14403,7 @@ type CreateWorkspaceRequest struct { func (x *CreateWorkspaceRequest) Reset() { *x = CreateWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[201] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13476,7 +14415,7 @@ func (x *CreateWorkspaceRequest) String() string { func (*CreateWorkspaceRequest) ProtoMessage() {} func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[201] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13489,7 +14428,7 @@ func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceRequest.ProtoReflect.Descriptor instead. func (*CreateWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{191} + return file_openshell_proto_rawDescGZIP(), []int{201} } func (x *CreateWorkspaceRequest) GetName() string { @@ -13516,7 +14455,7 @@ type CreateWorkspaceResponse struct { func (x *CreateWorkspaceResponse) Reset() { *x = CreateWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[202] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13528,7 +14467,7 @@ func (x *CreateWorkspaceResponse) String() string { func (*CreateWorkspaceResponse) ProtoMessage() {} func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[202] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13541,7 +14480,7 @@ func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceResponse.ProtoReflect.Descriptor instead. func (*CreateWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{192} + return file_openshell_proto_rawDescGZIP(), []int{202} } func (x *CreateWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -13562,7 +14501,7 @@ type GetWorkspaceRequest struct { func (x *GetWorkspaceRequest) Reset() { *x = GetWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[203] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13574,7 +14513,7 @@ func (x *GetWorkspaceRequest) String() string { func (*GetWorkspaceRequest) ProtoMessage() {} func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[203] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13587,7 +14526,7 @@ func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceRequest.ProtoReflect.Descriptor instead. func (*GetWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{193} + return file_openshell_proto_rawDescGZIP(), []int{203} } func (x *GetWorkspaceRequest) GetName() string { @@ -13607,7 +14546,7 @@ type GetWorkspaceResponse struct { func (x *GetWorkspaceResponse) Reset() { *x = GetWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[204] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13619,7 +14558,7 @@ func (x *GetWorkspaceResponse) String() string { func (*GetWorkspaceResponse) ProtoMessage() {} func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[204] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13632,7 +14571,7 @@ func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceResponse.ProtoReflect.Descriptor instead. func (*GetWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{194} + return file_openshell_proto_rawDescGZIP(), []int{204} } func (x *GetWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -13659,7 +14598,7 @@ type ListWorkspacesRequest struct { func (x *ListWorkspacesRequest) Reset() { *x = ListWorkspacesRequest{} - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[205] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13671,7 +14610,7 @@ func (x *ListWorkspacesRequest) String() string { func (*ListWorkspacesRequest) ProtoMessage() {} func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[205] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13684,7 +14623,7 @@ func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesRequest.ProtoReflect.Descriptor instead. func (*ListWorkspacesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{195} + return file_openshell_proto_rawDescGZIP(), []int{205} } func (x *ListWorkspacesRequest) GetPageSize() int32 { @@ -13720,7 +14659,7 @@ type ListWorkspacesResponse struct { func (x *ListWorkspacesResponse) Reset() { *x = ListWorkspacesResponse{} - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[206] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13732,7 +14671,7 @@ func (x *ListWorkspacesResponse) String() string { func (*ListWorkspacesResponse) ProtoMessage() {} func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[206] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13745,7 +14684,7 @@ func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesResponse.ProtoReflect.Descriptor instead. func (*ListWorkspacesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{196} + return file_openshell_proto_rawDescGZIP(), []int{206} } func (x *ListWorkspacesResponse) GetWorkspaces() []*datamodelv1.Workspace { @@ -13773,7 +14712,7 @@ type DeleteWorkspaceRequest struct { func (x *DeleteWorkspaceRequest) Reset() { *x = DeleteWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[207] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13785,7 +14724,7 @@ func (x *DeleteWorkspaceRequest) String() string { func (*DeleteWorkspaceRequest) ProtoMessage() {} func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[207] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13798,7 +14737,7 @@ func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{197} + return file_openshell_proto_rawDescGZIP(), []int{207} } func (x *DeleteWorkspaceRequest) GetName() string { @@ -13818,7 +14757,7 @@ type DeleteWorkspaceResponse struct { func (x *DeleteWorkspaceResponse) Reset() { *x = DeleteWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[208] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13830,7 +14769,7 @@ func (x *DeleteWorkspaceResponse) String() string { func (*DeleteWorkspaceResponse) ProtoMessage() {} func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[208] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13843,7 +14782,7 @@ func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceResponse.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{198} + return file_openshell_proto_rawDescGZIP(), []int{208} } func (x *DeleteWorkspaceResponse) GetDeleted() bool { @@ -13867,7 +14806,7 @@ type WorkspaceMember struct { func (x *WorkspaceMember) Reset() { *x = WorkspaceMember{} - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[209] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13879,7 +14818,7 @@ func (x *WorkspaceMember) String() string { func (*WorkspaceMember) ProtoMessage() {} func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[209] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13892,7 +14831,7 @@ func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkspaceMember.ProtoReflect.Descriptor instead. func (*WorkspaceMember) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{199} + return file_openshell_proto_rawDescGZIP(), []int{209} } func (x *WorkspaceMember) GetMetadata() *datamodelv1.ObjectMeta { @@ -13931,7 +14870,7 @@ type AddWorkspaceMemberRequest struct { func (x *AddWorkspaceMemberRequest) Reset() { *x = AddWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[210] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13943,7 +14882,7 @@ func (x *AddWorkspaceMemberRequest) String() string { func (*AddWorkspaceMemberRequest) ProtoMessage() {} func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[210] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13956,7 +14895,7 @@ func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{200} + return file_openshell_proto_rawDescGZIP(), []int{210} } func (x *AddWorkspaceMemberRequest) GetWorkspace() string { @@ -13990,7 +14929,7 @@ type AddWorkspaceMemberResponse struct { func (x *AddWorkspaceMemberResponse) Reset() { *x = AddWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[211] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14002,7 +14941,7 @@ func (x *AddWorkspaceMemberResponse) String() string { func (*AddWorkspaceMemberResponse) ProtoMessage() {} func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[211] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14015,7 +14954,7 @@ func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{201} + return file_openshell_proto_rawDescGZIP(), []int{211} } func (x *AddWorkspaceMemberResponse) GetMember() *WorkspaceMember { @@ -14038,7 +14977,7 @@ type RemoveWorkspaceMemberRequest struct { func (x *RemoveWorkspaceMemberRequest) Reset() { *x = RemoveWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[212] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14050,7 +14989,7 @@ func (x *RemoveWorkspaceMemberRequest) String() string { func (*RemoveWorkspaceMemberRequest) ProtoMessage() {} func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[212] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14063,7 +15002,7 @@ func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{202} + return file_openshell_proto_rawDescGZIP(), []int{212} } func (x *RemoveWorkspaceMemberRequest) GetWorkspace() string { @@ -14090,7 +15029,7 @@ type RemoveWorkspaceMemberResponse struct { func (x *RemoveWorkspaceMemberResponse) Reset() { *x = RemoveWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[213] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14102,7 +15041,7 @@ func (x *RemoveWorkspaceMemberResponse) String() string { func (*RemoveWorkspaceMemberResponse) ProtoMessage() {} func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[213] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14115,7 +15054,7 @@ func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{203} + return file_openshell_proto_rawDescGZIP(), []int{213} } func (x *RemoveWorkspaceMemberResponse) GetRemoved() bool { @@ -14142,7 +15081,7 @@ type ListWorkspaceMembersRequest struct { func (x *ListWorkspaceMembersRequest) Reset() { *x = ListWorkspaceMembersRequest{} - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[214] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14154,7 +15093,7 @@ func (x *ListWorkspaceMembersRequest) String() string { func (*ListWorkspaceMembersRequest) ProtoMessage() {} func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[214] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14167,7 +15106,7 @@ func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersRequest.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{204} + return file_openshell_proto_rawDescGZIP(), []int{214} } func (x *ListWorkspaceMembersRequest) GetWorkspace() string { @@ -14203,7 +15142,7 @@ type ListWorkspaceMembersResponse struct { func (x *ListWorkspaceMembersResponse) Reset() { *x = ListWorkspaceMembersResponse{} - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[215] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14215,7 +15154,7 @@ func (x *ListWorkspaceMembersResponse) String() string { func (*ListWorkspaceMembersResponse) ProtoMessage() {} func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[215] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14228,7 +15167,7 @@ func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersResponse.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{205} + return file_openshell_proto_rawDescGZIP(), []int{215} } func (x *ListWorkspaceMembersResponse) GetMembers() []*WorkspaceMember { @@ -14263,7 +15202,7 @@ type ExtensionServiceCredential struct { func (x *ExtensionServiceCredential) Reset() { *x = ExtensionServiceCredential{} - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[216] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14275,7 +15214,7 @@ func (x *ExtensionServiceCredential) String() string { func (*ExtensionServiceCredential) ProtoMessage() {} func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[216] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14288,7 +15227,7 @@ func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionServiceCredential.ProtoReflect.Descriptor instead. func (*ExtensionServiceCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{206} + return file_openshell_proto_rawDescGZIP(), []int{216} } func (x *ExtensionServiceCredential) GetServiceName() string { @@ -14941,7 +15880,21 @@ const file_openshell_proto_rawDesc = "" + "\x05value\x18\x02 \x01(\v2'.openshell.v1.ProviderProfileCredentialR\x05value:\x028\x01\x1ar\n" + "\x1dStaticCredentialBindingsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12;\n" + - "\x05value\x18\x02 \x01(\v2%.openshell.v1.StaticCredentialBindingR\x05value:\x028\x01\"\xbd\x01\n" + + "\x05value\x18\x02 \x01(\v2%.openshell.v1.StaticCredentialBindingR\x05value:\x028\x01\"\xc6\x02\n" + + "\x18ProviderEnvironmentValue\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1a\n" + + "\x05value\x18\x02 \x01(\tB\x04\x88\xb5\x18\x01R\x05value\x12'\n" + + "\rexpires_at_ms\x18\x03 \x01(\x03H\x00R\vexpiresAtMs\x88\x01\x01\x12\\\n" + + "\x0eclassification\x18\x04 \x01(\x0e24.openshell.v1.ProviderEnvironmentValueClassificationR\x0eclassification\x12a\n" + + "\x19static_credential_binding\x18\x05 \x01(\v2%.openshell.v1.StaticCredentialBindingR\x17staticCredentialBindingB\x10\n" + + "\x0e_expires_at_ms\"\xf5\x02\n" + + "\x1bProviderEnvironmentSnapshot\x122\n" + + "\x15provider_env_revision\x18\x01 \x01(\x04R\x13providerEnvRevision\x12>\n" + + "\x06values\x18\x02 \x03(\v2&.openshell.v1.ProviderEnvironmentValueR\x06values\x12r\n" + + "\x13dynamic_credentials\x18\x03 \x03(\v2A.openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntryR\x12dynamicCredentials\x1an\n" + + "\x17DynamicCredentialsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12=\n" + + "\x05value\x18\x02 \x01(\v2'.openshell.v1.ProviderProfileCredentialR\x05value:\x028\x01\"\xbd\x01\n" + "#ExchangeProviderSubjectTokenRequest\x12\x1d\n" + "\n" + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x1a\n" + @@ -15069,14 +16022,16 @@ const file_openshell_proto_rawDesc = "" + "\x17PushSandboxLogsResponse\"m\n" + "\x16GetSandboxLogsResponse\x120\n" + "\x04logs\x18\x01 \x03(\v2\x1c.openshell.v1.SandboxLogLineR\x04logs\x12!\n" + - "\fbuffer_total\x18\x02 \x01(\rR\vbufferTotal\"\xa2\x02\n" + + "\fbuffer_total\x18\x02 \x01(\rR\vbufferTotal\"\xd7\x03\n" + "\x11SupervisorMessage\x125\n" + "\x05hello\x18\x01 \x01(\v2\x1d.openshell.v1.SupervisorHelloH\x00R\x05hello\x12A\n" + "\theartbeat\x18\x02 \x01(\v2!.openshell.v1.SupervisorHeartbeatH\x00R\theartbeat\x12K\n" + "\x11relay_open_result\x18\x03 \x01(\v2\x1d.openshell.v1.RelayOpenResultH\x00R\x0frelayOpenResult\x12;\n" + "\vrelay_close\x18\x04 \x01(\v2\x18.openshell.v1.RelayCloseH\x00R\n" + - "relayCloseB\t\n" + - "\apayload\"\xea\x02\n" + + "relayClose\x12T\n" + + "\x14config_update_result\x18\x05 \x01(\v2 .openshell.v1.ConfigUpdateResultH\x00R\x12configUpdateResult\x12]\n" + + "\x17config_bootstrap_result\x18\x06 \x01(\v2#.openshell.v1.ConfigBootstrapResultH\x00R\x15configBootstrapResultB\t\n" + + "\apayload\"\xad\x03\n" + "\x0eGatewayMessage\x12J\n" + "\x10session_accepted\x18\x01 \x01(\v2\x1d.openshell.v1.SessionAcceptedH\x00R\x0fsessionAccepted\x12J\n" + "\x10session_rejected\x18\x02 \x01(\v2\x1d.openshell.v1.SessionRejectedH\x00R\x0fsessionRejected\x12>\n" + @@ -15084,17 +16039,55 @@ const file_openshell_proto_rawDesc = "" + "\n" + "relay_open\x18\x04 \x01(\v2\x17.openshell.v1.RelayOpenH\x00R\trelayOpen\x12;\n" + "\vrelay_close\x18\x05 \x01(\v2\x18.openshell.v1.RelayCloseH\x00R\n" + - "relayCloseB\t\n" + - "\apayload\"Q\n" + + "relayClose\x12A\n" + + "\rconfig_update\x18\x06 \x01(\v2\x1a.openshell.v1.ConfigUpdateH\x00R\fconfigUpdateB\t\n" + + "\apayload\"~\n" + "\x0fSupervisorHello\x12\x1d\n" + "\n" + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x1f\n" + "\vinstance_id\x18\x02 \x01(\tR\n" + - "instanceId\"h\n" + + "instanceId\x12+\n" + + "\x11protocol_revision\x18\x03 \x01(\rR\x10protocolRevision\"\xd2\x01\n" + "\x0fSessionAccepted\x12\x1d\n" + "\n" + "session_id\x18\x01 \x01(\tR\tsessionId\x126\n" + - "\x17heartbeat_interval_secs\x18\x02 \x01(\rR\x15heartbeatIntervalSecs\")\n" + + "\x17heartbeat_interval_secs\x18\x02 \x01(\rR\x15heartbeatIntervalSecs\x12;\n" + + "\tbootstrap\x18\x03 \x01(\v2\x1d.openshell.v1.ConfigBootstrapR\tbootstrap\x12+\n" + + "\x11protocol_revision\x18\x04 \x01(\rR\x10protocolRevision\"\xc3\x01\n" + + "\x0fConfigBootstrap\x12R\n" + + "\x0esandbox_config\x18\x01 \x01(\v2+.openshell.sandbox.v1.SandboxConfigSnapshotR\rsandboxConfig\x12\\\n" + + "\x14provider_environment\x18\x02 \x01(\v2).openshell.v1.ProviderEnvironmentSnapshotR\x13providerEnvironment\"\x9d\x02\n" + + "\fConfigUpdate\x12\x1b\n" + + "\tupdate_id\x18\x01 \x01(\tR\bupdateId\x12-\n" + + "\x12component_sequence\x18\x02 \x01(\x04R\x11componentSequence\x12T\n" + + "\x0esandbox_config\x18\x03 \x01(\v2+.openshell.sandbox.v1.SandboxConfigSnapshotH\x00R\rsandboxConfig\x12^\n" + + "\x14provider_environment\x18\x04 \x01(\v2).openshell.v1.ProviderEnvironmentSnapshotH\x00R\x13providerEnvironmentB\v\n" + + "\tcomponent\"\xa8\x01\n" + + "\x16ConfigSnapshotRevision\x12L\n" + + "\x0esandbox_config\x18\x01 \x01(\v2#.openshell.v1.SandboxConfigRevisionH\x00R\rsandboxConfig\x123\n" + + "\x14provider_environment\x18\x02 \x01(\x04H\x00R\x13providerEnvironmentB\v\n" + + "\tcomponent\"\xe4\x01\n" + + "\x15SandboxConfigRevision\x12'\n" + + "\x0fconfig_revision\x18\x01 \x01(\x04R\x0econfigRevision\x12%\n" + + "\x0epolicy_version\x18\x02 \x01(\rR\rpolicyVersion\x12G\n" + + "\rpolicy_source\x18\x03 \x01(\x0e2\".openshell.sandbox.v1.PolicySourceR\fpolicySource\x122\n" + + "\x15global_policy_version\x18\x04 \x01(\rR\x13globalPolicyVersion\"`\n" + + "\x12ConfigApplyFailure\x12\x12\n" + + "\x04code\x18\x01 \x01(\tR\x04code\x12\x18\n" + + "\amessage\x18\x02 \x01(\tR\amessage\x12\x1c\n" + + "\tretryable\x18\x03 \x01(\bR\tretryable\"\xf7\x02\n" + + "\x1aConfigComponentApplyResult\x12;\n" + + "\tcomponent\x18\x01 \x01(\x0e2\x1d.openshell.v1.ConfigComponentR\tcomponent\x12S\n" + + "\x12requested_revision\x18\x02 \x01(\v2$.openshell.v1.ConfigSnapshotRevisionR\x11requestedRevision\x12O\n" + + "\x10applied_revision\x18\x03 \x01(\v2$.openshell.v1.ConfigSnapshotRevisionR\x0fappliedRevision\x12:\n" + + "\aoutcome\x18\x04 \x01(\x0e2 .openshell.v1.ConfigApplyOutcomeR\aoutcome\x12:\n" + + "\afailure\x18\x05 \x01(\v2 .openshell.v1.ConfigApplyFailureR\afailure\"\xa2\x01\n" + + "\x12ConfigUpdateResult\x12\x1b\n" + + "\tupdate_id\x18\x01 \x01(\tR\bupdateId\x12-\n" + + "\x12component_sequence\x18\x02 \x01(\x04R\x11componentSequence\x12@\n" + + "\x06result\x18\x03 \x01(\v2(.openshell.v1.ConfigComponentApplyResultR\x06result\"[\n" + + "\x15ConfigBootstrapResult\x12B\n" + + "\aresults\x18\x01 \x03(\v2(.openshell.v1.ConfigComponentApplyResultR\aresults\")\n" + "\x0fSessionRejected\x12\x16\n" + "\x06reason\x18\x01 \x01(\tR\x06reason\"\x15\n" + "\x13SupervisorHeartbeat\"\x12\n" + @@ -15379,13 +16372,31 @@ const file_openshell_proto_rawDesc = "" + "(PROVIDER_PROFILE_CATEGORY_SOURCE_CONTROL\x10\x04\x12'\n" + "#PROVIDER_PROFILE_CATEGORY_MESSAGING\x10\x05\x12\"\n" + "\x1ePROVIDER_PROFILE_CATEGORY_DATA\x10\x06\x12'\n" + - "#PROVIDER_PROFILE_CATEGORY_KNOWLEDGE\x10\a*\x9a\x01\n" + + "#PROVIDER_PROFILE_CATEGORY_KNOWLEDGE\x10\a*\xde\x01\n" + + "&ProviderEnvironmentValueClassification\x129\n" + + "5PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_UNSPECIFIED\x10\x00\x128\n" + + "4PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_NON_SECRET\x10\x01\x12?\n" + + ";PROVIDER_ENVIRONMENT_VALUE_CLASSIFICATION_STATIC_CREDENTIAL\x10\x02*\x9a\x01\n" + "\fPolicyStatus\x12\x1d\n" + "\x19POLICY_STATUS_UNSPECIFIED\x10\x00\x12\x19\n" + "\x15POLICY_STATUS_PENDING\x10\x01\x12\x18\n" + "\x14POLICY_STATUS_LOADED\x10\x02\x12\x18\n" + "\x14POLICY_STATUS_FAILED\x10\x03\x12\x1c\n" + - "\x18POLICY_STATUS_SUPERSEDED\x10\x04*\x86\x01\n" + + "\x18POLICY_STATUS_SUPERSEDED\x10\x04*\x83\x01\n" + + "\x0fConfigComponent\x12 \n" + + "\x1cCONFIG_COMPONENT_UNSPECIFIED\x10\x00\x12#\n" + + "\x1fCONFIG_COMPONENT_SANDBOX_CONFIG\x10\x01\x12)\n" + + "%CONFIG_COMPONENT_PROVIDER_ENVIRONMENT\x10\x02*\x8d\x03\n" + + "\x12ConfigApplyOutcome\x12$\n" + + " CONFIG_APPLY_OUTCOME_UNSPECIFIED\x10\x00\x12 \n" + + "\x1cCONFIG_APPLY_OUTCOME_APPLIED\x10\x01\x12*\n" + + "&CONFIG_APPLY_OUTCOME_IGNORED_DUPLICATE\x10\x02\x12&\n" + + "\"CONFIG_APPLY_OUTCOME_IGNORED_STALE\x10\x03\x120\n" + + ",CONFIG_APPLY_OUTCOME_RETAINED_LOCAL_OVERRIDE\x10\x04\x12!\n" + + "\x1dCONFIG_APPLY_OUTCOME_DEGRADED\x10\x05\x128\n" + + "4CONFIG_APPLY_OUTCOME_FAILED_RETAINED_LAST_KNOWN_GOOD\x10\x06\x12&\n" + + "\"CONFIG_APPLY_OUTCOME_FAILED_CLOSED\x10\a\x12$\n" + + " CONFIG_APPLY_OUTCOME_UNSUPPORTED\x10\b*\x86\x01\n" + "\rServiceStatus\x12\x1e\n" + "\x1aSERVICE_STATUS_UNSPECIFIED\x10\x00\x12\x1a\n" + "\x16SERVICE_STATUS_HEALTHY\x10\x01\x12\x1b\n" + @@ -15566,621 +16577,659 @@ func file_openshell_proto_rawDescGZIP() []byte { return file_openshell_proto_rawDescData } -var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 8) -var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 228) +var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 11) +var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 239) var file_openshell_proto_goTypes = []any{ (SandboxPhase)(0), // 0: openshell.v1.SandboxPhase (ProviderCredentialTokenGrantType)(0), // 1: openshell.v1.ProviderCredentialTokenGrantType (ProviderCredentialRefreshStrategy)(0), // 2: openshell.v1.ProviderCredentialRefreshStrategy (ProviderProfileCategory)(0), // 3: openshell.v1.ProviderProfileCategory - (PolicyStatus)(0), // 4: openshell.v1.PolicyStatus - (ServiceStatus)(0), // 5: openshell.v1.ServiceStatus - (WorkspaceRole)(0), // 6: openshell.v1.WorkspaceRole - (ProviderCredentialRefreshRecoveryAction)(0), // 7: openshell.v1.ProviderCredentialRefreshRecoveryAction - (*IssueSandboxTokenRequest)(nil), // 8: openshell.v1.IssueSandboxTokenRequest - (*IssueSandboxTokenResponse)(nil), // 9: openshell.v1.IssueSandboxTokenResponse - (*RefreshSandboxTokenRequest)(nil), // 10: openshell.v1.RefreshSandboxTokenRequest - (*RefreshSandboxTokenResponse)(nil), // 11: openshell.v1.RefreshSandboxTokenResponse - (*HealthRequest)(nil), // 12: openshell.v1.HealthRequest - (*HealthResponse)(nil), // 13: openshell.v1.HealthResponse - (*GetCurrentUserRequest)(nil), // 14: openshell.v1.GetCurrentUserRequest - (*GetCurrentUserResponse)(nil), // 15: openshell.v1.GetCurrentUserResponse - (*GetGatewayInfoRequest)(nil), // 16: openshell.v1.GetGatewayInfoRequest - (*GetGatewayInfoResponse)(nil), // 17: openshell.v1.GetGatewayInfoResponse - (*ComputeDriverInfo)(nil), // 18: openshell.v1.ComputeDriverInfo - (*ComputeDriverCapabilities)(nil), // 19: openshell.v1.ComputeDriverCapabilities - (*ResourceCapabilities)(nil), // 20: openshell.v1.ResourceCapabilities - (*CpuResourceCapabilities)(nil), // 21: openshell.v1.CpuResourceCapabilities - (*MemoryResourceCapabilities)(nil), // 22: openshell.v1.MemoryResourceCapabilities - (*GpuResourceCapabilities)(nil), // 23: openshell.v1.GpuResourceCapabilities - (*Sandbox)(nil), // 24: openshell.v1.Sandbox - (*SandboxSpec)(nil), // 25: openshell.v1.SandboxSpec - (*ResourceRequirements)(nil), // 26: openshell.v1.ResourceRequirements - (*GpuResourceRequirements)(nil), // 27: openshell.v1.GpuResourceRequirements - (*SandboxTemplate)(nil), // 28: openshell.v1.SandboxTemplate - (*SandboxWorkloadTemplate)(nil), // 29: openshell.v1.SandboxWorkloadTemplate - (*SandboxWorkloadTemplateSpec)(nil), // 30: openshell.v1.SandboxWorkloadTemplateSpec - (*SandboxWorkloadConfig)(nil), // 31: openshell.v1.SandboxWorkloadConfig - (*SandboxResources)(nil), // 32: openshell.v1.SandboxResources - (*SandboxServiceLevel)(nil), // 33: openshell.v1.SandboxServiceLevel - (*SandboxStartup)(nil), // 34: openshell.v1.SandboxStartup - (*SandboxWorkloadTemplateProvenance)(nil), // 35: openshell.v1.SandboxWorkloadTemplateProvenance - (*SandboxStatus)(nil), // 36: openshell.v1.SandboxStatus - (*SandboxCondition)(nil), // 37: openshell.v1.SandboxCondition - (*PlatformEvent)(nil), // 38: openshell.v1.PlatformEvent - (*CreateSandboxRequest)(nil), // 39: openshell.v1.CreateSandboxRequest - (*CreateSandboxTemplateRequest)(nil), // 40: openshell.v1.CreateSandboxTemplateRequest - (*GetSandboxTemplateRequest)(nil), // 41: openshell.v1.GetSandboxTemplateRequest - (*ListSandboxTemplatesRequest)(nil), // 42: openshell.v1.ListSandboxTemplatesRequest - (*DeleteSandboxTemplateRequest)(nil), // 43: openshell.v1.DeleteSandboxTemplateRequest - (*SandboxTemplateResponse)(nil), // 44: openshell.v1.SandboxTemplateResponse - (*ListSandboxTemplatesResponse)(nil), // 45: openshell.v1.ListSandboxTemplatesResponse - (*DeleteSandboxTemplateResponse)(nil), // 46: openshell.v1.DeleteSandboxTemplateResponse - (*BeginRootfsTarStagingRequest)(nil), // 47: openshell.v1.BeginRootfsTarStagingRequest - (*BeginRootfsTarStagingResponse)(nil), // 48: openshell.v1.BeginRootfsTarStagingResponse - (*GetSandboxRequest)(nil), // 49: openshell.v1.GetSandboxRequest - (*ListSandboxesRequest)(nil), // 50: openshell.v1.ListSandboxesRequest - (*ListSandboxProvidersRequest)(nil), // 51: openshell.v1.ListSandboxProvidersRequest - (*AttachSandboxProviderRequest)(nil), // 52: openshell.v1.AttachSandboxProviderRequest - (*DetachSandboxProviderRequest)(nil), // 53: openshell.v1.DetachSandboxProviderRequest - (*DeleteSandboxRequest)(nil), // 54: openshell.v1.DeleteSandboxRequest - (*StopSandboxRequest)(nil), // 55: openshell.v1.StopSandboxRequest - (*StartSandboxRequest)(nil), // 56: openshell.v1.StartSandboxRequest - (*SandboxResponse)(nil), // 57: openshell.v1.SandboxResponse - (*ListSandboxesResponse)(nil), // 58: openshell.v1.ListSandboxesResponse - (*ListSandboxProvidersResponse)(nil), // 59: openshell.v1.ListSandboxProvidersResponse - (*AttachSandboxProviderResponse)(nil), // 60: openshell.v1.AttachSandboxProviderResponse - (*DetachSandboxProviderResponse)(nil), // 61: openshell.v1.DetachSandboxProviderResponse - (*DeleteSandboxResponse)(nil), // 62: openshell.v1.DeleteSandboxResponse - (*CreateSshSessionRequest)(nil), // 63: openshell.v1.CreateSshSessionRequest - (*CreateSshSessionResponse)(nil), // 64: openshell.v1.CreateSshSessionResponse - (*ExposeServiceRequest)(nil), // 65: openshell.v1.ExposeServiceRequest - (*GetServiceRequest)(nil), // 66: openshell.v1.GetServiceRequest - (*ListServicesRequest)(nil), // 67: openshell.v1.ListServicesRequest - (*ListServicesResponse)(nil), // 68: openshell.v1.ListServicesResponse - (*DeleteServiceRequest)(nil), // 69: openshell.v1.DeleteServiceRequest - (*DeleteServiceResponse)(nil), // 70: openshell.v1.DeleteServiceResponse - (*ServiceEndpoint)(nil), // 71: openshell.v1.ServiceEndpoint - (*ServiceEndpointResponse)(nil), // 72: openshell.v1.ServiceEndpointResponse - (*RevokeSshSessionRequest)(nil), // 73: openshell.v1.RevokeSshSessionRequest - (*RevokeSshSessionResponse)(nil), // 74: openshell.v1.RevokeSshSessionResponse - (*ExecSandboxRequest)(nil), // 75: openshell.v1.ExecSandboxRequest - (*ExecSandboxStdout)(nil), // 76: openshell.v1.ExecSandboxStdout - (*ExecSandboxStderr)(nil), // 77: openshell.v1.ExecSandboxStderr - (*ExecSandboxExit)(nil), // 78: openshell.v1.ExecSandboxExit - (*ExecSandboxEvent)(nil), // 79: openshell.v1.ExecSandboxEvent - (*TcpForwardInit)(nil), // 80: openshell.v1.TcpForwardInit - (*TcpForwardFrame)(nil), // 81: openshell.v1.TcpForwardFrame - (*ExecSandboxInput)(nil), // 82: openshell.v1.ExecSandboxInput - (*ExecSandboxWindowResize)(nil), // 83: openshell.v1.ExecSandboxWindowResize - (*SshSession)(nil), // 84: openshell.v1.SshSession - (*WatchSandboxRequest)(nil), // 85: openshell.v1.WatchSandboxRequest - (*SandboxStreamEvent)(nil), // 86: openshell.v1.SandboxStreamEvent - (*SandboxLogLine)(nil), // 87: openshell.v1.SandboxLogLine - (*SandboxStreamWarning)(nil), // 88: openshell.v1.SandboxStreamWarning - (*CreateProviderRequest)(nil), // 89: openshell.v1.CreateProviderRequest - (*GetProviderRequest)(nil), // 90: openshell.v1.GetProviderRequest - (*ListProvidersRequest)(nil), // 91: openshell.v1.ListProvidersRequest - (*UpdateProviderRequest)(nil), // 92: openshell.v1.UpdateProviderRequest - (*DeleteProviderRequest)(nil), // 93: openshell.v1.DeleteProviderRequest - (*ProviderResponse)(nil), // 94: openshell.v1.ProviderResponse - (*ListProvidersResponse)(nil), // 95: openshell.v1.ListProvidersResponse - (*ListProviderProfilesRequest)(nil), // 96: openshell.v1.ListProviderProfilesRequest - (*GetProviderProfileRequest)(nil), // 97: openshell.v1.GetProviderProfileRequest - (*ProviderProfileImportItem)(nil), // 98: openshell.v1.ProviderProfileImportItem - (*ProviderProfileDiagnostic)(nil), // 99: openshell.v1.ProviderProfileDiagnostic - (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 100: openshell.v1.ProviderCredentialTokenGrantAudienceOverride - (*ProviderCredentialTokenGrantSubjectToken)(nil), // 101: openshell.v1.ProviderCredentialTokenGrantSubjectToken - (*ProviderCredentialTokenGrant)(nil), // 102: openshell.v1.ProviderCredentialTokenGrant - (*ProviderProfileCredential)(nil), // 103: openshell.v1.ProviderProfileCredential - (*ProviderCredentialRefreshMaterial)(nil), // 104: openshell.v1.ProviderCredentialRefreshMaterial - (*ProviderCredentialRefreshOutput)(nil), // 105: openshell.v1.ProviderCredentialRefreshOutput - (*ProviderCredentialRefresh)(nil), // 106: openshell.v1.ProviderCredentialRefresh - (*ProviderCredentialRefreshStatus)(nil), // 107: openshell.v1.ProviderCredentialRefreshStatus - (*ProviderProfileDiscovery)(nil), // 108: openshell.v1.ProviderProfileDiscovery - (*GetProviderRefreshStatusRequest)(nil), // 109: openshell.v1.GetProviderRefreshStatusRequest - (*GetProviderRefreshStatusResponse)(nil), // 110: openshell.v1.GetProviderRefreshStatusResponse - (*ConfigureProviderRefreshRequest)(nil), // 111: openshell.v1.ConfigureProviderRefreshRequest - (*ConfigureProviderRefreshResponse)(nil), // 112: openshell.v1.ConfigureProviderRefreshResponse - (*RotateProviderCredentialRequest)(nil), // 113: openshell.v1.RotateProviderCredentialRequest - (*RotateProviderCredentialResponse)(nil), // 114: openshell.v1.RotateProviderCredentialResponse - (*DeleteProviderRefreshRequest)(nil), // 115: openshell.v1.DeleteProviderRefreshRequest - (*DeleteProviderRefreshResponse)(nil), // 116: openshell.v1.DeleteProviderRefreshResponse - (*ProviderProfile)(nil), // 117: openshell.v1.ProviderProfile - (*ProviderProfileResponse)(nil), // 118: openshell.v1.ProviderProfileResponse - (*ListProviderProfilesResponse)(nil), // 119: openshell.v1.ListProviderProfilesResponse - (*ImportProviderProfilesRequest)(nil), // 120: openshell.v1.ImportProviderProfilesRequest - (*ImportProviderProfilesResponse)(nil), // 121: openshell.v1.ImportProviderProfilesResponse - (*UpdateProviderProfilesRequest)(nil), // 122: openshell.v1.UpdateProviderProfilesRequest - (*UpdateProviderProfilesResponse)(nil), // 123: openshell.v1.UpdateProviderProfilesResponse - (*LintProviderProfilesRequest)(nil), // 124: openshell.v1.LintProviderProfilesRequest - (*LintProviderProfilesResponse)(nil), // 125: openshell.v1.LintProviderProfilesResponse - (*DeleteProviderResponse)(nil), // 126: openshell.v1.DeleteProviderResponse - (*DeleteProviderProfileRequest)(nil), // 127: openshell.v1.DeleteProviderProfileRequest - (*DeleteProviderProfileResponse)(nil), // 128: openshell.v1.DeleteProviderProfileResponse - (*GetSandboxProviderEnvironmentRequest)(nil), // 129: openshell.v1.GetSandboxProviderEnvironmentRequest - (*StaticCredentialEndpointBinding)(nil), // 130: openshell.v1.StaticCredentialEndpointBinding - (*StaticCredentialBinding)(nil), // 131: openshell.v1.StaticCredentialBinding - (*GetSandboxProviderEnvironmentResponse)(nil), // 132: openshell.v1.GetSandboxProviderEnvironmentResponse - (*ExchangeProviderSubjectTokenRequest)(nil), // 133: openshell.v1.ExchangeProviderSubjectTokenRequest - (*ExchangeProviderSubjectTokenResponse)(nil), // 134: openshell.v1.ExchangeProviderSubjectTokenResponse - (*UpdateConfigRequest)(nil), // 135: openshell.v1.UpdateConfigRequest - (*PolicyMergeOperation)(nil), // 136: openshell.v1.PolicyMergeOperation - (*AddNetworkRule)(nil), // 137: openshell.v1.AddNetworkRule - (*RemoveNetworkEndpoint)(nil), // 138: openshell.v1.RemoveNetworkEndpoint - (*RemoveNetworkRule)(nil), // 139: openshell.v1.RemoveNetworkRule - (*AddDenyRules)(nil), // 140: openshell.v1.AddDenyRules - (*AddAllowRules)(nil), // 141: openshell.v1.AddAllowRules - (*RemoveNetworkBinary)(nil), // 142: openshell.v1.RemoveNetworkBinary - (*UpdateConfigResponse)(nil), // 143: openshell.v1.UpdateConfigResponse - (*GetSandboxPolicyStatusRequest)(nil), // 144: openshell.v1.GetSandboxPolicyStatusRequest - (*GetSandboxPolicyStatusResponse)(nil), // 145: openshell.v1.GetSandboxPolicyStatusResponse - (*ListSandboxPoliciesRequest)(nil), // 146: openshell.v1.ListSandboxPoliciesRequest - (*ListSandboxPoliciesResponse)(nil), // 147: openshell.v1.ListSandboxPoliciesResponse - (*ReportPolicyStatusRequest)(nil), // 148: openshell.v1.ReportPolicyStatusRequest - (*ReportPolicyStatusResponse)(nil), // 149: openshell.v1.ReportPolicyStatusResponse - (*SandboxPolicyRevision)(nil), // 150: openshell.v1.SandboxPolicyRevision - (*GetSandboxLogsRequest)(nil), // 151: openshell.v1.GetSandboxLogsRequest - (*PushSandboxLogsRequest)(nil), // 152: openshell.v1.PushSandboxLogsRequest - (*PushSandboxLogsResponse)(nil), // 153: openshell.v1.PushSandboxLogsResponse - (*GetSandboxLogsResponse)(nil), // 154: openshell.v1.GetSandboxLogsResponse - (*SupervisorMessage)(nil), // 155: openshell.v1.SupervisorMessage - (*GatewayMessage)(nil), // 156: openshell.v1.GatewayMessage - (*SupervisorHello)(nil), // 157: openshell.v1.SupervisorHello - (*SessionAccepted)(nil), // 158: openshell.v1.SessionAccepted - (*SessionRejected)(nil), // 159: openshell.v1.SessionRejected - (*SupervisorHeartbeat)(nil), // 160: openshell.v1.SupervisorHeartbeat - (*GatewayHeartbeat)(nil), // 161: openshell.v1.GatewayHeartbeat - (*ReportMainProcessExitRequest)(nil), // 162: openshell.v1.ReportMainProcessExitRequest - (*ReportMainProcessExitResponse)(nil), // 163: openshell.v1.ReportMainProcessExitResponse - (*FinalizeMainProcessExitRequest)(nil), // 164: openshell.v1.FinalizeMainProcessExitRequest - (*FinalizeMainProcessExitResponse)(nil), // 165: openshell.v1.FinalizeMainProcessExitResponse - (*RelayOpen)(nil), // 166: openshell.v1.RelayOpen - (*SshRelayTarget)(nil), // 167: openshell.v1.SshRelayTarget - (*TcpRelayTarget)(nil), // 168: openshell.v1.TcpRelayTarget - (*RelayInit)(nil), // 169: openshell.v1.RelayInit - (*RelayFrame)(nil), // 170: openshell.v1.RelayFrame - (*RelayOpenResult)(nil), // 171: openshell.v1.RelayOpenResult - (*RelayClose)(nil), // 172: openshell.v1.RelayClose - (*L7RequestSample)(nil), // 173: openshell.v1.L7RequestSample - (*DenialSummary)(nil), // 174: openshell.v1.DenialSummary - (*DenialGroupCount)(nil), // 175: openshell.v1.DenialGroupCount - (*NetworkActivitySummary)(nil), // 176: openshell.v1.NetworkActivitySummary - (*PolicyChunk)(nil), // 177: openshell.v1.PolicyChunk - (*DraftPolicyUpdate)(nil), // 178: openshell.v1.DraftPolicyUpdate - (*SubmitPolicyAnalysisRequest)(nil), // 179: openshell.v1.SubmitPolicyAnalysisRequest - (*SubmitPolicyAnalysisResponse)(nil), // 180: openshell.v1.SubmitPolicyAnalysisResponse - (*GetDraftPolicyRequest)(nil), // 181: openshell.v1.GetDraftPolicyRequest - (*GetDraftPolicyResponse)(nil), // 182: openshell.v1.GetDraftPolicyResponse - (*ApproveDraftChunkRequest)(nil), // 183: openshell.v1.ApproveDraftChunkRequest - (*ApproveDraftChunkResponse)(nil), // 184: openshell.v1.ApproveDraftChunkResponse - (*RejectDraftChunkRequest)(nil), // 185: openshell.v1.RejectDraftChunkRequest - (*RejectDraftChunkResponse)(nil), // 186: openshell.v1.RejectDraftChunkResponse - (*DraftChunkApproval)(nil), // 187: openshell.v1.DraftChunkApproval - (*ApproveAllDraftChunksRequest)(nil), // 188: openshell.v1.ApproveAllDraftChunksRequest - (*ApproveAllDraftChunksResponse)(nil), // 189: openshell.v1.ApproveAllDraftChunksResponse - (*EditDraftChunkRequest)(nil), // 190: openshell.v1.EditDraftChunkRequest - (*EditDraftChunkResponse)(nil), // 191: openshell.v1.EditDraftChunkResponse - (*UndoDraftChunkRequest)(nil), // 192: openshell.v1.UndoDraftChunkRequest - (*UndoDraftChunkResponse)(nil), // 193: openshell.v1.UndoDraftChunkResponse - (*ClearDraftChunksRequest)(nil), // 194: openshell.v1.ClearDraftChunksRequest - (*ClearDraftChunksResponse)(nil), // 195: openshell.v1.ClearDraftChunksResponse - (*GetDraftHistoryRequest)(nil), // 196: openshell.v1.GetDraftHistoryRequest - (*DraftHistoryEntry)(nil), // 197: openshell.v1.DraftHistoryEntry - (*GetDraftHistoryResponse)(nil), // 198: openshell.v1.GetDraftHistoryResponse - (*CreateWorkspaceRequest)(nil), // 199: openshell.v1.CreateWorkspaceRequest - (*CreateWorkspaceResponse)(nil), // 200: openshell.v1.CreateWorkspaceResponse - (*GetWorkspaceRequest)(nil), // 201: openshell.v1.GetWorkspaceRequest - (*GetWorkspaceResponse)(nil), // 202: openshell.v1.GetWorkspaceResponse - (*ListWorkspacesRequest)(nil), // 203: openshell.v1.ListWorkspacesRequest - (*ListWorkspacesResponse)(nil), // 204: openshell.v1.ListWorkspacesResponse - (*DeleteWorkspaceRequest)(nil), // 205: openshell.v1.DeleteWorkspaceRequest - (*DeleteWorkspaceResponse)(nil), // 206: openshell.v1.DeleteWorkspaceResponse - (*WorkspaceMember)(nil), // 207: openshell.v1.WorkspaceMember - (*AddWorkspaceMemberRequest)(nil), // 208: openshell.v1.AddWorkspaceMemberRequest - (*AddWorkspaceMemberResponse)(nil), // 209: openshell.v1.AddWorkspaceMemberResponse - (*RemoveWorkspaceMemberRequest)(nil), // 210: openshell.v1.RemoveWorkspaceMemberRequest - (*RemoveWorkspaceMemberResponse)(nil), // 211: openshell.v1.RemoveWorkspaceMemberResponse - (*ListWorkspaceMembersRequest)(nil), // 212: openshell.v1.ListWorkspaceMembersRequest - (*ListWorkspaceMembersResponse)(nil), // 213: openshell.v1.ListWorkspaceMembersResponse - (*ExtensionServiceCredential)(nil), // 214: openshell.v1.ExtensionServiceCredential - nil, // 215: openshell.v1.SandboxSpec.EnvironmentEntry - nil, // 216: openshell.v1.SandboxTemplate.LabelsEntry - nil, // 217: openshell.v1.SandboxTemplate.AnnotationsEntry - nil, // 218: openshell.v1.SandboxTemplate.EnvironmentEntry - nil, // 219: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - nil, // 220: openshell.v1.PlatformEvent.MetadataEntry - nil, // 221: openshell.v1.CreateSandboxRequest.LabelsEntry - nil, // 222: openshell.v1.CreateSandboxRequest.AnnotationsEntry - nil, // 223: openshell.v1.ExecSandboxRequest.EnvironmentEntry - nil, // 224: openshell.v1.SandboxLogLine.FieldsEntry - nil, // 225: openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry - nil, // 226: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - nil, // 227: openshell.v1.ProviderProfile.AnnotationsEntry - nil, // 228: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - nil, // 229: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry - nil, // 230: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - nil, // 231: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - nil, // 232: openshell.v1.UpdateConfigRequest.AnnotationsEntry - nil, // 233: openshell.v1.UpdateConfigResponse.AnnotationsEntry - nil, // 234: openshell.v1.SandboxPolicyRevision.ProvenanceEntry - nil, // 235: openshell.v1.CreateWorkspaceRequest.LabelsEntry - (*datamodelv1.ObjectMeta)(nil), // 236: openshell.datamodel.v1.ObjectMeta - (*sandboxv1.SandboxPolicy)(nil), // 237: openshell.sandbox.v1.SandboxPolicy - (*structpb.Struct)(nil), // 238: google.protobuf.Struct - (*durationpb.Duration)(nil), // 239: google.protobuf.Duration - (*datamodelv1.WorkspaceSelector)(nil), // 240: openshell.datamodel.v1.WorkspaceSelector - (*datamodelv1.Provider)(nil), // 241: openshell.datamodel.v1.Provider - (*sandboxv1.NetworkEndpoint)(nil), // 242: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 243: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 244: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 245: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 246: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 247: openshell.sandbox.v1.L7Rule - (*datamodelv1.Workspace)(nil), // 248: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 249: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 250: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 251: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 252: openshell.sandbox.v1.GetGatewayConfigResponse + (ProviderEnvironmentValueClassification)(0), // 4: openshell.v1.ProviderEnvironmentValueClassification + (PolicyStatus)(0), // 5: openshell.v1.PolicyStatus + (ConfigComponent)(0), // 6: openshell.v1.ConfigComponent + (ConfigApplyOutcome)(0), // 7: openshell.v1.ConfigApplyOutcome + (ServiceStatus)(0), // 8: openshell.v1.ServiceStatus + (WorkspaceRole)(0), // 9: openshell.v1.WorkspaceRole + (ProviderCredentialRefreshRecoveryAction)(0), // 10: openshell.v1.ProviderCredentialRefreshRecoveryAction + (*IssueSandboxTokenRequest)(nil), // 11: openshell.v1.IssueSandboxTokenRequest + (*IssueSandboxTokenResponse)(nil), // 12: openshell.v1.IssueSandboxTokenResponse + (*RefreshSandboxTokenRequest)(nil), // 13: openshell.v1.RefreshSandboxTokenRequest + (*RefreshSandboxTokenResponse)(nil), // 14: openshell.v1.RefreshSandboxTokenResponse + (*HealthRequest)(nil), // 15: openshell.v1.HealthRequest + (*HealthResponse)(nil), // 16: openshell.v1.HealthResponse + (*GetCurrentUserRequest)(nil), // 17: openshell.v1.GetCurrentUserRequest + (*GetCurrentUserResponse)(nil), // 18: openshell.v1.GetCurrentUserResponse + (*GetGatewayInfoRequest)(nil), // 19: openshell.v1.GetGatewayInfoRequest + (*GetGatewayInfoResponse)(nil), // 20: openshell.v1.GetGatewayInfoResponse + (*ComputeDriverInfo)(nil), // 21: openshell.v1.ComputeDriverInfo + (*ComputeDriverCapabilities)(nil), // 22: openshell.v1.ComputeDriverCapabilities + (*ResourceCapabilities)(nil), // 23: openshell.v1.ResourceCapabilities + (*CpuResourceCapabilities)(nil), // 24: openshell.v1.CpuResourceCapabilities + (*MemoryResourceCapabilities)(nil), // 25: openshell.v1.MemoryResourceCapabilities + (*GpuResourceCapabilities)(nil), // 26: openshell.v1.GpuResourceCapabilities + (*Sandbox)(nil), // 27: openshell.v1.Sandbox + (*SandboxSpec)(nil), // 28: openshell.v1.SandboxSpec + (*ResourceRequirements)(nil), // 29: openshell.v1.ResourceRequirements + (*GpuResourceRequirements)(nil), // 30: openshell.v1.GpuResourceRequirements + (*SandboxTemplate)(nil), // 31: openshell.v1.SandboxTemplate + (*SandboxWorkloadTemplate)(nil), // 32: openshell.v1.SandboxWorkloadTemplate + (*SandboxWorkloadTemplateSpec)(nil), // 33: openshell.v1.SandboxWorkloadTemplateSpec + (*SandboxWorkloadConfig)(nil), // 34: openshell.v1.SandboxWorkloadConfig + (*SandboxResources)(nil), // 35: openshell.v1.SandboxResources + (*SandboxServiceLevel)(nil), // 36: openshell.v1.SandboxServiceLevel + (*SandboxStartup)(nil), // 37: openshell.v1.SandboxStartup + (*SandboxWorkloadTemplateProvenance)(nil), // 38: openshell.v1.SandboxWorkloadTemplateProvenance + (*SandboxStatus)(nil), // 39: openshell.v1.SandboxStatus + (*SandboxCondition)(nil), // 40: openshell.v1.SandboxCondition + (*PlatformEvent)(nil), // 41: openshell.v1.PlatformEvent + (*CreateSandboxRequest)(nil), // 42: openshell.v1.CreateSandboxRequest + (*CreateSandboxTemplateRequest)(nil), // 43: openshell.v1.CreateSandboxTemplateRequest + (*GetSandboxTemplateRequest)(nil), // 44: openshell.v1.GetSandboxTemplateRequest + (*ListSandboxTemplatesRequest)(nil), // 45: openshell.v1.ListSandboxTemplatesRequest + (*DeleteSandboxTemplateRequest)(nil), // 46: openshell.v1.DeleteSandboxTemplateRequest + (*SandboxTemplateResponse)(nil), // 47: openshell.v1.SandboxTemplateResponse + (*ListSandboxTemplatesResponse)(nil), // 48: openshell.v1.ListSandboxTemplatesResponse + (*DeleteSandboxTemplateResponse)(nil), // 49: openshell.v1.DeleteSandboxTemplateResponse + (*BeginRootfsTarStagingRequest)(nil), // 50: openshell.v1.BeginRootfsTarStagingRequest + (*BeginRootfsTarStagingResponse)(nil), // 51: openshell.v1.BeginRootfsTarStagingResponse + (*GetSandboxRequest)(nil), // 52: openshell.v1.GetSandboxRequest + (*ListSandboxesRequest)(nil), // 53: openshell.v1.ListSandboxesRequest + (*ListSandboxProvidersRequest)(nil), // 54: openshell.v1.ListSandboxProvidersRequest + (*AttachSandboxProviderRequest)(nil), // 55: openshell.v1.AttachSandboxProviderRequest + (*DetachSandboxProviderRequest)(nil), // 56: openshell.v1.DetachSandboxProviderRequest + (*DeleteSandboxRequest)(nil), // 57: openshell.v1.DeleteSandboxRequest + (*StopSandboxRequest)(nil), // 58: openshell.v1.StopSandboxRequest + (*StartSandboxRequest)(nil), // 59: openshell.v1.StartSandboxRequest + (*SandboxResponse)(nil), // 60: openshell.v1.SandboxResponse + (*ListSandboxesResponse)(nil), // 61: openshell.v1.ListSandboxesResponse + (*ListSandboxProvidersResponse)(nil), // 62: openshell.v1.ListSandboxProvidersResponse + (*AttachSandboxProviderResponse)(nil), // 63: openshell.v1.AttachSandboxProviderResponse + (*DetachSandboxProviderResponse)(nil), // 64: openshell.v1.DetachSandboxProviderResponse + (*DeleteSandboxResponse)(nil), // 65: openshell.v1.DeleteSandboxResponse + (*CreateSshSessionRequest)(nil), // 66: openshell.v1.CreateSshSessionRequest + (*CreateSshSessionResponse)(nil), // 67: openshell.v1.CreateSshSessionResponse + (*ExposeServiceRequest)(nil), // 68: openshell.v1.ExposeServiceRequest + (*GetServiceRequest)(nil), // 69: openshell.v1.GetServiceRequest + (*ListServicesRequest)(nil), // 70: openshell.v1.ListServicesRequest + (*ListServicesResponse)(nil), // 71: openshell.v1.ListServicesResponse + (*DeleteServiceRequest)(nil), // 72: openshell.v1.DeleteServiceRequest + (*DeleteServiceResponse)(nil), // 73: openshell.v1.DeleteServiceResponse + (*ServiceEndpoint)(nil), // 74: openshell.v1.ServiceEndpoint + (*ServiceEndpointResponse)(nil), // 75: openshell.v1.ServiceEndpointResponse + (*RevokeSshSessionRequest)(nil), // 76: openshell.v1.RevokeSshSessionRequest + (*RevokeSshSessionResponse)(nil), // 77: openshell.v1.RevokeSshSessionResponse + (*ExecSandboxRequest)(nil), // 78: openshell.v1.ExecSandboxRequest + (*ExecSandboxStdout)(nil), // 79: openshell.v1.ExecSandboxStdout + (*ExecSandboxStderr)(nil), // 80: openshell.v1.ExecSandboxStderr + (*ExecSandboxExit)(nil), // 81: openshell.v1.ExecSandboxExit + (*ExecSandboxEvent)(nil), // 82: openshell.v1.ExecSandboxEvent + (*TcpForwardInit)(nil), // 83: openshell.v1.TcpForwardInit + (*TcpForwardFrame)(nil), // 84: openshell.v1.TcpForwardFrame + (*ExecSandboxInput)(nil), // 85: openshell.v1.ExecSandboxInput + (*ExecSandboxWindowResize)(nil), // 86: openshell.v1.ExecSandboxWindowResize + (*SshSession)(nil), // 87: openshell.v1.SshSession + (*WatchSandboxRequest)(nil), // 88: openshell.v1.WatchSandboxRequest + (*SandboxStreamEvent)(nil), // 89: openshell.v1.SandboxStreamEvent + (*SandboxLogLine)(nil), // 90: openshell.v1.SandboxLogLine + (*SandboxStreamWarning)(nil), // 91: openshell.v1.SandboxStreamWarning + (*CreateProviderRequest)(nil), // 92: openshell.v1.CreateProviderRequest + (*GetProviderRequest)(nil), // 93: openshell.v1.GetProviderRequest + (*ListProvidersRequest)(nil), // 94: openshell.v1.ListProvidersRequest + (*UpdateProviderRequest)(nil), // 95: openshell.v1.UpdateProviderRequest + (*DeleteProviderRequest)(nil), // 96: openshell.v1.DeleteProviderRequest + (*ProviderResponse)(nil), // 97: openshell.v1.ProviderResponse + (*ListProvidersResponse)(nil), // 98: openshell.v1.ListProvidersResponse + (*ListProviderProfilesRequest)(nil), // 99: openshell.v1.ListProviderProfilesRequest + (*GetProviderProfileRequest)(nil), // 100: openshell.v1.GetProviderProfileRequest + (*ProviderProfileImportItem)(nil), // 101: openshell.v1.ProviderProfileImportItem + (*ProviderProfileDiagnostic)(nil), // 102: openshell.v1.ProviderProfileDiagnostic + (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 103: openshell.v1.ProviderCredentialTokenGrantAudienceOverride + (*ProviderCredentialTokenGrantSubjectToken)(nil), // 104: openshell.v1.ProviderCredentialTokenGrantSubjectToken + (*ProviderCredentialTokenGrant)(nil), // 105: openshell.v1.ProviderCredentialTokenGrant + (*ProviderProfileCredential)(nil), // 106: openshell.v1.ProviderProfileCredential + (*ProviderCredentialRefreshMaterial)(nil), // 107: openshell.v1.ProviderCredentialRefreshMaterial + (*ProviderCredentialRefreshOutput)(nil), // 108: openshell.v1.ProviderCredentialRefreshOutput + (*ProviderCredentialRefresh)(nil), // 109: openshell.v1.ProviderCredentialRefresh + (*ProviderCredentialRefreshStatus)(nil), // 110: openshell.v1.ProviderCredentialRefreshStatus + (*ProviderProfileDiscovery)(nil), // 111: openshell.v1.ProviderProfileDiscovery + (*GetProviderRefreshStatusRequest)(nil), // 112: openshell.v1.GetProviderRefreshStatusRequest + (*GetProviderRefreshStatusResponse)(nil), // 113: openshell.v1.GetProviderRefreshStatusResponse + (*ConfigureProviderRefreshRequest)(nil), // 114: openshell.v1.ConfigureProviderRefreshRequest + (*ConfigureProviderRefreshResponse)(nil), // 115: openshell.v1.ConfigureProviderRefreshResponse + (*RotateProviderCredentialRequest)(nil), // 116: openshell.v1.RotateProviderCredentialRequest + (*RotateProviderCredentialResponse)(nil), // 117: openshell.v1.RotateProviderCredentialResponse + (*DeleteProviderRefreshRequest)(nil), // 118: openshell.v1.DeleteProviderRefreshRequest + (*DeleteProviderRefreshResponse)(nil), // 119: openshell.v1.DeleteProviderRefreshResponse + (*ProviderProfile)(nil), // 120: openshell.v1.ProviderProfile + (*ProviderProfileResponse)(nil), // 121: openshell.v1.ProviderProfileResponse + (*ListProviderProfilesResponse)(nil), // 122: openshell.v1.ListProviderProfilesResponse + (*ImportProviderProfilesRequest)(nil), // 123: openshell.v1.ImportProviderProfilesRequest + (*ImportProviderProfilesResponse)(nil), // 124: openshell.v1.ImportProviderProfilesResponse + (*UpdateProviderProfilesRequest)(nil), // 125: openshell.v1.UpdateProviderProfilesRequest + (*UpdateProviderProfilesResponse)(nil), // 126: openshell.v1.UpdateProviderProfilesResponse + (*LintProviderProfilesRequest)(nil), // 127: openshell.v1.LintProviderProfilesRequest + (*LintProviderProfilesResponse)(nil), // 128: openshell.v1.LintProviderProfilesResponse + (*DeleteProviderResponse)(nil), // 129: openshell.v1.DeleteProviderResponse + (*DeleteProviderProfileRequest)(nil), // 130: openshell.v1.DeleteProviderProfileRequest + (*DeleteProviderProfileResponse)(nil), // 131: openshell.v1.DeleteProviderProfileResponse + (*GetSandboxProviderEnvironmentRequest)(nil), // 132: openshell.v1.GetSandboxProviderEnvironmentRequest + (*StaticCredentialEndpointBinding)(nil), // 133: openshell.v1.StaticCredentialEndpointBinding + (*StaticCredentialBinding)(nil), // 134: openshell.v1.StaticCredentialBinding + (*GetSandboxProviderEnvironmentResponse)(nil), // 135: openshell.v1.GetSandboxProviderEnvironmentResponse + (*ProviderEnvironmentValue)(nil), // 136: openshell.v1.ProviderEnvironmentValue + (*ProviderEnvironmentSnapshot)(nil), // 137: openshell.v1.ProviderEnvironmentSnapshot + (*ExchangeProviderSubjectTokenRequest)(nil), // 138: openshell.v1.ExchangeProviderSubjectTokenRequest + (*ExchangeProviderSubjectTokenResponse)(nil), // 139: openshell.v1.ExchangeProviderSubjectTokenResponse + (*UpdateConfigRequest)(nil), // 140: openshell.v1.UpdateConfigRequest + (*PolicyMergeOperation)(nil), // 141: openshell.v1.PolicyMergeOperation + (*AddNetworkRule)(nil), // 142: openshell.v1.AddNetworkRule + (*RemoveNetworkEndpoint)(nil), // 143: openshell.v1.RemoveNetworkEndpoint + (*RemoveNetworkRule)(nil), // 144: openshell.v1.RemoveNetworkRule + (*AddDenyRules)(nil), // 145: openshell.v1.AddDenyRules + (*AddAllowRules)(nil), // 146: openshell.v1.AddAllowRules + (*RemoveNetworkBinary)(nil), // 147: openshell.v1.RemoveNetworkBinary + (*UpdateConfigResponse)(nil), // 148: openshell.v1.UpdateConfigResponse + (*GetSandboxPolicyStatusRequest)(nil), // 149: openshell.v1.GetSandboxPolicyStatusRequest + (*GetSandboxPolicyStatusResponse)(nil), // 150: openshell.v1.GetSandboxPolicyStatusResponse + (*ListSandboxPoliciesRequest)(nil), // 151: openshell.v1.ListSandboxPoliciesRequest + (*ListSandboxPoliciesResponse)(nil), // 152: openshell.v1.ListSandboxPoliciesResponse + (*ReportPolicyStatusRequest)(nil), // 153: openshell.v1.ReportPolicyStatusRequest + (*ReportPolicyStatusResponse)(nil), // 154: openshell.v1.ReportPolicyStatusResponse + (*SandboxPolicyRevision)(nil), // 155: openshell.v1.SandboxPolicyRevision + (*GetSandboxLogsRequest)(nil), // 156: openshell.v1.GetSandboxLogsRequest + (*PushSandboxLogsRequest)(nil), // 157: openshell.v1.PushSandboxLogsRequest + (*PushSandboxLogsResponse)(nil), // 158: openshell.v1.PushSandboxLogsResponse + (*GetSandboxLogsResponse)(nil), // 159: openshell.v1.GetSandboxLogsResponse + (*SupervisorMessage)(nil), // 160: openshell.v1.SupervisorMessage + (*GatewayMessage)(nil), // 161: openshell.v1.GatewayMessage + (*SupervisorHello)(nil), // 162: openshell.v1.SupervisorHello + (*SessionAccepted)(nil), // 163: openshell.v1.SessionAccepted + (*ConfigBootstrap)(nil), // 164: openshell.v1.ConfigBootstrap + (*ConfigUpdate)(nil), // 165: openshell.v1.ConfigUpdate + (*ConfigSnapshotRevision)(nil), // 166: openshell.v1.ConfigSnapshotRevision + (*SandboxConfigRevision)(nil), // 167: openshell.v1.SandboxConfigRevision + (*ConfigApplyFailure)(nil), // 168: openshell.v1.ConfigApplyFailure + (*ConfigComponentApplyResult)(nil), // 169: openshell.v1.ConfigComponentApplyResult + (*ConfigUpdateResult)(nil), // 170: openshell.v1.ConfigUpdateResult + (*ConfigBootstrapResult)(nil), // 171: openshell.v1.ConfigBootstrapResult + (*SessionRejected)(nil), // 172: openshell.v1.SessionRejected + (*SupervisorHeartbeat)(nil), // 173: openshell.v1.SupervisorHeartbeat + (*GatewayHeartbeat)(nil), // 174: openshell.v1.GatewayHeartbeat + (*ReportMainProcessExitRequest)(nil), // 175: openshell.v1.ReportMainProcessExitRequest + (*ReportMainProcessExitResponse)(nil), // 176: openshell.v1.ReportMainProcessExitResponse + (*FinalizeMainProcessExitRequest)(nil), // 177: openshell.v1.FinalizeMainProcessExitRequest + (*FinalizeMainProcessExitResponse)(nil), // 178: openshell.v1.FinalizeMainProcessExitResponse + (*RelayOpen)(nil), // 179: openshell.v1.RelayOpen + (*SshRelayTarget)(nil), // 180: openshell.v1.SshRelayTarget + (*TcpRelayTarget)(nil), // 181: openshell.v1.TcpRelayTarget + (*RelayInit)(nil), // 182: openshell.v1.RelayInit + (*RelayFrame)(nil), // 183: openshell.v1.RelayFrame + (*RelayOpenResult)(nil), // 184: openshell.v1.RelayOpenResult + (*RelayClose)(nil), // 185: openshell.v1.RelayClose + (*L7RequestSample)(nil), // 186: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 187: openshell.v1.DenialSummary + (*DenialGroupCount)(nil), // 188: openshell.v1.DenialGroupCount + (*NetworkActivitySummary)(nil), // 189: openshell.v1.NetworkActivitySummary + (*PolicyChunk)(nil), // 190: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 191: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 192: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 193: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 194: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 195: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 196: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 197: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 198: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 199: openshell.v1.RejectDraftChunkResponse + (*DraftChunkApproval)(nil), // 200: openshell.v1.DraftChunkApproval + (*ApproveAllDraftChunksRequest)(nil), // 201: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 202: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 203: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 204: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 205: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 206: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 207: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 208: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 209: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 210: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 211: openshell.v1.GetDraftHistoryResponse + (*CreateWorkspaceRequest)(nil), // 212: openshell.v1.CreateWorkspaceRequest + (*CreateWorkspaceResponse)(nil), // 213: openshell.v1.CreateWorkspaceResponse + (*GetWorkspaceRequest)(nil), // 214: openshell.v1.GetWorkspaceRequest + (*GetWorkspaceResponse)(nil), // 215: openshell.v1.GetWorkspaceResponse + (*ListWorkspacesRequest)(nil), // 216: openshell.v1.ListWorkspacesRequest + (*ListWorkspacesResponse)(nil), // 217: openshell.v1.ListWorkspacesResponse + (*DeleteWorkspaceRequest)(nil), // 218: openshell.v1.DeleteWorkspaceRequest + (*DeleteWorkspaceResponse)(nil), // 219: openshell.v1.DeleteWorkspaceResponse + (*WorkspaceMember)(nil), // 220: openshell.v1.WorkspaceMember + (*AddWorkspaceMemberRequest)(nil), // 221: openshell.v1.AddWorkspaceMemberRequest + (*AddWorkspaceMemberResponse)(nil), // 222: openshell.v1.AddWorkspaceMemberResponse + (*RemoveWorkspaceMemberRequest)(nil), // 223: openshell.v1.RemoveWorkspaceMemberRequest + (*RemoveWorkspaceMemberResponse)(nil), // 224: openshell.v1.RemoveWorkspaceMemberResponse + (*ListWorkspaceMembersRequest)(nil), // 225: openshell.v1.ListWorkspaceMembersRequest + (*ListWorkspaceMembersResponse)(nil), // 226: openshell.v1.ListWorkspaceMembersResponse + (*ExtensionServiceCredential)(nil), // 227: openshell.v1.ExtensionServiceCredential + nil, // 228: openshell.v1.SandboxSpec.EnvironmentEntry + nil, // 229: openshell.v1.SandboxTemplate.LabelsEntry + nil, // 230: openshell.v1.SandboxTemplate.AnnotationsEntry + nil, // 231: openshell.v1.SandboxTemplate.EnvironmentEntry + nil, // 232: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + nil, // 233: openshell.v1.PlatformEvent.MetadataEntry + nil, // 234: openshell.v1.CreateSandboxRequest.LabelsEntry + nil, // 235: openshell.v1.CreateSandboxRequest.AnnotationsEntry + nil, // 236: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 237: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 238: openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry + nil, // 239: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + nil, // 240: openshell.v1.ProviderProfile.AnnotationsEntry + nil, // 241: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + nil, // 242: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry + nil, // 243: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + nil, // 244: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + nil, // 245: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + nil, // 246: openshell.v1.UpdateConfigRequest.AnnotationsEntry + nil, // 247: openshell.v1.UpdateConfigResponse.AnnotationsEntry + nil, // 248: openshell.v1.SandboxPolicyRevision.ProvenanceEntry + nil, // 249: openshell.v1.CreateWorkspaceRequest.LabelsEntry + (*datamodelv1.ObjectMeta)(nil), // 250: openshell.datamodel.v1.ObjectMeta + (*sandboxv1.SandboxPolicy)(nil), // 251: openshell.sandbox.v1.SandboxPolicy + (*structpb.Struct)(nil), // 252: google.protobuf.Struct + (*durationpb.Duration)(nil), // 253: google.protobuf.Duration + (*datamodelv1.WorkspaceSelector)(nil), // 254: openshell.datamodel.v1.WorkspaceSelector + (*datamodelv1.Provider)(nil), // 255: openshell.datamodel.v1.Provider + (*sandboxv1.NetworkEndpoint)(nil), // 256: openshell.sandbox.v1.NetworkEndpoint + (*sandboxv1.NetworkBinary)(nil), // 257: openshell.sandbox.v1.NetworkBinary + (*sandboxv1.SettingValue)(nil), // 258: openshell.sandbox.v1.SettingValue + (*sandboxv1.NetworkPolicyRule)(nil), // 259: openshell.sandbox.v1.NetworkPolicyRule + (*sandboxv1.L7DenyRule)(nil), // 260: openshell.sandbox.v1.L7DenyRule + (*sandboxv1.L7Rule)(nil), // 261: openshell.sandbox.v1.L7Rule + (*sandboxv1.SandboxConfigSnapshot)(nil), // 262: openshell.sandbox.v1.SandboxConfigSnapshot + (sandboxv1.PolicySource)(0), // 263: openshell.sandbox.v1.PolicySource + (*datamodelv1.Workspace)(nil), // 264: openshell.datamodel.v1.Workspace + (*sandboxv1.GetSandboxConfigRequest)(nil), // 265: openshell.sandbox.v1.GetSandboxConfigRequest + (*sandboxv1.GetGatewayConfigRequest)(nil), // 266: openshell.sandbox.v1.GetGatewayConfigRequest + (*sandboxv1.GetSandboxConfigResponse)(nil), // 267: openshell.sandbox.v1.GetSandboxConfigResponse + (*sandboxv1.GetGatewayConfigResponse)(nil), // 268: openshell.sandbox.v1.GetGatewayConfigResponse } var file_openshell_proto_depIdxs = []int32{ - 214, // 0: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential - 5, // 1: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus - 5, // 2: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus - 18, // 3: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo - 19, // 4: openshell.v1.ComputeDriverInfo.capabilities:type_name -> openshell.v1.ComputeDriverCapabilities - 20, // 5: openshell.v1.ComputeDriverCapabilities.resource_capabilities:type_name -> openshell.v1.ResourceCapabilities - 21, // 6: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities - 22, // 7: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities - 23, // 8: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities - 236, // 9: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 25, // 10: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec - 36, // 11: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus - 35, // 12: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance - 215, // 13: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry - 28, // 14: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate - 237, // 15: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 26, // 16: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements - 27, // 17: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements - 216, // 18: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry - 217, // 19: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry - 218, // 20: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry - 238, // 21: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct - 238, // 22: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct - 236, // 23: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 30, // 24: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec - 31, // 25: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig - 238, // 26: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct - 33, // 27: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel - 219, // 28: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - 32, // 29: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources - 27, // 30: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements - 34, // 31: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup - 239, // 32: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration - 37, // 33: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition + 227, // 0: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential + 8, // 1: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus + 8, // 2: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus + 21, // 3: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo + 22, // 4: openshell.v1.ComputeDriverInfo.capabilities:type_name -> openshell.v1.ComputeDriverCapabilities + 23, // 5: openshell.v1.ComputeDriverCapabilities.resource_capabilities:type_name -> openshell.v1.ResourceCapabilities + 24, // 6: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities + 25, // 7: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities + 26, // 8: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities + 250, // 9: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 28, // 10: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec + 39, // 11: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus + 38, // 12: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance + 228, // 13: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry + 31, // 14: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate + 251, // 15: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 29, // 16: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements + 30, // 17: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements + 229, // 18: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry + 230, // 19: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry + 231, // 20: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry + 252, // 21: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 252, // 22: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct + 250, // 23: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 33, // 24: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec + 34, // 25: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig + 252, // 26: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct + 36, // 27: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel + 232, // 28: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + 35, // 29: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources + 30, // 30: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements + 37, // 31: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup + 253, // 32: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 40, // 33: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition 0, // 34: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 220, // 35: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 25, // 36: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 221, // 37: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 222, // 38: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 240, // 39: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 29, // 40: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 240, // 41: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 42: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 43: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 44: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 29, // 45: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 29, // 46: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate - 240, // 47: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 48: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 49: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 50: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 51: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 52: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 53: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 54: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 55: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 24, // 56: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 24, // 57: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 241, // 58: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 24, // 59: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 24, // 60: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 240, // 61: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 62: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 63: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 72, // 64: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 240, // 65: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 236, // 66: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 71, // 67: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint - 223, // 68: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 76, // 69: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout - 77, // 70: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr - 78, // 71: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 167, // 72: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 168, // 73: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget - 80, // 74: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit - 75, // 75: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest - 83, // 76: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 236, // 77: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 24, // 78: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox - 87, // 79: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine - 38, // 80: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent - 88, // 81: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 178, // 82: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 224, // 83: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 241, // 84: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 240, // 85: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 86: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 87: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 241, // 88: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 225, // 89: openshell.v1.UpdateProviderRequest.credential_expires_at_ms:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry - 240, // 90: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 91: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 241, // 92: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider - 241, // 93: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 117, // 94: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 100, // 95: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride + 233, // 35: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 28, // 36: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec + 234, // 37: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 235, // 38: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 254, // 39: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 32, // 40: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 254, // 41: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 42: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 43: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 44: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 32, // 45: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 32, // 46: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate + 254, // 47: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 48: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 49: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 50: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 51: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 52: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 53: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 54: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 55: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 27, // 56: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox + 27, // 57: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox + 255, // 58: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 27, // 59: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 27, // 60: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 254, // 61: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 62: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 63: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 75, // 64: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse + 254, // 65: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 250, // 66: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 74, // 67: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint + 236, // 68: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 79, // 69: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout + 80, // 70: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr + 81, // 71: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit + 180, // 72: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget + 181, // 73: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget + 83, // 74: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit + 78, // 75: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest + 86, // 76: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize + 250, // 77: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 27, // 78: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox + 90, // 79: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine + 41, // 80: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent + 91, // 81: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning + 191, // 82: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 237, // 83: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 255, // 84: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 254, // 85: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 86: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 87: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 255, // 88: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 238, // 89: openshell.v1.UpdateProviderRequest.credential_expires_at_ms:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry + 254, // 90: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 91: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 255, // 92: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 255, // 93: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 120, // 94: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile + 103, // 95: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride 1, // 96: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType - 101, // 97: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken - 106, // 98: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh - 102, // 99: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant + 104, // 97: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken + 109, // 98: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh + 105, // 99: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant 2, // 100: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 104, // 101: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial - 105, // 102: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput + 107, // 101: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial + 108, // 102: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput 2, // 103: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 7, // 104: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 240, // 105: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 107, // 106: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 10, // 104: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 254, // 105: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 110, // 106: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus 2, // 107: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 226, // 108: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 240, // 109: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 107, // 110: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 240, // 111: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 107, // 112: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 240, // 113: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 239, // 108: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 254, // 109: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 110, // 110: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 254, // 111: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 110, // 112: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 254, // 113: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 3, // 114: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory - 103, // 115: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 242, // 116: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 243, // 117: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 108, // 118: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 227, // 119: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 117, // 120: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 117, // 121: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 98, // 122: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 99, // 123: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 117, // 124: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 98, // 125: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 99, // 126: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 117, // 127: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 98, // 128: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 99, // 129: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 130, // 130: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 228, // 131: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 229, // 132: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expires_at_ms:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry - 230, // 133: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 231, // 134: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 237, // 135: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 244, // 136: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 136, // 137: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 232, // 138: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 240, // 139: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 137, // 140: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 138, // 141: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 139, // 142: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 140, // 143: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 141, // 144: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 142, // 145: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 245, // 146: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 246, // 147: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 247, // 148: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 233, // 149: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 240, // 150: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 150, // 151: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 240, // 152: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 150, // 153: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 4, // 154: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 4, // 155: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 237, // 156: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 234, // 157: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 240, // 158: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 87, // 159: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 87, // 160: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 157, // 161: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 160, // 162: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 171, // 163: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 172, // 164: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 158, // 165: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 159, // 166: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 161, // 167: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 166, // 168: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 172, // 169: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 167, // 170: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 168, // 171: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 169, // 172: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 173, // 173: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 175, // 174: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 245, // 175: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 237, // 176: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 237, // 177: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 174, // 178: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 177, // 179: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 176, // 180: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 240, // 181: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 177, // 182: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 240, // 183: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 184: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 187, // 185: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval - 240, // 186: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 245, // 187: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 240, // 188: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 189: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 190: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 240, // 191: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 197, // 192: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 235, // 193: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 248, // 194: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 248, // 195: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 248, // 196: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 236, // 197: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 6, // 198: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 6, // 199: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 207, // 200: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 207, // 201: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 103, // 202: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 131, // 203: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 12, // 204: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 14, // 205: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 16, // 206: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 39, // 207: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 47, // 208: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest - 49, // 209: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 50, // 210: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 40, // 211: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 41, // 212: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 42, // 213: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 43, // 214: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 51, // 215: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 52, // 216: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 53, // 217: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 54, // 218: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 55, // 219: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 56, // 220: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 63, // 221: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 65, // 222: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 66, // 223: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 67, // 224: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 69, // 225: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 73, // 226: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 75, // 227: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 81, // 228: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 82, // 229: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 89, // 230: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 90, // 231: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 91, // 232: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 96, // 233: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 97, // 234: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 120, // 235: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 122, // 236: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 124, // 237: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 92, // 238: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 109, // 239: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 111, // 240: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 113, // 241: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 115, // 242: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 93, // 243: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 127, // 244: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 249, // 245: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 250, // 246: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 135, // 247: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 144, // 248: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 146, // 249: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 148, // 250: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 129, // 251: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 133, // 252: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest - 151, // 253: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 152, // 254: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 155, // 255: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 162, // 256: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest - 164, // 257: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest - 170, // 258: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 85, // 259: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 179, // 260: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 181, // 261: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 183, // 262: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 185, // 263: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 188, // 264: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 190, // 265: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 192, // 266: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 194, // 267: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 196, // 268: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 8, // 269: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 10, // 270: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 199, // 271: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 201, // 272: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 203, // 273: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 205, // 274: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 208, // 275: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 210, // 276: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 212, // 277: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 13, // 278: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 15, // 279: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 17, // 280: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 57, // 281: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 48, // 282: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse - 57, // 283: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 58, // 284: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 44, // 285: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 44, // 286: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 45, // 287: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 46, // 288: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 59, // 289: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 60, // 290: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 61, // 291: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 62, // 292: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 57, // 293: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 57, // 294: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 64, // 295: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 72, // 296: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 72, // 297: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 68, // 298: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 70, // 299: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 74, // 300: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 79, // 301: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 81, // 302: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 79, // 303: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 94, // 304: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 94, // 305: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 95, // 306: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 119, // 307: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 118, // 308: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 121, // 309: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 123, // 310: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 125, // 311: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 94, // 312: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 110, // 313: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 112, // 314: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 114, // 315: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 116, // 316: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 126, // 317: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 128, // 318: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 251, // 319: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 252, // 320: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 143, // 321: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 145, // 322: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 147, // 323: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 149, // 324: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 132, // 325: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 134, // 326: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse - 154, // 327: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 153, // 328: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 156, // 329: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 163, // 330: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse - 165, // 331: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse - 170, // 332: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 86, // 333: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 180, // 334: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 182, // 335: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 184, // 336: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 186, // 337: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 189, // 338: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 191, // 339: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 193, // 340: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 195, // 341: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 198, // 342: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 9, // 343: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 11, // 344: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 200, // 345: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 202, // 346: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 204, // 347: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 206, // 348: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 209, // 349: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 211, // 350: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 213, // 351: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 278, // [278:352] is the sub-list for method output_type - 204, // [204:278] is the sub-list for method input_type - 204, // [204:204] is the sub-list for extension type_name - 204, // [204:204] is the sub-list for extension extendee - 0, // [0:204] is the sub-list for field type_name + 106, // 115: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential + 256, // 116: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 257, // 117: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 111, // 118: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery + 240, // 119: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 120, // 120: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile + 120, // 121: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 101, // 122: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 102, // 123: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 120, // 124: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 101, // 125: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem + 102, // 126: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 120, // 127: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile + 101, // 128: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 102, // 129: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 133, // 130: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding + 241, // 131: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 242, // 132: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expires_at_ms:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry + 243, // 133: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 244, // 134: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 4, // 135: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification + 134, // 136: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding + 136, // 137: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue + 245, // 138: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + 251, // 139: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 258, // 140: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 141, // 141: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation + 246, // 142: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 254, // 143: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 142, // 144: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule + 143, // 145: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint + 144, // 146: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule + 145, // 147: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules + 146, // 148: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules + 147, // 149: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary + 259, // 150: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 260, // 151: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 261, // 152: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 247, // 153: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 254, // 154: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 155, // 155: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 254, // 156: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 155, // 157: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 5, // 158: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 5, // 159: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 251, // 160: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 248, // 161: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 254, // 162: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 90, // 163: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 90, // 164: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 162, // 165: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello + 173, // 166: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat + 184, // 167: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 185, // 168: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 170, // 169: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult + 171, // 170: openshell.v1.SupervisorMessage.config_bootstrap_result:type_name -> openshell.v1.ConfigBootstrapResult + 163, // 171: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted + 172, // 172: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected + 174, // 173: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat + 179, // 174: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen + 185, // 175: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 165, // 176: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate + 164, // 177: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigBootstrap + 262, // 178: openshell.v1.ConfigBootstrap.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot + 137, // 179: openshell.v1.ConfigBootstrap.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot + 262, // 180: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot + 137, // 181: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot + 167, // 182: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision + 263, // 183: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 6, // 184: openshell.v1.ConfigComponentApplyResult.component:type_name -> openshell.v1.ConfigComponent + 166, // 185: openshell.v1.ConfigComponentApplyResult.requested_revision:type_name -> openshell.v1.ConfigSnapshotRevision + 166, // 186: openshell.v1.ConfigComponentApplyResult.applied_revision:type_name -> openshell.v1.ConfigSnapshotRevision + 7, // 187: openshell.v1.ConfigComponentApplyResult.outcome:type_name -> openshell.v1.ConfigApplyOutcome + 168, // 188: openshell.v1.ConfigComponentApplyResult.failure:type_name -> openshell.v1.ConfigApplyFailure + 169, // 189: openshell.v1.ConfigUpdateResult.result:type_name -> openshell.v1.ConfigComponentApplyResult + 169, // 190: openshell.v1.ConfigBootstrapResult.results:type_name -> openshell.v1.ConfigComponentApplyResult + 180, // 191: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget + 181, // 192: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget + 182, // 193: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit + 186, // 194: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 188, // 195: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 259, // 196: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 251, // 197: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 251, // 198: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 187, // 199: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 190, // 200: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 189, // 201: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 254, // 202: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 190, // 203: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 254, // 204: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 205: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 200, // 206: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval + 254, // 207: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 259, // 208: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 254, // 209: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 210: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 211: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 254, // 212: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 210, // 213: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 249, // 214: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 264, // 215: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 264, // 216: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 264, // 217: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 250, // 218: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 9, // 219: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 9, // 220: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 220, // 221: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 220, // 222: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 106, // 223: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 134, // 224: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 106, // 225: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 15, // 226: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 17, // 227: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 19, // 228: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 42, // 229: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 50, // 230: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest + 52, // 231: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 53, // 232: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 43, // 233: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 44, // 234: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 45, // 235: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 46, // 236: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 54, // 237: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 55, // 238: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 56, // 239: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 57, // 240: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 58, // 241: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 59, // 242: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 66, // 243: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 68, // 244: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 69, // 245: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 70, // 246: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 72, // 247: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 76, // 248: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 78, // 249: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 84, // 250: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 85, // 251: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 92, // 252: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 93, // 253: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 94, // 254: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 99, // 255: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 100, // 256: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 123, // 257: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 125, // 258: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 127, // 259: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 95, // 260: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 112, // 261: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 114, // 262: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 116, // 263: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 118, // 264: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 96, // 265: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 130, // 266: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 265, // 267: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 266, // 268: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 140, // 269: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 149, // 270: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 151, // 271: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 153, // 272: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 132, // 273: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 138, // 274: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest + 156, // 275: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 157, // 276: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 160, // 277: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 175, // 278: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest + 177, // 279: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest + 183, // 280: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 88, // 281: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 192, // 282: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 194, // 283: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 196, // 284: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 198, // 285: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 201, // 286: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 203, // 287: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 205, // 288: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 207, // 289: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 209, // 290: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 11, // 291: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 13, // 292: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 212, // 293: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 214, // 294: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 216, // 295: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 218, // 296: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 221, // 297: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 223, // 298: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 225, // 299: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 16, // 300: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 18, // 301: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 20, // 302: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 60, // 303: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 51, // 304: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse + 60, // 305: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 61, // 306: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 47, // 307: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 47, // 308: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 48, // 309: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 49, // 310: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 62, // 311: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 63, // 312: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 64, // 313: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 65, // 314: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 60, // 315: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 60, // 316: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 67, // 317: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 75, // 318: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 75, // 319: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 71, // 320: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 73, // 321: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 77, // 322: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 82, // 323: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 84, // 324: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 82, // 325: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 97, // 326: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 97, // 327: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 98, // 328: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 122, // 329: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 121, // 330: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 124, // 331: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 126, // 332: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 128, // 333: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 97, // 334: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 113, // 335: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 115, // 336: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 117, // 337: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 119, // 338: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 129, // 339: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 131, // 340: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 267, // 341: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 268, // 342: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 148, // 343: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 150, // 344: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 152, // 345: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 154, // 346: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 135, // 347: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 139, // 348: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse + 159, // 349: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 158, // 350: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 161, // 351: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 176, // 352: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse + 178, // 353: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse + 183, // 354: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 89, // 355: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 193, // 356: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 195, // 357: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 197, // 358: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 199, // 359: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 202, // 360: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 204, // 361: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 206, // 362: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 208, // 363: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 211, // 364: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 12, // 365: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 14, // 366: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 213, // 367: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 215, // 368: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 217, // 369: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 219, // 370: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 222, // 371: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 224, // 372: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 226, // 373: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 300, // [300:374] is the sub-list for method output_type + 226, // [226:300] is the sub-list for method input_type + 226, // [226:226] is the sub-list for extension type_name + 226, // [226:226] is the sub-list for extension extendee + 0, // [0:226] is the sub-list for field type_name } func init() { file_openshell_proto_init() } @@ -16217,7 +17266,8 @@ func file_openshell_proto_init() { (*SandboxStreamEvent_DraftPolicyUpdate)(nil), } file_openshell_proto_msgTypes[103].OneofWrappers = []any{} - file_openshell_proto_msgTypes[128].OneofWrappers = []any{ + file_openshell_proto_msgTypes[125].OneofWrappers = []any{} + file_openshell_proto_msgTypes[130].OneofWrappers = []any{ (*PolicyMergeOperation_AddRule)(nil), (*PolicyMergeOperation_RemoveEndpoint)(nil), (*PolicyMergeOperation_RemoveRule)(nil), @@ -16225,24 +17275,35 @@ func file_openshell_proto_init() { (*PolicyMergeOperation_AddAllowRules)(nil), (*PolicyMergeOperation_RemoveBinary)(nil), } - file_openshell_proto_msgTypes[147].OneofWrappers = []any{ + file_openshell_proto_msgTypes[149].OneofWrappers = []any{ (*SupervisorMessage_Hello)(nil), (*SupervisorMessage_Heartbeat)(nil), (*SupervisorMessage_RelayOpenResult)(nil), (*SupervisorMessage_RelayClose)(nil), + (*SupervisorMessage_ConfigUpdateResult)(nil), + (*SupervisorMessage_ConfigBootstrapResult)(nil), } - file_openshell_proto_msgTypes[148].OneofWrappers = []any{ + file_openshell_proto_msgTypes[150].OneofWrappers = []any{ (*GatewayMessage_SessionAccepted)(nil), (*GatewayMessage_SessionRejected)(nil), (*GatewayMessage_Heartbeat)(nil), (*GatewayMessage_RelayOpen)(nil), (*GatewayMessage_RelayClose)(nil), + (*GatewayMessage_ConfigUpdate)(nil), + } + file_openshell_proto_msgTypes[154].OneofWrappers = []any{ + (*ConfigUpdate_SandboxConfig)(nil), + (*ConfigUpdate_ProviderEnvironment)(nil), + } + file_openshell_proto_msgTypes[155].OneofWrappers = []any{ + (*ConfigSnapshotRevision_SandboxConfig)(nil), + (*ConfigSnapshotRevision_ProviderEnvironment)(nil), } - file_openshell_proto_msgTypes[158].OneofWrappers = []any{ + file_openshell_proto_msgTypes[168].OneofWrappers = []any{ (*RelayOpen_Ssh)(nil), (*RelayOpen_Tcp)(nil), } - file_openshell_proto_msgTypes[162].OneofWrappers = []any{ + file_openshell_proto_msgTypes[172].OneofWrappers = []any{ (*RelayFrame_Init)(nil), (*RelayFrame_Data)(nil), } @@ -16251,8 +17312,8 @@ func file_openshell_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_openshell_proto_rawDesc), len(file_openshell_proto_rawDesc)), - NumEnums: 8, - NumMessages: 228, + NumEnums: 11, + NumMessages: 239, 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 d8f3c91008..8d68c4bb82 100644 --- a/sdk/go/proto/openshellv1/openshell_grpc.pb.go +++ b/sdk/go/proto/openshellv1/openshell_grpc.pb.go @@ -234,9 +234,10 @@ type OpenShellClient interface { // // The supervisor opens this stream at startup and keeps it alive for the // sandbox lifetime. The gateway uses it to coordinate relay channels for - // SSH connect, ExecSandbox, and targetable sandbox services. Raw service - // bytes flow over RelayStream calls (separate HTTP/2 streams on the same - // connection), not over this stream. + // SSH connect, ExecSandbox, targetable sandbox services, and configuration + // delivery. Peers must report the same exact protocol_revision during the + // handshake. Raw service bytes flow over RelayStream calls (separate HTTP/2 + // streams on the same connection), not over this stream. ConnectSupervisor(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[SupervisorMessage, GatewayMessage], error) // Persist the canonical main process result before the supervisor exits. ReportMainProcessExit(ctx context.Context, in *ReportMainProcessExitRequest, opts ...grpc.CallOption) (*ReportMainProcessExitResponse, error) @@ -1224,9 +1225,10 @@ type OpenShellServer interface { // // The supervisor opens this stream at startup and keeps it alive for the // sandbox lifetime. The gateway uses it to coordinate relay channels for - // SSH connect, ExecSandbox, and targetable sandbox services. Raw service - // bytes flow over RelayStream calls (separate HTTP/2 streams on the same - // connection), not over this stream. + // SSH connect, ExecSandbox, targetable sandbox services, and configuration + // delivery. Peers must report the same exact protocol_revision during the + // handshake. Raw service bytes flow over RelayStream calls (separate HTTP/2 + // streams on the same connection), not over this stream. ConnectSupervisor(grpc.BidiStreamingServer[SupervisorMessage, GatewayMessage]) error // Persist the canonical main process result before the supervisor exits. ReportMainProcessExit(context.Context, *ReportMainProcessExitRequest) (*ReportMainProcessExitResponse, error) diff --git a/sdk/go/proto/sandboxv1/sandbox.pb.go b/sdk/go/proto/sandboxv1/sandbox.pb.go index 989589002b..386f7b4cfd 100644 --- a/sdk/go/proto/sandboxv1/sandbox.pb.go +++ b/sdk/go/proto/sandboxv1/sandbox.pb.go @@ -75,7 +75,7 @@ func (SettingScope) EnumDescriptor() ([]byte, []int) { return file_sandbox_proto_rawDescGZIP(), []int{0} } -// Source used for the policy payload in GetSandboxConfigResponse. +// Source used for a sandbox configuration payload. type PolicySource int32 const ( @@ -1801,6 +1801,139 @@ func (x *EffectiveSetting) GetScope() SettingScope { return SettingScope_SETTING_SCOPE_UNSPECIFIED } +// Complete effective sandbox configuration delivered to a supervisor. +type SandboxConfigSnapshot struct { + state protoimpl.MessageState `protogen:"open.v1"` + Policy *SandboxPolicy `protobuf:"bytes,1,opt,name=policy,proto3" json:"policy,omitempty"` + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + PolicyHash string `protobuf:"bytes,3,opt,name=policy_hash,json=policyHash,proto3" json:"policy_hash,omitempty"` + Settings map[string]*EffectiveSetting `protobuf:"bytes,4,rep,name=settings,proto3" json:"settings,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + ConfigRevision uint64 `protobuf:"varint,5,opt,name=config_revision,json=configRevision,proto3" json:"config_revision,omitempty"` + PolicySource PolicySource `protobuf:"varint,6,opt,name=policy_source,json=policySource,proto3,enum=openshell.sandbox.v1.PolicySource" json:"policy_source,omitempty"` + GlobalPolicyVersion uint32 `protobuf:"varint,7,opt,name=global_policy_version,json=globalPolicyVersion,proto3" json:"global_policy_version,omitempty"` + ProviderEnvRevision uint64 `protobuf:"varint,8,opt,name=provider_env_revision,json=providerEnvRevision,proto3" json:"provider_env_revision,omitempty"` + SupervisorMiddlewareServices []*SupervisorMiddlewareService `protobuf:"bytes,9,rep,name=supervisor_middleware_services,json=supervisorMiddlewareServices,proto3" json:"supervisor_middleware_services,omitempty"` + Workspace string `protobuf:"bytes,10,opt,name=workspace,proto3" json:"workspace,omitempty"` + PolicyValidationFailureMode string `protobuf:"bytes,11,opt,name=policy_validation_failure_mode,json=policyValidationFailureMode,proto3" json:"policy_validation_failure_mode,omitempty"` + ExtensionAuthenticationEnabled bool `protobuf:"varint,12,opt,name=extension_authentication_enabled,json=extensionAuthenticationEnabled,proto3" json:"extension_authentication_enabled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxConfigSnapshot) Reset() { + *x = SandboxConfigSnapshot{} + mi := &file_sandbox_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxConfigSnapshot) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxConfigSnapshot) ProtoMessage() {} + +func (x *SandboxConfigSnapshot) ProtoReflect() protoreflect.Message { + mi := &file_sandbox_proto_msgTypes[21] + 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 SandboxConfigSnapshot.ProtoReflect.Descriptor instead. +func (*SandboxConfigSnapshot) Descriptor() ([]byte, []int) { + return file_sandbox_proto_rawDescGZIP(), []int{21} +} + +func (x *SandboxConfigSnapshot) GetPolicy() *SandboxPolicy { + if x != nil { + return x.Policy + } + return nil +} + +func (x *SandboxConfigSnapshot) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *SandboxConfigSnapshot) GetPolicyHash() string { + if x != nil { + return x.PolicyHash + } + return "" +} + +func (x *SandboxConfigSnapshot) GetSettings() map[string]*EffectiveSetting { + if x != nil { + return x.Settings + } + return nil +} + +func (x *SandboxConfigSnapshot) GetConfigRevision() uint64 { + if x != nil { + return x.ConfigRevision + } + return 0 +} + +func (x *SandboxConfigSnapshot) GetPolicySource() PolicySource { + if x != nil { + return x.PolicySource + } + return PolicySource_POLICY_SOURCE_UNSPECIFIED +} + +func (x *SandboxConfigSnapshot) GetGlobalPolicyVersion() uint32 { + if x != nil { + return x.GlobalPolicyVersion + } + return 0 +} + +func (x *SandboxConfigSnapshot) GetProviderEnvRevision() uint64 { + if x != nil { + return x.ProviderEnvRevision + } + return 0 +} + +func (x *SandboxConfigSnapshot) GetSupervisorMiddlewareServices() []*SupervisorMiddlewareService { + if x != nil { + return x.SupervisorMiddlewareServices + } + return nil +} + +func (x *SandboxConfigSnapshot) GetWorkspace() string { + if x != nil { + return x.Workspace + } + return "" +} + +func (x *SandboxConfigSnapshot) GetPolicyValidationFailureMode() string { + if x != nil { + return x.PolicyValidationFailureMode + } + return "" +} + +func (x *SandboxConfigSnapshot) GetExtensionAuthenticationEnabled() bool { + if x != nil { + return x.ExtensionAuthenticationEnabled + } + return false +} + // Response containing effective sandbox settings and policy. type GetSandboxConfigResponse struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1843,7 +1976,7 @@ type GetSandboxConfigResponse struct { func (x *GetSandboxConfigResponse) Reset() { *x = GetSandboxConfigResponse{} - mi := &file_sandbox_proto_msgTypes[21] + mi := &file_sandbox_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1855,7 +1988,7 @@ func (x *GetSandboxConfigResponse) String() string { func (*GetSandboxConfigResponse) ProtoMessage() {} func (x *GetSandboxConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[21] + mi := &file_sandbox_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1868,7 +2001,7 @@ func (x *GetSandboxConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxConfigResponse.ProtoReflect.Descriptor instead. func (*GetSandboxConfigResponse) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{21} + return file_sandbox_proto_rawDescGZIP(), []int{22} } func (x *GetSandboxConfigResponse) GetPolicy() *SandboxPolicy { @@ -1988,7 +2121,7 @@ type SupervisorMiddlewareService struct { func (x *SupervisorMiddlewareService) Reset() { *x = SupervisorMiddlewareService{} - mi := &file_sandbox_proto_msgTypes[22] + mi := &file_sandbox_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2000,7 +2133,7 @@ func (x *SupervisorMiddlewareService) String() string { func (*SupervisorMiddlewareService) ProtoMessage() {} func (x *SupervisorMiddlewareService) ProtoReflect() protoreflect.Message { - mi := &file_sandbox_proto_msgTypes[22] + mi := &file_sandbox_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2013,7 +2146,7 @@ func (x *SupervisorMiddlewareService) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMiddlewareService.ProtoReflect.Descriptor instead. func (*SupervisorMiddlewareService) Descriptor() ([]byte, []int) { - return file_sandbox_proto_rawDescGZIP(), []int{22} + return file_sandbox_proto_rawDescGZIP(), []int{23} } func (x *SupervisorMiddlewareService) GetName() string { @@ -2220,7 +2353,25 @@ const file_sandbox_proto_rawDesc = "" + "\x05value\"\x86\x01\n" + "\x10EffectiveSetting\x128\n" + "\x05value\x18\x01 \x01(\v2\".openshell.sandbox.v1.SettingValueR\x05value\x128\n" + - "\x05scope\x18\x02 \x01(\x0e2\".openshell.sandbox.v1.SettingScopeR\x05scope\"\xd1\x06\n" + + "\x05scope\x18\x02 \x01(\x0e2\".openshell.sandbox.v1.SettingScopeR\x05scope\"\xcb\x06\n" + + "\x15SandboxConfigSnapshot\x12;\n" + + "\x06policy\x18\x01 \x01(\v2#.openshell.sandbox.v1.SandboxPolicyR\x06policy\x12\x18\n" + + "\aversion\x18\x02 \x01(\rR\aversion\x12\x1f\n" + + "\vpolicy_hash\x18\x03 \x01(\tR\n" + + "policyHash\x12U\n" + + "\bsettings\x18\x04 \x03(\v29.openshell.sandbox.v1.SandboxConfigSnapshot.SettingsEntryR\bsettings\x12'\n" + + "\x0fconfig_revision\x18\x05 \x01(\x04R\x0econfigRevision\x12G\n" + + "\rpolicy_source\x18\x06 \x01(\x0e2\".openshell.sandbox.v1.PolicySourceR\fpolicySource\x122\n" + + "\x15global_policy_version\x18\a \x01(\rR\x13globalPolicyVersion\x122\n" + + "\x15provider_env_revision\x18\b \x01(\x04R\x13providerEnvRevision\x12w\n" + + "\x1esupervisor_middleware_services\x18\t \x03(\v21.openshell.sandbox.v1.SupervisorMiddlewareServiceR\x1csupervisorMiddlewareServices\x12\x1c\n" + + "\tworkspace\x18\n" + + " \x01(\tR\tworkspace\x12C\n" + + "\x1epolicy_validation_failure_mode\x18\v \x01(\tR\x1bpolicyValidationFailureMode\x12H\n" + + " extension_authentication_enabled\x18\f \x01(\bR\x1eextensionAuthenticationEnabled\x1ac\n" + + "\rSettingsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12<\n" + + "\x05value\x18\x02 \x01(\v2&.openshell.sandbox.v1.EffectiveSettingR\x05value:\x028\x01\"\xd1\x06\n" + "\x18GetSandboxConfigResponse\x12;\n" + "\x06policy\x18\x01 \x01(\v2#.openshell.sandbox.v1.SandboxPolicyR\x06policy\x12\x18\n" + "\aversion\x18\x02 \x01(\rR\aversion\x12\x1f\n" + @@ -2269,7 +2420,7 @@ func file_sandbox_proto_rawDescGZIP() []byte { } var file_sandbox_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 32) +var file_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 34) var file_sandbox_proto_goTypes = []any{ (SettingScope)(0), // 0: openshell.sandbox.v1.SettingScope (PolicySource)(0), // 1: openshell.sandbox.v1.PolicySource @@ -2294,60 +2445,67 @@ var file_sandbox_proto_goTypes = []any{ (*GetGatewayConfigResponse)(nil), // 20: openshell.sandbox.v1.GetGatewayConfigResponse (*SettingValue)(nil), // 21: openshell.sandbox.v1.SettingValue (*EffectiveSetting)(nil), // 22: openshell.sandbox.v1.EffectiveSetting - (*GetSandboxConfigResponse)(nil), // 23: openshell.sandbox.v1.GetSandboxConfigResponse - (*SupervisorMiddlewareService)(nil), // 24: openshell.sandbox.v1.SupervisorMiddlewareService - nil, // 25: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry - nil, // 26: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry - nil, // 27: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry - nil, // 28: openshell.sandbox.v1.L7DenyRule.QueryEntry - nil, // 29: openshell.sandbox.v1.L7DenyRule.ParamsEntry - nil, // 30: openshell.sandbox.v1.L7Allow.QueryEntry - nil, // 31: openshell.sandbox.v1.L7Allow.ParamsEntry - nil, // 32: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry - nil, // 33: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry - (*structpb.Struct)(nil), // 34: google.protobuf.Struct + (*SandboxConfigSnapshot)(nil), // 23: openshell.sandbox.v1.SandboxConfigSnapshot + (*GetSandboxConfigResponse)(nil), // 24: openshell.sandbox.v1.GetSandboxConfigResponse + (*SupervisorMiddlewareService)(nil), // 25: openshell.sandbox.v1.SupervisorMiddlewareService + nil, // 26: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry + nil, // 27: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry + nil, // 28: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry + nil, // 29: openshell.sandbox.v1.L7DenyRule.QueryEntry + nil, // 30: openshell.sandbox.v1.L7DenyRule.ParamsEntry + nil, // 31: openshell.sandbox.v1.L7Allow.QueryEntry + nil, // 32: openshell.sandbox.v1.L7Allow.ParamsEntry + nil, // 33: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry + nil, // 34: openshell.sandbox.v1.SandboxConfigSnapshot.SettingsEntry + nil, // 35: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry + (*structpb.Struct)(nil), // 36: google.protobuf.Struct } var file_sandbox_proto_depIdxs = []int32{ 3, // 0: openshell.sandbox.v1.SandboxPolicy.filesystem:type_name -> openshell.sandbox.v1.FilesystemPolicy 4, // 1: openshell.sandbox.v1.SandboxPolicy.landlock:type_name -> openshell.sandbox.v1.LandlockPolicy 5, // 2: openshell.sandbox.v1.SandboxPolicy.process:type_name -> openshell.sandbox.v1.ProcessPolicy - 25, // 3: openshell.sandbox.v1.SandboxPolicy.network_policies:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry - 26, // 4: openshell.sandbox.v1.SandboxPolicy.network_middlewares:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry + 26, // 3: openshell.sandbox.v1.SandboxPolicy.network_policies:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry + 27, // 4: openshell.sandbox.v1.SandboxPolicy.network_middlewares:type_name -> openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry 10, // 5: openshell.sandbox.v1.NetworkPolicyRule.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint 17, // 6: openshell.sandbox.v1.NetworkPolicyRule.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 34, // 7: openshell.sandbox.v1.NetworkMiddlewareConfig.config:type_name -> google.protobuf.Struct + 36, // 7: openshell.sandbox.v1.NetworkMiddlewareConfig.config:type_name -> google.protobuf.Struct 8, // 8: openshell.sandbox.v1.NetworkMiddlewareConfig.endpoints:type_name -> openshell.sandbox.v1.MiddlewareEndpointSelector 14, // 9: openshell.sandbox.v1.NetworkEndpoint.rules:type_name -> openshell.sandbox.v1.L7Rule 13, // 10: openshell.sandbox.v1.NetworkEndpoint.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 27, // 11: openshell.sandbox.v1.NetworkEndpoint.graphql_persisted_queries:type_name -> openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry + 28, // 11: openshell.sandbox.v1.NetworkEndpoint.graphql_persisted_queries:type_name -> openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry 11, // 12: openshell.sandbox.v1.NetworkEndpoint.mcp:type_name -> openshell.sandbox.v1.McpOptions 9, // 13: openshell.sandbox.v1.NetworkEndpoint.credential_binding:type_name -> openshell.sandbox.v1.NetworkCredentialBinding - 28, // 14: openshell.sandbox.v1.L7DenyRule.query:type_name -> openshell.sandbox.v1.L7DenyRule.QueryEntry - 29, // 15: openshell.sandbox.v1.L7DenyRule.params:type_name -> openshell.sandbox.v1.L7DenyRule.ParamsEntry + 29, // 14: openshell.sandbox.v1.L7DenyRule.query:type_name -> openshell.sandbox.v1.L7DenyRule.QueryEntry + 30, // 15: openshell.sandbox.v1.L7DenyRule.params:type_name -> openshell.sandbox.v1.L7DenyRule.ParamsEntry 15, // 16: openshell.sandbox.v1.L7Rule.allow:type_name -> openshell.sandbox.v1.L7Allow - 30, // 17: openshell.sandbox.v1.L7Allow.query:type_name -> openshell.sandbox.v1.L7Allow.QueryEntry - 31, // 18: openshell.sandbox.v1.L7Allow.params:type_name -> openshell.sandbox.v1.L7Allow.ParamsEntry - 32, // 19: openshell.sandbox.v1.GetGatewayConfigResponse.settings:type_name -> openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry + 31, // 17: openshell.sandbox.v1.L7Allow.query:type_name -> openshell.sandbox.v1.L7Allow.QueryEntry + 32, // 18: openshell.sandbox.v1.L7Allow.params:type_name -> openshell.sandbox.v1.L7Allow.ParamsEntry + 33, // 19: openshell.sandbox.v1.GetGatewayConfigResponse.settings:type_name -> openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry 21, // 20: openshell.sandbox.v1.EffectiveSetting.value:type_name -> openshell.sandbox.v1.SettingValue 0, // 21: openshell.sandbox.v1.EffectiveSetting.scope:type_name -> openshell.sandbox.v1.SettingScope - 2, // 22: openshell.sandbox.v1.GetSandboxConfigResponse.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 33, // 23: openshell.sandbox.v1.GetSandboxConfigResponse.settings:type_name -> openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry - 1, // 24: openshell.sandbox.v1.GetSandboxConfigResponse.policy_source:type_name -> openshell.sandbox.v1.PolicySource - 24, // 25: openshell.sandbox.v1.GetSandboxConfigResponse.supervisor_middleware_services:type_name -> openshell.sandbox.v1.SupervisorMiddlewareService - 6, // 26: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry.value:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 7, // 27: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry.value:type_name -> openshell.sandbox.v1.NetworkMiddlewareConfig - 12, // 28: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry.value:type_name -> openshell.sandbox.v1.GraphqlOperation - 16, // 29: openshell.sandbox.v1.L7DenyRule.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 16, // 30: openshell.sandbox.v1.L7DenyRule.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 16, // 31: openshell.sandbox.v1.L7Allow.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 16, // 32: openshell.sandbox.v1.L7Allow.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher - 21, // 33: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.SettingValue - 22, // 34: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.EffectiveSetting - 35, // [35:35] is the sub-list for method output_type - 35, // [35:35] is the sub-list for method input_type - 35, // [35:35] is the sub-list for extension type_name - 35, // [35:35] is the sub-list for extension extendee - 0, // [0:35] is the sub-list for field type_name + 2, // 22: openshell.sandbox.v1.SandboxConfigSnapshot.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 34, // 23: openshell.sandbox.v1.SandboxConfigSnapshot.settings:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot.SettingsEntry + 1, // 24: openshell.sandbox.v1.SandboxConfigSnapshot.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 25, // 25: openshell.sandbox.v1.SandboxConfigSnapshot.supervisor_middleware_services:type_name -> openshell.sandbox.v1.SupervisorMiddlewareService + 2, // 26: openshell.sandbox.v1.GetSandboxConfigResponse.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 35, // 27: openshell.sandbox.v1.GetSandboxConfigResponse.settings:type_name -> openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry + 1, // 28: openshell.sandbox.v1.GetSandboxConfigResponse.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 25, // 29: openshell.sandbox.v1.GetSandboxConfigResponse.supervisor_middleware_services:type_name -> openshell.sandbox.v1.SupervisorMiddlewareService + 6, // 30: openshell.sandbox.v1.SandboxPolicy.NetworkPoliciesEntry.value:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 7, // 31: openshell.sandbox.v1.SandboxPolicy.NetworkMiddlewaresEntry.value:type_name -> openshell.sandbox.v1.NetworkMiddlewareConfig + 12, // 32: openshell.sandbox.v1.NetworkEndpoint.GraphqlPersistedQueriesEntry.value:type_name -> openshell.sandbox.v1.GraphqlOperation + 16, // 33: openshell.sandbox.v1.L7DenyRule.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 16, // 34: openshell.sandbox.v1.L7DenyRule.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 16, // 35: openshell.sandbox.v1.L7Allow.QueryEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 16, // 36: openshell.sandbox.v1.L7Allow.ParamsEntry.value:type_name -> openshell.sandbox.v1.L7QueryMatcher + 21, // 37: openshell.sandbox.v1.GetGatewayConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.SettingValue + 22, // 38: openshell.sandbox.v1.SandboxConfigSnapshot.SettingsEntry.value:type_name -> openshell.sandbox.v1.EffectiveSetting + 22, // 39: openshell.sandbox.v1.GetSandboxConfigResponse.SettingsEntry.value:type_name -> openshell.sandbox.v1.EffectiveSetting + 40, // [40:40] is the sub-list for method output_type + 40, // [40:40] is the sub-list for method input_type + 40, // [40:40] is the sub-list for extension type_name + 40, // [40:40] is the sub-list for extension extendee + 0, // [0:40] is the sub-list for field type_name } func init() { file_sandbox_proto_init() } @@ -2368,7 +2526,7 @@ func file_sandbox_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_sandbox_proto_rawDesc), len(file_sandbox_proto_rawDesc)), NumEnums: 2, - NumMessages: 32, + NumMessages: 34, NumExtensions: 0, NumServices: 0, }, diff --git a/sdk/typescript/src/raw.ts b/sdk/typescript/src/raw.ts index b0be2cd9bf..42b9530643 100644 --- a/sdk/typescript/src/raw.ts +++ b/sdk/typescript/src/raw.ts @@ -7,7 +7,7 @@ export * from './gen/datamodel_pb.js'; // 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 -// shift when the proto regenerates. The four generated modules export disjoint +// shift when the proto regenerates. The generated modules export disjoint // symbol names, so a flat re-export is unambiguous. export * from './gen/openshell_pb.js'; export * from './gen/options_pb.js'; diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index 5b460ce7f6..4f730587cc 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -16,6 +16,8 @@ The target deployment flow is: 1. Operator starts or deploys the gateway with system packages, systemd, or Helm. The CLI does not start, stop, or destroy gateway services. 2. Operator configures the compute driver. 3. Operator provides the CLI and supervisor authentication material required by the deployment mode: edge or OIDC user auth, optional CLI mTLS, and gateway-minted sandbox JWTs. + +If supervisor sessions fail with a protocol revision mismatch, check that custom supervisor images match the gateway release. Gateway and supervisor require the same internal protocol revision; authentication success does not make mismatched versions compatible. See the published [gateway configuration reference](https://docs.nvidia.com/openshell/latest/reference/gateway-config). 4. The CLI registers a reachable gateway endpoint with `openshell gateway add`. 5. The gateway creates sandboxes through the selected compute driver. From d0d8d02b40dbb67c6a494d80c085add1c4e3f463 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Wed, 9 Sep 2026 14:27:20 -0700 Subject: [PATCH 02/15] fix(server): skip invalid stored policies during policy history repair The startup repair that creates version-one policy history for legacy sandboxes propagated validation failures, so a single stored policy that no longer passes current validation rules prevented the gateway from starting. Skip such sandboxes with a warning and a completion summary so they keep the pre-repair behavior where only their own configuration reads report the failure. Store errors remain fatal. Signed-off-by: Piotr Mlocek --- crates/openshell-server/src/grpc/policy.rs | 125 ++++++++++++++++++--- 1 file changed, 110 insertions(+), 15 deletions(-) diff --git a/crates/openshell-server/src/grpc/policy.rs b/crates/openshell-server/src/grpc/policy.rs index 8df376d971..0d99a0b876 100644 --- a/crates/openshell-server/src/grpc/policy.rs +++ b/crates/openshell-server/src/grpc/policy.rs @@ -85,7 +85,7 @@ use sha2::{Digest, Sha256}; use std::collections::{BTreeMap, HashMap, HashSet}; use std::net::{IpAddr, Ipv4Addr}; use std::sync::Arc; -use tonic::{Request, Response, Status}; +use tonic::{Code, Request, Response, Status}; use tracing::{debug, info, warn}; use super::validation::{ @@ -2351,7 +2351,7 @@ async fn resolve_sandbox_by_name_for_principal( }; crate::auth::guard::ensure_sandbox_scope(principal, sandbox.object_id()).map_err( |status| { - if status.code() == tonic::Code::PermissionDenied { + if status.code() == Code::PermissionDenied { Status::permission_denied("sandbox not found or not owned by caller") } else { status @@ -2621,13 +2621,16 @@ impl InitialPolicyHistoryStatus { /// Insert the version-one policy baseline if this sandbox still has no policy /// history. This never modifies an existing revision or apply result. +/// +/// Returns `true` when a baseline was written. Stored policies that fail the +/// current validation rules are rejected with `FailedPrecondition`. pub async fn initialize_policy_history( store: &Store, sandbox: &Sandbox, status: InitialPolicyHistoryStatus, -) -> Result<(), Status> { +) -> Result { let Some(policy) = sandbox.spec.as_ref().and_then(|spec| spec.policy.as_ref()) else { - return Ok(()); + return Ok(false); }; if store .get_latest_policy(sandbox.object_id()) @@ -2635,7 +2638,7 @@ pub async fn initialize_policy_history( .map_err(|error| Status::internal(format!("read policy history failed: {error}")))? .is_some() { - return Ok(()); + return Ok(false); } let policy = validate_and_canonicalize_stored_policy(policy.clone(), STORED_POLICY_SOURCE_SPEC)?; @@ -2656,15 +2659,22 @@ pub async fn initialize_policy_history( sandbox.object_workspace(), ) .await - .map_err(|error| Status::internal(format!("initialize policy history failed: {error}"))) + .map_err(|error| Status::internal(format!("initialize policy history failed: {error}")))?; + Ok(true) } /// Create policy-history baselines for sandboxes written by older gateways. /// -/// Snapshot reads stay pure once this startup repair has completed. +/// Snapshot reads stay pure once this startup repair has completed. A stored +/// policy that no longer passes validation is skipped rather than blocking +/// gateway startup; that sandbox keeps the pre-repair behavior where its own +/// configuration reads report the validation failure. Store errors remain +/// fatal. pub async fn backfill_legacy_policy_history(state: &Arc) -> Result<(), Status> { const PAGE_SIZE: u32 = 1000; let mut offset = 0; + let mut repaired = 0_usize; + let mut skipped = 0_usize; loop { let sandboxes = state .store @@ -2673,23 +2683,38 @@ pub async fn backfill_legacy_policy_history(state: &Arc) -> Result< .map_err(|error| { Status::internal(format!("list sandboxes for policy repair failed: {error}")) })?; - if sandboxes.is_empty() { - return Ok(()); - } let count = u32::try_from(sandboxes.len()).unwrap_or(PAGE_SIZE); for sandbox in sandboxes { - initialize_policy_history( + match initialize_policy_history( state.store.as_ref(), &sandbox, InitialPolicyHistoryStatus::Loaded, ) - .await?; + .await + { + Ok(true) => repaired += 1, + Ok(false) => {} + Err(status) if status.code() == Code::FailedPrecondition => { + skipped += 1; + warn!( + sandbox_id = %sandbox.object_id(), + workspace = %sandbox.object_workspace(), + error = %status.message(), + "skipping policy history repair for invalid stored policy" + ); + } + Err(status) => return Err(status), + } } if count < PAGE_SIZE { - return Ok(()); + break; } offset = offset.saturating_add(count); } + if repaired > 0 || skipped > 0 { + info!(repaired, skipped, "legacy policy history repair complete"); + } + Ok(()) } #[cfg(test)] @@ -5383,7 +5408,7 @@ async fn handle_approve_all_draft_chunks_inner( .await { Ok(evaluation) => evaluation, - Err(status) if status.code() == tonic::Code::FailedPrecondition => { + Err(status) if status.code() == Code::FailedPrecondition => { info!( sandbox_id = %sandbox_id, chunk_id = %chunk.id, @@ -7362,7 +7387,6 @@ mod tests { use std::collections::HashMap; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; - use tonic::Code; /// Wrap a request with a user `Principal` so handler scope guards treat /// the test caller as a CLI user. Most handler tests exercise @@ -11279,6 +11303,77 @@ mod tests { ); } + #[tokio::test] + async fn legacy_policy_history_repair_skips_invalid_stored_policy() { + use openshell_core::proto::LandlockPolicy; + + let state = test_server_state().await; + let valid_policy = test_policy_with_rule("valid", "valid.example.com"); + state + .store + .put_message(&test_sandbox( + "sb-valid-legacy", + "valid-legacy", + valid_policy.clone(), + Vec::new(), + )) + .await + .unwrap(); + let mut invalid_policy = test_policy_with_rule("invalid", "invalid.example.com"); + invalid_policy.landlock = Some(LandlockPolicy { + compatibility: "best-effort".to_string(), + }); + state + .store + .put_message(&test_sandbox( + "sb-invalid-legacy", + "invalid-legacy", + invalid_policy, + Vec::new(), + )) + .await + .unwrap(); + + backfill_legacy_policy_history(&state) + .await + .expect("one invalid stored policy must not block startup repair"); + + let repaired = state + .store + .get_latest_policy("sb-valid-legacy") + .await + .unwrap() + .expect("valid legacy sandbox gets a baseline"); + assert_eq!(repaired.version, 1); + assert_eq!(repaired.status, "loaded"); + assert_eq!( + repaired.policy_hash, + deterministic_policy_hash(&valid_policy) + ); + assert!( + state + .store + .get_latest_policy("sb-invalid-legacy") + .await + .unwrap() + .is_none(), + "invalid stored policy must not be persisted as history" + ); + + let error = handle_get_sandbox_config( + &state, + with_sandbox( + Request::new(GetSandboxConfigRequest { + sandbox_id: "sb-invalid-legacy".to_string(), + }), + "sb-invalid-legacy", + ), + ) + .await + .expect_err("invalid stored policy still fails only its own config read"); + assert_eq!(error.code(), Code::FailedPrecondition); + } + #[tokio::test] async fn legacy_policy_history_repair_is_idempotent() { let state = test_server_state().await; From fc3a92d5b7265c4515ae73bd0b233dbb4c12b1a5 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Wed, 9 Sep 2026 16:28:53 -0700 Subject: [PATCH 03/15] fix(server): bound concurrent supervisor snapshot builds Fleet-wide configuration changes spawned one snapshot build per connected sandbox and component with no concurrency limit, so a global setting or provider change issued every store query and credential-driver call at once. Gate builds behind a semaphore sized from the database pool and start the build deadline only once a permit is held. Signed-off-by: Piotr Mlocek --- architecture/sandbox.md | 15 +- crates/openshell-server/Cargo.toml | 1 + .../openshell-server/src/config_delivery.rs | 166 ++++++++++++++++-- crates/openshell-server/src/lib.rs | 4 +- .../openshell-server/src/persistence/mod.rs | 8 + .../src/persistence/postgres.rs | 4 + .../src/persistence/sqlite.rs | 4 + 7 files changed, 184 insertions(+), 18 deletions(-) diff --git a/architecture/sandbox.md b/architecture/sandbox.md index 588bfa7a56..56b7d635dc 100644 --- a/architecture/sandbox.md +++ b/architecture/sandbox.md @@ -504,12 +504,15 @@ Polling remains the only path that changes runtime state and repairs dropped or unavailable delivery. The gateway serializes construction per sandbox and component, and coalesces repeated mutations into the latest full snapshot. An enqueue result means only that the local stream queue accepted the message. A -bounded scope fanout scheduler coalesces repeated workspace and global changes. -Snapshot construction has a deadline, and the gateway rejects encoded stream -messages that approach the transport decoder limit. A -later migration will apply these payloads directly and acknowledge their exact -revisions before removing supervisor polling. At that point, the gateway will -require a valid bootstrap before marking a session ready. +bounded scope fanout scheduler coalesces repeated workspace and global changes, +and a semaphore sized from the database pool bounds how many snapshots build +at once so a fleet-wide change cannot saturate the store or credential +backends. Snapshot construction has a deadline that starts once a build holds a +permit, and the gateway rejects encoded stream messages that approach the +transport decoder limit. A later migration will apply these payloads directly +and acknowledge their exact revisions before removing supervisor polling. At +that point, the gateway will require a valid bootstrap before marking a session +ready. ## Policy Revision Acknowledgement diff --git a/crates/openshell-server/Cargo.toml b/crates/openshell-server/Cargo.toml index f712665d2a..d92a411835 100644 --- a/crates/openshell-server/Cargo.toml +++ b/crates/openshell-server/Cargo.toml @@ -127,6 +127,7 @@ protoc-bin-vendored = { workspace = true } [dev-dependencies] base64 = { workspace = true } +tokio = { workspace = true, features = ["test-util"] } hyper-rustls = { version = "0.27", default-features = false, features = ["native-tokio", "http1", "tls12", "logging", "aws-lc-rs"] } rcgen = { workspace = true } rsa = { version = "0.9", features = ["pem"] } diff --git a/crates/openshell-server/src/config_delivery.rs b/crates/openshell-server/src/config_delivery.rs index 99470ef7bc..e70bd4d8b8 100644 --- a/crates/openshell-server/src/config_delivery.rs +++ b/crates/openshell-server/src/config_delivery.rs @@ -13,6 +13,7 @@ use metrics::counter; use openshell_core::proto::{ ConfigBootstrap, ProviderEnvironmentSnapshot, Sandbox, SandboxConfigSnapshot, }; +use tokio::sync::Semaphore; use tonic::{Code, Status}; use tracing::warn; @@ -26,6 +27,11 @@ use crate::supervisor_session::SupervisorSessionRegistry; pub const MAX_SUPERVISOR_CONFIG_MESSAGE_BYTES: usize = 3 * 1024 * 1024; const CONFIG_SNAPSHOT_BUILD_TIMEOUT: Duration = Duration::from_secs(45); const MAX_ACTIVE_FANOUT_WORKERS: usize = 64; +/// Concurrent snapshot builds allowed per pooled database connection. Builds +/// are short bursts of small queries, so a little oversubscription keeps the +/// pool busy without stacking every waiter on the acquire timeout. +const SNAPSHOT_BUILDS_PER_DB_CONNECTION: usize = 2; +const MIN_CONCURRENT_SNAPSHOT_BUILDS: usize = 4; /// One complete configuration component awaiting delivery to a supervisor. #[derive(Clone)] @@ -181,13 +187,65 @@ struct FanoutKey { /// The map entry is also the worker lease. Its boolean is set when another /// mutation arrives during a build or route operation. The worker then rebuilds /// the current full snapshot once, regardless of how many mutations arrived. -#[derive(Debug, Default)] +/// +/// Workers are spawned eagerly so coalescing stays exact, but snapshot +/// construction itself is bounded by `build_permits`. A fleet-wide change +/// therefore queues on the semaphore instead of saturating the database pool +/// and credential backends all at once. +#[derive(Debug)] pub struct ConfigDeliveryQueue { pending: Mutex>, fanout_pending: Mutex>, + build_permits: Semaphore, +} + +impl Default for ConfigDeliveryQueue { + fn default() -> Self { + Self::new(MIN_CONCURRENT_SNAPSHOT_BUILDS) + } } impl ConfigDeliveryQueue { + #[must_use] + pub fn new(max_concurrent_builds: usize) -> Self { + Self { + pending: Mutex::default(), + fanout_pending: Mutex::default(), + build_permits: Semaphore::new(max_concurrent_builds.max(1)), + } + } + + /// Size the build bound from the persistence pool that every build reads. + #[must_use] + pub fn for_db_connections(max_connections: u32) -> Self { + let max_connections = usize::try_from(max_connections).unwrap_or(usize::MAX); + Self::new( + max_connections + .saturating_mul(SNAPSHOT_BUILDS_PER_DB_CONNECTION) + .max(MIN_CONCURRENT_SNAPSHOT_BUILDS), + ) + } + + #[cfg(test)] + fn max_concurrent_builds(&self) -> usize { + self.build_permits.available_permits() + } + + /// Run one snapshot build under the concurrency bound. The deadline starts + /// only once a permit is held so queued builds do not spend their budget + /// waiting. + async fn run_bounded_build( + &self, + build: impl Future, + ) -> Result { + let _permit = self + .build_permits + .acquire() + .await + .expect("snapshot build semaphore is never closed"); + tokio::time::timeout(CONFIG_SNAPSHOT_BUILD_TIMEOUT, build).await + } + fn enqueue(&self, key: DeliveryKey) -> bool { let mut pending = self.pending.lock().unwrap(); match pending.entry(key) { @@ -337,16 +395,16 @@ fn enqueue_sandbox(state: &Arc, sandbox_id: &str, components: Confi } async fn publish_sandbox_component_now(state: &Arc, key: &DeliveryKey) { - let sandbox = match state.store.get_message::(&key.sandbox_id).await { - Ok(Some(sandbox)) => sandbox, - Ok(None) => return, - Err(_) => { - record_build_failure(&key.sandbox_id, "sandbox", Code::Internal); - return; - } - }; let component = key.component.name(); let build = async { + let sandbox = state + .store + .get_message::(&key.sandbox_id) + .await + .map_err(|error| Status::internal(format!("fetch sandbox failed: {error}")))?; + let Some(sandbox) = sandbox else { + return Ok(None); + }; match key.component { ConfigComponentKind::SandboxConfig => build_sandbox_config_snapshot(state, &sandbox) .await @@ -357,9 +415,11 @@ async fn publish_sandbox_component_now(state: &Arc, key: &DeliveryK .map(SupervisorConfigMessage::ProviderEnvironment) } } + .map(Some) }; - match tokio::time::timeout(CONFIG_SNAPSHOT_BUILD_TIMEOUT, build).await { - Ok(Ok(message)) => { + match state.config_delivery_queue.run_bounded_build(build).await { + Ok(Ok(None)) => {} + Ok(Ok(Some(message))) => { let disposition = state .supervisor_config_router() .deliver(&key.sandbox_id, message) @@ -478,6 +538,8 @@ fn record_build_failure(sandbox_id: &str, component: &'static str, error_code: C #[cfg(test)] mod tests { + use std::sync::atomic::{AtomicUsize, Ordering}; + use super::*; use crate::grpc::{OpenShellService, test_support::test_server_state}; use openshell_core::proto::{ @@ -508,6 +570,88 @@ mod tests { assert!(!queue.finish_pass(&key)); } + #[test] + fn build_bound_is_sized_from_the_database_pool() { + assert_eq!( + ConfigDeliveryQueue::for_db_connections(10).max_concurrent_builds(), + 20 + ); + assert_eq!( + ConfigDeliveryQueue::for_db_connections(1).max_concurrent_builds(), + MIN_CONCURRENT_SNAPSHOT_BUILDS + ); + assert_eq!(ConfigDeliveryQueue::new(0).max_concurrent_builds(), 1); + } + + #[tokio::test(start_paused = true)] + async fn bounded_builds_never_exceed_the_permit_count() { + const PERMITS: usize = 4; + const BUILDS: usize = 40; + let queue = Arc::new(ConfigDeliveryQueue::new(PERMITS)); + let active = Arc::new(AtomicUsize::new(0)); + let peak = Arc::new(AtomicUsize::new(0)); + + let workers = (0..BUILDS) + .map(|_| { + let queue = Arc::clone(&queue); + let active = Arc::clone(&active); + let peak = Arc::clone(&peak); + tokio::spawn(async move { + queue + .run_bounded_build(async { + let now = active.fetch_add(1, Ordering::SeqCst) + 1; + peak.fetch_max(now, Ordering::SeqCst); + tokio::time::sleep(Duration::from_millis(50)).await; + active.fetch_sub(1, Ordering::SeqCst); + }) + .await + .expect("build must not time out"); + }) + }) + .collect::>(); + for worker in workers { + worker.await.unwrap(); + } + + assert_eq!(peak.load(Ordering::SeqCst), PERMITS); + assert_eq!(active.load(Ordering::SeqCst), 0); + assert_eq!(queue.max_concurrent_builds(), PERMITS); + } + + #[tokio::test(start_paused = true)] + async fn build_deadline_starts_after_a_permit_is_held() { + let queue = Arc::new(ConfigDeliveryQueue::new(1)); + let almost_deadline = CONFIG_SNAPSHOT_BUILD_TIMEOUT + .checked_sub(Duration::from_secs(1)) + .unwrap(); + let first = { + let queue = Arc::clone(&queue); + tokio::spawn(async move { + queue + .run_bounded_build(tokio::time::sleep(almost_deadline)) + .await + }) + }; + tokio::task::yield_now().await; + let second = queue.run_bounded_build(tokio::time::sleep(almost_deadline)); + + let (first, second) = tokio::join!(first, second); + assert!(first.unwrap().is_ok()); + assert!( + second.is_ok(), + "waiting for a permit must not consume the build deadline" + ); + + assert!( + queue + .run_bounded_build(tokio::time::sleep( + CONFIG_SNAPSHOT_BUILD_TIMEOUT + Duration::from_secs(1), + )) + .await + .is_err() + ); + } + #[test] fn queue_runs_components_and_sandboxes_independently() { let queue = ConfigDeliveryQueue::default(); diff --git a/crates/openshell-server/src/lib.rs b/crates/openshell-server/src/lib.rs index dee5260eb6..8c0870d26a 100644 --- a/crates/openshell-server/src/lib.rs +++ b/crates/openshell-server/src/lib.rs @@ -419,6 +419,8 @@ impl ServerState { let supervisor_config_router: Arc = Arc::new( config_delivery::LocalSupervisorConfigRouter::new(Arc::clone(&supervisor_sessions)), ); + let config_delivery_queue = + config_delivery::ConfigDeliveryQueue::for_db_connections(store.max_connections()); Self { config, store, @@ -433,7 +435,7 @@ impl ServerState { settings_mutex: tokio::sync::Mutex::new(()), supervisor_sessions, gateway_shutting_down: AtomicBool::new(false), - config_delivery_queue: config_delivery::ConfigDeliveryQueue::default(), + config_delivery_queue, supervisor_config_router, extension_mint_limiter: auth::extension_mint_limit::ExtensionMintLimiter::default(), middleware_registry: Arc::new(MiddlewareRegistry::default()), diff --git a/crates/openshell-server/src/persistence/mod.rs b/crates/openshell-server/src/persistence/mod.rs index e22f5f99b9..ac55c4db8e 100644 --- a/crates/openshell-server/src/persistence/mod.rs +++ b/crates/openshell-server/src/persistence/mod.rs @@ -271,6 +271,14 @@ impl Store { matches!(self, Self::Sqlite(_)) } + /// Maximum number of pooled database connections for this backend. + pub fn max_connections(&self) -> u32 { + match self { + Self::Postgres(store) => store.max_connections(), + Self::Sqlite(store) => store.max_connections(), + } + } + /// Connect to a persistence store based on the database URL. pub async fn connect(url: &str) -> CoreResult { if url.starts_with("postgres://") || url.starts_with("postgresql://") { diff --git a/crates/openshell-server/src/persistence/postgres.rs b/crates/openshell-server/src/persistence/postgres.rs index 2402a8e2df..655c1565fb 100644 --- a/crates/openshell-server/src/persistence/postgres.rs +++ b/crates/openshell-server/src/persistence/postgres.rs @@ -45,6 +45,10 @@ impl PostgresStore { Ok(Self { pool }) } + pub fn max_connections(&self) -> u32 { + self.pool.options().get_max_connections() + } + pub async fn migrate(&self) -> PersistenceResult<()> { POSTGRES_MIGRATOR .run(&self.pool) diff --git a/crates/openshell-server/src/persistence/sqlite.rs b/crates/openshell-server/src/persistence/sqlite.rs index d8feafc60e..fe506f3c1f 100644 --- a/crates/openshell-server/src/persistence/sqlite.rs +++ b/crates/openshell-server/src/persistence/sqlite.rs @@ -77,6 +77,10 @@ impl SqliteStore { self.close().await; } + pub fn max_connections(&self) -> u32 { + self.pool.options().get_max_connections() + } + pub async fn connect(url: &str) -> PersistenceResult { let is_in_memory = url.contains(":memory:") || url.contains("mode=memory"); let max_connections = if is_in_memory { 1 } else { 5 }; From 2c95079cba71ae3040ed7d1ec79f397d5fc6727d Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Wed, 9 Sep 2026 14:11:00 -0700 Subject: [PATCH 04/15] fix(supervisor): accept legacy supervisors without a protocol revision Sandboxes keep their supervisor binary until they are recreated, so a gateway upgrade meets supervisors that predate the handshake and report revision zero. Rejecting them severs every running sandbox with no automatic recovery. Accept revision zero for one release, log a warning per session, and count them in openshell_supervisor_protocol_legacy_sessions_total. The supervisor mirrors the allowance for gateways that predate the handshake. Add a shared ConnectSupervisor test harness and handler-level tests for legacy acceptance and unknown-revision rejection. Move the skill troubleshooting paragraph out of the numbered deployment list so the list renders. Signed-off-by: Piotr Mlocek --- architecture/sandbox.md | 4 +- crates/openshell-core/src/proto/mod.rs | 8 ++ .../openshell-server/src/config_delivery.rs | 47 ++------- crates/openshell-server/src/grpc/mod.rs | 66 +++++++++++++ .../src/supervisor_session.rs | 99 ++++++++++++++++--- .../src/supervisor_session.rs | 26 +++-- docs/reference/gateway-config.mdx | 2 + proto/openshell.proto | 1 + skills/debug-openshell-cluster/SKILL.md | 4 +- 9 files changed, 196 insertions(+), 61 deletions(-) diff --git a/architecture/sandbox.md b/architecture/sandbox.md index 56b7d635dc..daba7bbacd 100644 --- a/architecture/sandbox.md +++ b/architecture/sandbox.md @@ -476,7 +476,9 @@ quickly. ## Supervisor Configuration Delivery The gateway and supervisor must implement the same internal supervisor protocol -revision. The gateway includes a configuration bootstrap when it accepts a +revision. Peers built before the handshake existed report revision zero and are +accepted for one release with a warning and a counter, because sandboxes keep +their supervisor binary until they are recreated. The gateway includes a configuration bootstrap when it accepts a `ConnectSupervisor` session and can send complete component replacements on the same stream after policy, settings, or provider state changes. Bootstrap construction does not gate the session while polling remains diff --git a/crates/openshell-core/src/proto/mod.rs b/crates/openshell-core/src/proto/mod.rs index d80325e65e..2ab1e155d1 100644 --- a/crates/openshell-core/src/proto/mod.rs +++ b/crates/openshell-core/src/proto/mod.rs @@ -101,3 +101,11 @@ pub fn all_workspaces_selector() -> WorkspaceSelector { /// Bump this when either peer can no longer honor the previous stream /// semantics. pub const SUPERVISOR_PROTOCOL_REVISION: u32 = 1; + +/// Revision implied by peers built before the handshake existed. Proto3 leaves +/// the field unset, so such peers report zero. +/// +/// Sandboxes keep their supervisor binary until they are recreated, so a +/// gateway upgrade must keep serving them for one release. Remove this +/// allowance once every supported release sends an explicit revision. +pub const LEGACY_SUPERVISOR_PROTOCOL_REVISION: u32 = 0; diff --git a/crates/openshell-server/src/config_delivery.rs b/crates/openshell-server/src/config_delivery.rs index e70bd4d8b8..b9c7495277 100644 --- a/crates/openshell-server/src/config_delivery.rs +++ b/crates/openshell-server/src/config_delivery.rs @@ -541,14 +541,8 @@ mod tests { use std::sync::atomic::{AtomicUsize, Ordering}; use super::*; - use crate::grpc::{OpenShellService, test_support::test_server_state}; - use openshell_core::proto::{ - GatewayMessage, ObjectMeta, SandboxSpec, SupervisorHello, SupervisorMessage, - gateway_message, open_shell_client::OpenShellClient, open_shell_server::OpenShellServer, - supervisor_message, - }; - use tokio::sync::mpsc; - use tokio_stream::wrappers::{ReceiverStream, TcpListenerStream}; + use crate::grpc::test_support::{connect_supervisor_stream, test_server_state}; + use openshell_core::proto::{GatewayMessage, ObjectMeta, SandboxSpec, gateway_message}; fn key(sandbox_id: &str, component: ConfigComponentKind) -> DeliveryKey { DeliveryKey { @@ -727,35 +721,15 @@ mod tests { .await .unwrap(); - let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); - let address = listener.local_addr().unwrap(); - let server = tokio::spawn( - tonic::transport::Server::builder() - .add_service(OpenShellServer::new(OpenShellService::new(Arc::clone( - &state, - )))) - .serve_with_incoming(TcpListenerStream::new(listener)), - ); - let mut client = OpenShellClient::connect(format!("http://{address}")) - .await - .unwrap(); - let (tx, rx) = mpsc::channel(4); - tx.send(SupervisorMessage { - payload: Some(supervisor_message::Payload::Hello(SupervisorHello { - sandbox_id: "sandbox".into(), - instance_id: "instance".into(), - protocol_revision: openshell_core::proto::SUPERVISOR_PROTOCOL_REVISION, - })), - }) + let mut harness = connect_supervisor_stream( + &state, + "sandbox", + openshell_core::proto::SUPERVISOR_PROTOCOL_REVISION, + ) .await .unwrap(); - let mut stream = client - .connect_supervisor(ReceiverStream::new(rx)) - .await - .unwrap() - .into_inner(); - let first = tokio::time::timeout(Duration::from_secs(5), stream.message()) + let first = tokio::time::timeout(Duration::from_secs(5), harness.inbound.message()) .await .unwrap() .unwrap() @@ -766,7 +740,7 @@ mod tests { )); publish_sandbox_components(&state, "sandbox", ConfigComponents::SANDBOX_CONFIG); - let update = tokio::time::timeout(Duration::from_secs(5), stream.message()) + let update = tokio::time::timeout(Duration::from_secs(5), harness.inbound.message()) .await .unwrap() .unwrap() @@ -777,9 +751,6 @@ mod tests { payload: Some(gateway_message::Payload::ConfigUpdate(_)) } )); - - drop(tx); - server.abort(); } #[test] diff --git a/crates/openshell-server/src/grpc/mod.rs b/crates/openshell-server/src/grpc/mod.rs index 95bd6eaa3b..15bbcd13b0 100644 --- a/crates/openshell-server/src/grpc/mod.rs +++ b/crates/openshell-server/src/grpc/mod.rs @@ -818,8 +818,74 @@ pub mod test_support { use crate::supervisor_session::SupervisorSessionRegistry; use crate::tracing_bus::TracingLogBus; use openshell_core::Config; + use openshell_core::proto::open_shell_client::OpenShellClient; + use openshell_core::proto::open_shell_server::OpenShellServer; + use openshell_core::proto::{ + GatewayMessage, SupervisorHello, SupervisorMessage, supervisor_message, + }; + use tokio::sync::mpsc; + use tokio_stream::wrappers::{ReceiverStream, TcpListenerStream}; use tonic::Request; + /// A live `ConnectSupervisor` stream against an in-process gateway. + pub struct SupervisorStreamHarness { + server: tokio::task::JoinHandle>, + /// Held so the supervisor side of the stream stays open. + _outbound: mpsc::Sender, + pub inbound: tonic::Streaming, + } + + impl Drop for SupervisorStreamHarness { + fn drop(&mut self) { + self.server.abort(); + } + } + + /// Serve `state` on loopback and open a supervisor stream whose hello + /// carries the given protocol revision. Returns the gRPC status when the + /// gateway rejects the stream before accepting it. + pub async fn connect_supervisor_stream( + state: &Arc, + sandbox_id: &str, + protocol_revision: u32, + ) -> Result { + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let address = listener.local_addr().unwrap(); + let server = tokio::spawn( + tonic::transport::Server::builder() + .add_service(OpenShellServer::new(super::OpenShellService::new( + Arc::clone(state), + ))) + .serve_with_incoming(TcpListenerStream::new(listener)), + ); + let mut client = OpenShellClient::connect(format!("http://{address}")) + .await + .unwrap(); + let (outbound, rx) = mpsc::channel(4); + outbound + .send(SupervisorMessage { + payload: Some(supervisor_message::Payload::Hello(SupervisorHello { + sandbox_id: sandbox_id.into(), + instance_id: "instance".into(), + protocol_revision, + })), + }) + .await + .unwrap(); + let inbound = match client.connect_supervisor(ReceiverStream::new(rx)).await { + Ok(response) => response.into_inner(), + Err(status) => { + server.abort(); + return Err(status); + } + }; + Ok(SupervisorStreamHarness { + server, + _outbound: outbound, + inbound, + }) + } + /// Wrap a proto message in a `Request` with a dev principal injected. /// /// The dev principal matches the unauthenticated dev user: subject diff --git a/crates/openshell-server/src/supervisor_session.rs b/crates/openshell-server/src/supervisor_session.rs index c5668cc41e..5cb66ac16f 100644 --- a/crates/openshell-server/src/supervisor_session.rs +++ b/crates/openshell-server/src/supervisor_session.rs @@ -15,12 +15,12 @@ use tonic::{Request, Response, Status}; use tracing::{debug, info, warn}; use uuid::Uuid; -use openshell_core::proto::SUPERVISOR_PROTOCOL_REVISION; use openshell_core::proto::{ ConfigUpdate, GatewayMessage, RelayFrame, RelayInit, RelayOpen, ReportMainProcessExitRequest, ReportMainProcessExitResponse, Sandbox, SandboxPhase, SessionAccepted, SshRelayTarget, SupervisorMessage, config_update, gateway_message, relay_open, supervisor_message, }; +use openshell_core::proto::{LEGACY_SUPERVISOR_PROTOCOL_REVISION, SUPERVISOR_PROTOCOL_REVISION}; use openshell_core::transport_errors::is_expected_transport_close_status; use crate::ServerState; @@ -810,7 +810,7 @@ pub async fn handle_connect_supervisor( if sandbox_id.is_empty() { return Err(Status::invalid_argument("sandbox_id is required")); } - validate_protocol_revision(hello.protocol_revision)?; + validate_protocol_revision(&sandbox_id, hello.protocol_revision)?; if let Some(principal) = principal.as_ref() { crate::auth::guard::ensure_sandbox_principal_scope(principal, &sandbox_id)?; } @@ -960,13 +960,20 @@ pub async fn handle_connect_supervisor( Ok(Response::new(stream)) } -fn validate_protocol_revision(supervisor_revision: u32) -> Result<(), Status> { - if supervisor_revision == SUPERVISOR_PROTOCOL_REVISION { - Ok(()) - } else { - Err(Status::failed_precondition(format!( - "supervisor protocol revision mismatch: gateway requires {SUPERVISOR_PROTOCOL_REVISION}, supervisor offered {supervisor_revision}" - ))) +fn validate_protocol_revision(sandbox_id: &str, supervisor_revision: u32) -> Result<(), Status> { + match supervisor_revision { + SUPERVISOR_PROTOCOL_REVISION => Ok(()), + LEGACY_SUPERVISOR_PROTOCOL_REVISION => { + counter!("openshell_supervisor_protocol_legacy_sessions_total").increment(1); + warn!( + sandbox_id = %sandbox_id, + "supervisor session: supervisor predates the protocol handshake; recreate the sandbox before the next gateway upgrade" + ); + Ok(()) + } + other => Err(Status::failed_precondition(format!( + "supervisor protocol revision mismatch: gateway requires {SUPERVISOR_PROTOCOL_REVISION}, supervisor offered {other}" + ))), } } @@ -1246,9 +1253,77 @@ mod tests { } #[test] - fn supervisor_protocol_revision_must_match_exactly() { - assert!(validate_protocol_revision(SUPERVISOR_PROTOCOL_REVISION).is_ok()); - let error = validate_protocol_revision(SUPERVISOR_PROTOCOL_REVISION + 1).unwrap_err(); + fn supervisor_protocol_revision_accepts_current_and_legacy_peers() { + assert!(validate_protocol_revision("sb-1", SUPERVISOR_PROTOCOL_REVISION).is_ok()); + assert!(validate_protocol_revision("sb-1", LEGACY_SUPERVISOR_PROTOCOL_REVISION).is_ok()); + } + + async fn state_with_sandbox(sandbox_id: &str) -> Arc { + let state = crate::grpc::test_support::test_server_state().await; + state + .store + .put_message(&sandbox_record(sandbox_id, sandbox_id)) + .await + .unwrap(); + state + } + + async fn first_gateway_message( + harness: &mut crate::grpc::test_support::SupervisorStreamHarness, + ) -> GatewayMessage { + tokio::time::timeout(Duration::from_secs(5), harness.inbound.message()) + .await + .expect("gateway response before timeout") + .expect("stream open") + .expect("gateway message") + } + + #[tokio::test] + async fn legacy_supervisor_without_protocol_revision_is_accepted() { + let state = state_with_sandbox("sb-legacy").await; + let mut harness = crate::grpc::test_support::connect_supervisor_stream( + &state, + "sb-legacy", + LEGACY_SUPERVISOR_PROTOCOL_REVISION, + ) + .await + .expect("legacy supervisor must connect"); + + let Some(gateway_message::Payload::SessionAccepted(accepted)) = + first_gateway_message(&mut harness).await.payload + else { + panic!("expected SessionAccepted"); + }; + assert_eq!(accepted.protocol_revision, SUPERVISOR_PROTOCOL_REVISION); + assert!( + state + .supervisor_sessions + .is_current_session("sb-legacy", &accepted.session_id) + ); + } + + #[tokio::test] + async fn unknown_supervisor_protocol_revision_is_rejected() { + let state = state_with_sandbox("sb-future").await; + let Err(status) = crate::grpc::test_support::connect_supervisor_stream( + &state, + "sb-future", + SUPERVISOR_PROTOCOL_REVISION + 1, + ) + .await + else { + panic!("mismatched revision must be rejected"); + }; + + assert_eq!(status.code(), tonic::Code::FailedPrecondition); + assert!(status.message().contains("revision mismatch")); + assert!(state.supervisor_sessions.connected_sandbox_ids().is_empty()); + } + + #[test] + fn supervisor_protocol_revision_rejects_unknown_peers() { + let error = + validate_protocol_revision("sb-1", SUPERVISOR_PROTOCOL_REVISION + 1).unwrap_err(); assert_eq!(error.code(), tonic::Code::FailedPrecondition); assert!(error.message().contains("revision mismatch")); } diff --git a/crates/openshell-supervisor-process/src/supervisor_session.rs b/crates/openshell-supervisor-process/src/supervisor_session.rs index 9b6882f84c..959d7dd0d6 100644 --- a/crates/openshell-supervisor-process/src/supervisor_session.rs +++ b/crates/openshell-supervisor-process/src/supervisor_session.rs @@ -17,13 +17,13 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; -use openshell_core::proto::SUPERVISOR_PROTOCOL_REVISION; use openshell_core::proto::open_shell_client::OpenShellClient; use openshell_core::proto::{ FinalizeMainProcessExitRequest, GatewayMessage, RelayFrame, RelayInit, RelayOpen, RelayOpenResult, ReportMainProcessExitRequest, SupervisorHeartbeat, SupervisorHello, SupervisorMessage, TcpRelayTarget, gateway_message, relay_open, supervisor_message, }; +use openshell_core::proto::{LEGACY_SUPERVISOR_PROTOCOL_REVISION, SUPERVISOR_PROTOCOL_REVISION}; use openshell_ocsf::{ ActivityId, ConnectionInfo, Endpoint, EventContext, NetworkActivityBuilder, OcsfEvent, SeverityId, StatusId, ocsf_emit, @@ -447,13 +447,18 @@ async fn run_single_session( fn validate_gateway_protocol_revision( gateway_revision: u32, ) -> Result<(), Box> { - if gateway_revision == SUPERVISOR_PROTOCOL_REVISION { - Ok(()) - } else { - Err(format!( - "supervisor protocol revision mismatch: supervisor requires {SUPERVISOR_PROTOCOL_REVISION}, gateway offered {gateway_revision}" + match gateway_revision { + SUPERVISOR_PROTOCOL_REVISION => Ok(()), + LEGACY_SUPERVISOR_PROTOCOL_REVISION => { + warn!( + "supervisor session: gateway predates the protocol handshake; upgrade the gateway before pinning newer supervisor images" + ); + Ok(()) + } + other => Err(format!( + "supervisor protocol revision mismatch: supervisor requires {SUPERVISOR_PROTOCOL_REVISION}, gateway offered {other}" ) - .into()) + .into()), } } @@ -863,8 +868,13 @@ mod target_tests { use super::*; #[test] - fn gateway_protocol_revision_must_match_exactly() { + fn gateway_protocol_revision_accepts_current_and_legacy_peers() { assert!(validate_gateway_protocol_revision(SUPERVISOR_PROTOCOL_REVISION).is_ok()); + assert!(validate_gateway_protocol_revision(LEGACY_SUPERVISOR_PROTOCOL_REVISION).is_ok()); + } + + #[test] + fn gateway_protocol_revision_rejects_unknown_peers() { let error = validate_gateway_protocol_revision(SUPERVISOR_PROTOCOL_REVISION + 1) .expect_err("version skew must be rejected"); assert!(error.to_string().contains("revision mismatch")); diff --git a/docs/reference/gateway-config.mdx b/docs/reference/gateway-config.mdx index 8aeb2281eb..6a0be10c8c 100644 --- a/docs/reference/gateway-config.mdx +++ b/docs/reference/gateway-config.mdx @@ -108,6 +108,8 @@ disable_tls = false default_image = "ghcr.io/nvidia/openshell-community/sandboxes/base:latest" # Defaults to the gateway version. Custom builds must match the gateway's # internal supervisor protocol revision; mismatched peers reject the session. +# Supervisors from releases before the handshake existed still connect, with +# a gateway warning, until the next release. # supervisor_image = "ghcr.io/nvidia/openshell/supervisor:" client_tls_secret_name = "openshell-client-tls" service_account_name = "openshell-sandbox" diff --git a/proto/openshell.proto b/proto/openshell.proto index 9e1a3e7f9a..a63d33ac4f 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -2517,6 +2517,7 @@ message SupervisorHello { // Supervisor instance ID (e.g. boot id or process epoch). string instance_id = 2; // Exact internal stream protocol revision implemented by this supervisor. + // Zero identifies a supervisor built before the handshake existed. uint32 protocol_revision = 3; } diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index 4f730587cc..ec6f3790f0 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -16,11 +16,11 @@ The target deployment flow is: 1. Operator starts or deploys the gateway with system packages, systemd, or Helm. The CLI does not start, stop, or destroy gateway services. 2. Operator configures the compute driver. 3. Operator provides the CLI and supervisor authentication material required by the deployment mode: edge or OIDC user auth, optional CLI mTLS, and gateway-minted sandbox JWTs. - -If supervisor sessions fail with a protocol revision mismatch, check that custom supervisor images match the gateway release. Gateway and supervisor require the same internal protocol revision; authentication success does not make mismatched versions compatible. See the published [gateway configuration reference](https://docs.nvidia.com/openshell/latest/reference/gateway-config). 4. The CLI registers a reachable gateway endpoint with `openshell gateway add`. 5. The gateway creates sandboxes through the selected compute driver. +If supervisor sessions fail with a protocol revision mismatch, check that custom supervisor images match the gateway release. Gateway and supervisor require the same internal protocol revision; authentication success does not make mismatched versions compatible. Supervisors that predate the handshake still connect for one release. The gateway logs a warning for each such session and counts them in the `openshell_supervisor_protocol_legacy_sessions_total` metric, so recreate those sandboxes before the next gateway upgrade. See the published [gateway configuration reference](https://docs.nvidia.com/openshell/latest/reference/gateway-config.md). + The `openshell-gateway` composition crate explicitly installs its compiled Docker, Podman, Kubernetes, and VM registrations at startup; `openshell-server` does not link compute-driver crates. Custom gateway binaries may include a From fe2fa4ee3b4327fb5718174c1891ac1de4fd7572 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Wed, 9 Sep 2026 16:54:24 -0700 Subject: [PATCH 05/15] chore(sdk): regenerate Go proto bindings for protocol revision comment Signed-off-by: Piotr Mlocek --- sdk/go/proto/openshellv1/openshell.pb.go | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index de2aadfafa..cce47f10ec 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -10982,6 +10982,7 @@ type SupervisorHello struct { // Supervisor instance ID (e.g. boot id or process epoch). InstanceId string `protobuf:"bytes,2,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` // Exact internal stream protocol revision implemented by this supervisor. + // Zero identifies a supervisor built before the handshake existed. ProtocolRevision uint32 `protobuf:"varint,3,opt,name=protocol_revision,json=protocolRevision,proto3" json:"protocol_revision,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache From 3053b2f95a55d4db49deae0b9504d410332608b2 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Thu, 10 Sep 2026 12:40:41 -0700 Subject: [PATCH 06/15] fix(supervisor): bound optional bootstrap latency on reconnect Signed-off-by: Piotr Mlocek --- architecture/sandbox.md | 6 +- .../openshell-server/src/config_delivery.rs | 86 ++++++++++++++++++- crates/openshell-server/src/credentials.rs | 56 ++++++++++++ crates/openshell-server/src/grpc/policy.rs | 4 + docs/reference/gateway-config.mdx | 6 ++ 5 files changed, 155 insertions(+), 3 deletions(-) diff --git a/architecture/sandbox.md b/architecture/sandbox.md index daba7bbacd..fa6db62add 100644 --- a/architecture/sandbox.md +++ b/architecture/sandbox.md @@ -481,8 +481,10 @@ accepted for one release with a warning and a counter, because sandboxes keep their supervisor binary until they are recreated. The gateway includes a configuration bootstrap when it accepts a `ConnectSupervisor` session and can send complete component replacements on the same stream after policy, settings, or provider state changes. -Bootstrap construction does not gate the session while polling remains -authoritative. These payloads describe the latest effective state rather than +While polling remains authoritative, optional bootstrap construction has a +one-second budget. The gateway accepts the session without a bootstrap when +that budget expires, so slow credential backends do not block relay reconnects. +These payloads describe the latest effective state rather than the mutation that produced it. The gateway assigns ordering sequences within each session and component, while each snapshot retains its own content revision. diff --git a/crates/openshell-server/src/config_delivery.rs b/crates/openshell-server/src/config_delivery.rs index b9c7495277..8019c63cea 100644 --- a/crates/openshell-server/src/config_delivery.rs +++ b/crates/openshell-server/src/config_delivery.rs @@ -26,6 +26,9 @@ use crate::supervisor_session::SupervisorSessionRegistry; /// future envelope fields. pub const MAX_SUPERVISOR_CONFIG_MESSAGE_BYTES: usize = 3 * 1024 * 1024; const CONFIG_SNAPSHOT_BUILD_TIMEOUT: Duration = Duration::from_secs(45); +// Stage 1 bootstrap is optional. Keep credential backend stalls well below +// the 15-second relay session-wait budget while polling remains authoritative. +const CONFIG_BOOTSTRAP_BUILD_TIMEOUT: Duration = Duration::from_secs(1); const MAX_ACTIVE_FANOUT_WORKERS: usize = 64; /// Concurrent snapshot builds allowed per pooled database connection. Builds /// are short bursts of small queries, so a little oversubscription keeps the @@ -321,7 +324,7 @@ pub async fn build_config_bootstrap( sandbox: &Sandbox, ) -> Result { tokio::time::timeout( - CONFIG_SNAPSHOT_BUILD_TIMEOUT, + CONFIG_BOOTSTRAP_BUILD_TIMEOUT, build_consistent_config_bootstrap(state, sandbox), ) .await @@ -773,4 +776,85 @@ mod tests { .provider_env_revision = 7; assert!(bootstrap_revisions_match(&bootstrap)); } + + #[tokio::test] + async fn stalled_credentials_do_not_block_session_acceptance() { + use openshell_core::proto::{CredentialHandle, Provider}; + + let state = test_server_state().await; + state + .store + .put_message(&Provider { + metadata: Some(ObjectMeta { + id: "provider".into(), + name: "provider".into(), + workspace: "default".into(), + ..Default::default() + }), + r#type: "github".into(), + credential_handles: HashMap::from([( + "GITHUB_TOKEN".into(), + CredentialHandle { + driver: "test-static".into(), + handle: "blocked".into(), + ..Default::default() + }, + )]), + ..Default::default() + }) + .await + .unwrap(); + state + .store + .put_message(&Sandbox { + metadata: Some(ObjectMeta { + id: "sandbox".into(), + name: "sandbox".into(), + workspace: "default".into(), + ..Default::default() + }), + spec: Some(SandboxSpec { + providers: vec!["provider".into()], + ..Default::default() + }), + ..Default::default() + }) + .await + .unwrap(); + let (resolve_hit, _release_resolve) = state.credentials.gate_next_resolve(); + tokio::time::timeout(Duration::from_secs(10), async { + let connect = connect_supervisor_stream( + &state, + "sandbox", + openshell_core::proto::SUPERVISOR_PROTOCOL_REVISION, + ); + let (response, hit) = tokio::join!(connect, resolve_hit); + hit.expect("bootstrap must reach the stalled credential driver"); + let mut harness = response.unwrap(); + let first = harness.inbound.message().await.unwrap().unwrap(); + let Some(gateway_message::Payload::SessionAccepted(accepted)) = first.payload else { + panic!("expected session acceptance"); + }; + assert!(accepted.bootstrap.is_none()); + assert!( + state + .supervisor_sessions + .is_current_session("sandbox", &accepted.session_id) + ); + // Relay control remains usable while credential resolution is stalled. + let (_, relay) = state + .supervisor_sessions + .open_relay("sandbox", Duration::from_secs(1)) + .await + .unwrap(); + let message = harness.inbound.message().await.unwrap().unwrap(); + assert!(matches!( + message.payload, + Some(gateway_message::Payload::RelayOpen(_)) + )); + drop(relay); + }) + .await + .expect("optional bootstrap must not consume the relay reconnect budget"); + } } diff --git a/crates/openshell-server/src/credentials.rs b/crates/openshell-server/src/credentials.rs index e1ea5994cc..922a0b8ebe 100644 --- a/crates/openshell-server/src/credentials.rs +++ b/crates/openshell-server/src/credentials.rs @@ -92,6 +92,16 @@ pub trait CredentialDriver: std::fmt::Debug + Send + Sync { #[cfg(test)] fn fail_next_delete(&self) {} + #[cfg(test)] + fn gate_next_resolve( + &self, + ) -> Option<( + tokio::sync::oneshot::Receiver<()>, + tokio::sync::oneshot::Sender<()>, + )> { + None + } + #[cfg(test)] fn gate_next_store( &self, @@ -268,6 +278,19 @@ impl CredentialRuntime { .expect("test credential driver supports store gating") } + #[cfg(test)] + pub(crate) fn gate_next_resolve( + &self, + ) -> ( + tokio::sync::oneshot::Receiver<()>, + tokio::sync::oneshot::Sender<()>, + ) { + self.drivers + .get(&self.registry.storage_owner_name()) + .and_then(|driver| driver.gate_next_resolve()) + .expect("test credential driver supports resolve gating") + } + pub async fn store_provider_credentials( &self, provider_name: &str, @@ -1711,6 +1734,13 @@ struct TestStaticCredentialDriver { fail_next_store: std::sync::atomic::AtomicBool, fail_next_delete: std::sync::atomic::AtomicBool, #[cfg(test)] + resolve_gate: std::sync::Mutex< + Option<( + tokio::sync::oneshot::Sender<()>, + tokio::sync::oneshot::Receiver<()>, + )>, + >, + #[cfg(test)] store_gate: std::sync::Mutex< Option<( tokio::sync::oneshot::Sender<()>, @@ -1729,6 +1759,8 @@ impl TestStaticCredentialDriver { fail_next_store: std::sync::atomic::AtomicBool::new(false), fail_next_delete: std::sync::atomic::AtomicBool::new(false), #[cfg(test)] + resolve_gate: std::sync::Mutex::new(None), + #[cfg(test)] store_gate: std::sync::Mutex::new(None), } } @@ -1806,6 +1838,17 @@ impl CredentialDriver for TestStaticCredentialDriver { requests: Vec, ) -> Result, Status> { let mut responses = Vec::with_capacity(requests.len()); + #[cfg(test)] + let gate = self + .resolve_gate + .lock() + .ok() + .and_then(|mut gate| gate.take()); + #[cfg(test)] + if let Some((hit, release)) = gate { + let _ = hit.send(()); + let _ = release.await; + } for request in requests { let handle = Self::handle_from_request(&request.request_id, request.handle)?; let value = self @@ -1836,6 +1879,19 @@ impl CredentialDriver for TestStaticCredentialDriver { .store(true, std::sync::atomic::Ordering::SeqCst); } + #[cfg(test)] + fn gate_next_resolve( + &self, + ) -> Option<( + tokio::sync::oneshot::Receiver<()>, + tokio::sync::oneshot::Sender<()>, + )> { + let (hit_tx, hit_rx) = tokio::sync::oneshot::channel(); + let (release_tx, release_rx) = tokio::sync::oneshot::channel(); + *self.resolve_gate.lock().ok()? = Some((hit_tx, release_rx)); + Some((hit_rx, release_tx)) + } + #[cfg(test)] fn fail_next_delete(&self) { self.fail_next_delete diff --git a/crates/openshell-server/src/grpc/policy.rs b/crates/openshell-server/src/grpc/policy.rs index 0d99a0b876..bd84508eeb 100644 --- a/crates/openshell-server/src/grpc/policy.rs +++ b/crates/openshell-server/src/grpc/policy.rs @@ -8078,6 +8078,10 @@ mod tests { .await .expect("store sandbox with invalid legacy spec"); + backfill_legacy_policy_history(&state) + .await + .expect("global override must allow startup with an invalid dormant spec"); + let response = handle_get_sandbox_config( &state, with_sandbox( diff --git a/docs/reference/gateway-config.mdx b/docs/reference/gateway-config.mdx index 6a0be10c8c..bbd8ee72aa 100644 --- a/docs/reference/gateway-config.mdx +++ b/docs/reference/gateway-config.mdx @@ -20,6 +20,12 @@ Gateway CLI flag > gateway OPENSHELL_* env var > TOML file > built-in defa `name` assigns an operator-facing identity to the gateway installation. Set it with `[openshell.gateway].name`, `--name`, or `OPENSHELL_GATEWAY_NAME`. It defaults to `openshell`; the Helm chart defaults it to the chart fullname so all replicas in one installation share a name. Chart fullnames are only unique within their Kubernetes namespace, so set `server.name` explicitly when one collector receives telemetry from multiple namespaces or clusters. This identity is independent of client-side gateway aliases, TLS names, and `gateway_jwt.gateway_id`. +## Supervisor connections and policy recovery + +During supervisor reconnects, the gateway waits at most one second for the optional configuration bootstrap. If a credential backend stalls, the gateway accepts the session without that bootstrap so SSH, exec, and service connections can resume. Supervisor polling continues to supply configuration. + +On startup, the gateway repairs missing legacy policy history and skips invalid stored policies. A valid global policy can still override an invalid local policy; otherwise, that sandbox's configuration reads continue to report the validation failure. + ## Package-Managed Locations Package-managed gateways do not require a TOML file. Create one at the package's optional config location when you need to override built-in defaults. Set `OPENSHELL_GATEWAY_CONFIG` in the launch environment to use a different file. From 86773ee3d1613ecb1382d4ecc17decf584320161 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Thu, 10 Sep 2026 14:36:40 -0700 Subject: [PATCH 07/15] fix(server): bound configuration delivery workers Signed-off-by: Piotr Mlocek --- architecture/gateway.md | 12 +- architecture/sandbox.md | 17 +- .../openshell-server/src/config_delivery.rs | 193 ++++++++++++++---- 3 files changed, 173 insertions(+), 49 deletions(-) diff --git a/architecture/gateway.md b/architecture/gateway.md index 70000c2c22..ac47301868 100644 --- a/architecture/gateway.md +++ b/architecture/gateway.md @@ -658,11 +658,13 @@ refresh bootstrap material; sandboxes receive minted access tokens instead. Committed configuration mutations publish component and scope identifiers, never configuration payloads, to a bounded coalescing scheduler. The scheduler -builds the latest full snapshot for each affected active sandbox. An async -router owns session lookup, message sizing, sequence allocation, and enqueue. -Its local implementation uses the process-local supervisor registry. A future -HA implementation can resolve the gateway that owns a session and forward the -same typed message without changing mutation handlers. +admits a fixed number of delivery workers and builds the latest full snapshot +for each affected active sandbox. Fleet fanout waits for worker capacity before +admitting another recipient. An async router owns session lookup, message +sizing, sequence allocation, and enqueue. Its local implementation uses the +process-local supervisor registry. A future HA implementation can resolve the +gateway that owns a session and forward the same typed message without changing +mutation handlers. Polling remains authoritative during the first rollout stage. Snapshot build, fanout, or enqueue failure cannot fail a mutation that already committed. diff --git a/architecture/sandbox.md b/architecture/sandbox.md index fa6db62add..00fc709c25 100644 --- a/architecture/sandbox.md +++ b/architecture/sandbox.md @@ -509,14 +509,15 @@ unavailable delivery. The gateway serializes construction per sandbox and component, and coalesces repeated mutations into the latest full snapshot. An enqueue result means only that the local stream queue accepted the message. A bounded scope fanout scheduler coalesces repeated workspace and global changes, -and a semaphore sized from the database pool bounds how many snapshots build -at once so a fleet-wide change cannot saturate the store or credential -backends. Snapshot construction has a deadline that starts once a build holds a -permit, and the gateway rejects encoded stream messages that approach the -transport decoder limit. A later migration will apply these payloads directly -and acknowledge their exact revisions before removing supervisor polling. At -that point, the gateway will require a valid bootstrap before marking a session -ready. +and semaphores sized from the database pool bound delivery workers and snapshot +builds. Fanout waits for worker capacity before admitting each recipient, so a +fleet-wide change cannot create a fleet-sized task backlog or saturate the store +and credential backends. Snapshot construction has a deadline that starts once +a build holds a permit, and the gateway rejects encoded stream messages that +approach the transport decoder limit. A later migration will apply these +payloads directly and acknowledge their exact revisions before removing +supervisor polling. At that point, the gateway will require a valid bootstrap +before marking a session ready. ## Policy Revision Acknowledgement diff --git a/crates/openshell-server/src/config_delivery.rs b/crates/openshell-server/src/config_delivery.rs index 8019c63cea..2437ada722 100644 --- a/crates/openshell-server/src/config_delivery.rs +++ b/crates/openshell-server/src/config_delivery.rs @@ -13,7 +13,7 @@ use metrics::counter; use openshell_core::proto::{ ConfigBootstrap, ProviderEnvironmentSnapshot, Sandbox, SandboxConfigSnapshot, }; -use tokio::sync::Semaphore; +use tokio::sync::{OwnedSemaphorePermit, Semaphore}; use tonic::{Code, Status}; use tracing::warn; @@ -143,13 +143,6 @@ impl ConfigComponents { .into_iter() .filter_map(|(selected, component)| selected.then_some(component)) } - - fn only(component: ConfigComponentKind) -> Self { - Self { - sandbox_config: component == ConfigComponentKind::SandboxConfig, - provider_environment: component == ConfigComponentKind::ProviderEnvironment, - } - } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -185,20 +178,21 @@ struct FanoutKey { component: ConfigComponentKind, } -/// Coalesces publications and runs one worker per sandbox and component. +/// Coalesces publications and bounds workers per sandbox and component. /// /// The map entry is also the worker lease. Its boolean is set when another /// mutation arrives during a build or route operation. The worker then rebuilds /// the current full snapshot once, regardless of how many mutations arrived. /// -/// Workers are spawned eagerly so coalescing stays exact, but snapshot -/// construction itself is bounded by `build_permits`. A fleet-wide change -/// therefore queues on the semaphore instead of saturating the database pool -/// and credential backends all at once. +/// Each pending map entry owns a delivery permit for its worker. Direct +/// publications fail fast when all permits are held. Fanout workers wait for a +/// permit before admitting the next recipient, which bounds both spawned tasks +/// and pending keys while still walking the full recipient list. #[derive(Debug)] pub struct ConfigDeliveryQueue { pending: Mutex>, fanout_pending: Mutex>, + delivery_permits: Arc, build_permits: Semaphore, } @@ -211,10 +205,12 @@ impl Default for ConfigDeliveryQueue { impl ConfigDeliveryQueue { #[must_use] pub fn new(max_concurrent_builds: usize) -> Self { + let max_concurrent_builds = max_concurrent_builds.max(1); Self { pending: Mutex::default(), fanout_pending: Mutex::default(), - build_permits: Semaphore::new(max_concurrent_builds.max(1)), + delivery_permits: Arc::new(Semaphore::new(max_concurrent_builds)), + build_permits: Semaphore::new(max_concurrent_builds), } } @@ -249,16 +245,45 @@ impl ConfigDeliveryQueue { tokio::time::timeout(CONFIG_SNAPSHOT_BUILD_TIMEOUT, build).await } - fn enqueue(&self, key: DeliveryKey) -> bool { + fn enqueue(&self, key: DeliveryKey) -> DeliveryEnqueue { + let mut pending = self.pending.lock().unwrap(); + match pending.entry(key) { + Entry::Occupied(mut entry) => { + *entry.get_mut() = true; + DeliveryEnqueue::Coalesced + } + Entry::Vacant(entry) => { + let Ok(permit) = Arc::clone(&self.delivery_permits).try_acquire_owned() else { + return DeliveryEnqueue::Full; + }; + entry.insert(true); + DeliveryEnqueue::StartWorker(permit) + } + } + } + + async fn enqueue_from_fanout(&self, key: DeliveryKey) -> DeliveryEnqueue { + { + let mut pending = self.pending.lock().unwrap(); + if let Entry::Occupied(mut entry) = pending.entry(key.clone()) { + *entry.get_mut() = true; + return DeliveryEnqueue::Coalesced; + } + } + + let permit = Arc::clone(&self.delivery_permits) + .acquire_owned() + .await + .expect("delivery worker semaphore is never closed"); let mut pending = self.pending.lock().unwrap(); match pending.entry(key) { Entry::Occupied(mut entry) => { *entry.get_mut() = true; - false + DeliveryEnqueue::Coalesced } Entry::Vacant(entry) => { entry.insert(true); - true + DeliveryEnqueue::StartWorker(permit) } } } @@ -312,6 +337,13 @@ impl ConfigDeliveryQueue { } } +#[derive(Debug)] +enum DeliveryEnqueue { + StartWorker(OwnedSemaphorePermit), + Coalesced, + Full, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum FanoutEnqueue { StartWorker, @@ -382,21 +414,52 @@ fn enqueue_sandbox(state: &Arc, sandbox_id: &str, components: Confi sandbox_id: sandbox_id.to_string(), component, }; - if state.config_delivery_queue.enqueue(key.clone()) { - let state = Arc::clone(state); - tokio::spawn(async move { - loop { - state.config_delivery_queue.take(&key); - publish_sandbox_component_now(&state, &key).await; - if !state.config_delivery_queue.finish_pass(&key) { - break; - } - } - }); + match state.config_delivery_queue.enqueue(key.clone()) { + DeliveryEnqueue::StartWorker(permit) => { + spawn_delivery_worker(state, key, permit); + } + DeliveryEnqueue::Coalesced => {} + DeliveryEnqueue::Full => { + record_delivery_worker_full(sandbox_id, component.name()); + } } } } +fn spawn_delivery_worker(state: &Arc, key: DeliveryKey, permit: OwnedSemaphorePermit) { + let state = Arc::clone(state); + tokio::spawn(async move { + let _permit = permit; + loop { + state.config_delivery_queue.take(&key); + publish_sandbox_component_now(&state, &key).await; + if !state.config_delivery_queue.finish_pass(&key) { + break; + } + } + }); +} + +async fn enqueue_sandbox_from_fanout( + state: &Arc, + sandbox_id: &str, + component: ConfigComponentKind, +) { + let key = DeliveryKey { + sandbox_id: sandbox_id.to_string(), + component, + }; + match state + .config_delivery_queue + .enqueue_from_fanout(key.clone()) + .await + { + DeliveryEnqueue::StartWorker(permit) => spawn_delivery_worker(state, key, permit), + DeliveryEnqueue::Coalesced => {} + DeliveryEnqueue::Full => unreachable!("fanout waits for delivery worker capacity"), + } +} + async fn publish_sandbox_component_now(state: &Arc, key: &DeliveryKey) { let component = key.component.name(); let build = async { @@ -505,10 +568,22 @@ async fn publish_fanout_now(state: &Arc, key: &FanoutKey) { continue; } } - enqueue_sandbox(state, &sandbox_id, ConfigComponents::only(key.component)); + enqueue_sandbox_from_fanout(state, &sandbox_id, key.component).await; } } +fn record_delivery_worker_full(sandbox_id: &str, component: &'static str) { + counter!( + "openshell_supervisor_config_delivery_workers_total", + "outcome" => "queue_full", + ) + .increment(1); + warn!( + sandbox_id, + component, "supervisor configuration delivery worker queue is full" + ); +} + fn record_delivery(component: &'static str, disposition: DeliveryDisposition) { let outcome = match disposition { DeliveryDisposition::Enqueued => "enqueued", @@ -558,13 +633,22 @@ mod tests { fn queue_coalesces_repeated_component_changes_while_worker_is_active() { let queue = ConfigDeliveryQueue::default(); let key = key("sb-1", ConfigComponentKind::SandboxConfig); - assert!(queue.enqueue(key.clone())); + let DeliveryEnqueue::StartWorker(permit) = queue.enqueue(key.clone()) else { + panic!("first publication must start a worker"); + }; queue.take(&key); - assert!(!queue.enqueue(key.clone())); - assert!(!queue.enqueue(key.clone())); + assert!(matches!( + queue.enqueue(key.clone()), + DeliveryEnqueue::Coalesced + )); + assert!(matches!( + queue.enqueue(key.clone()), + DeliveryEnqueue::Coalesced + )); assert!(queue.finish_pass(&key)); queue.take(&key); assert!(!queue.finish_pass(&key)); + drop(permit); } #[test] @@ -651,10 +735,47 @@ mod tests { #[test] fn queue_runs_components_and_sandboxes_independently() { - let queue = ConfigDeliveryQueue::default(); - assert!(queue.enqueue(key("sb-1", ConfigComponentKind::SandboxConfig))); - assert!(queue.enqueue(key("sb-1", ConfigComponentKind::ProviderEnvironment))); - assert!(queue.enqueue(key("sb-2", ConfigComponentKind::SandboxConfig))); + let queue = ConfigDeliveryQueue::new(3); + assert!(matches!( + queue.enqueue(key("sb-1", ConfigComponentKind::SandboxConfig)), + DeliveryEnqueue::StartWorker(_) + )); + assert!(matches!( + queue.enqueue(key("sb-1", ConfigComponentKind::ProviderEnvironment)), + DeliveryEnqueue::StartWorker(_) + )); + assert!(matches!( + queue.enqueue(key("sb-2", ConfigComponentKind::SandboxConfig)), + DeliveryEnqueue::StartWorker(_) + )); + } + + #[tokio::test] + async fn fleet_fanout_waits_without_creating_unbounded_delivery_workers() { + const ROUTED_SANDBOXES: usize = 10_000; + let queue = Arc::new(ConfigDeliveryQueue::new(1)); + let first = key("sandbox-0", ConfigComponentKind::SandboxConfig); + let DeliveryEnqueue::StartWorker(_blocked_worker) = queue.enqueue(first) else { + panic!("first publication must start a worker"); + }; + + let sandbox_ids = (1..ROUTED_SANDBOXES) + .map(|index| format!("sandbox-{index}")) + .collect::>(); + let fanout = async { + for sandbox_id in sandbox_ids { + for component in ConfigComponents::ALL.selected() { + let _ = queue.enqueue_from_fanout(key(&sandbox_id, component)).await; + } + } + }; + tokio::pin!(fanout); + tokio::select! { + () = &mut fanout => panic!("fanout must wait for worker capacity"), + () = tokio::task::yield_now() => {} + } + + assert_eq!(queue.pending.lock().unwrap().len(), 1); } #[test] From 70773d35e88bdcbb3158590dc348134191efe87e Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Thu, 10 Sep 2026 19:02:33 -0700 Subject: [PATCH 08/15] fix(server): update configuration tests for workspace selector Signed-off-by: Piotr Mlocek --- crates/openshell-server/src/grpc/policy.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/openshell-server/src/grpc/policy.rs b/crates/openshell-server/src/grpc/policy.rs index bd84508eeb..77c997e046 100644 --- a/crates/openshell-server/src/grpc/policy.rs +++ b/crates/openshell-server/src/grpc/policy.rs @@ -10886,7 +10886,7 @@ mod tests { &state, with_user(Request::new(UpdateConfigRequest { name: "rejected-policy".to_string(), - workspace: "default".to_string(), + workspace_scope: Some(openshell_core::proto::workspace_selector("default")), policy: Some(test_policy_with_rule("rejected", "api.example.com")), expected_resource_version: u64::MAX, ..Default::default() @@ -10932,7 +10932,7 @@ mod tests { &state, with_user(Request::new(UpdateConfigRequest { name: "published-policy".to_string(), - workspace: "default".to_string(), + workspace_scope: Some(openshell_core::proto::workspace_selector("default")), policy: Some(test_policy_with_rule("published", "api.example.com")), ..Default::default() })), From c6451122461304d1442cbcb4d8658625d9193158 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Thu, 10 Sep 2026 19:49:52 -0700 Subject: [PATCH 09/15] fix(proto): refresh public schema inventory Signed-off-by: Piotr Mlocek --- architecture/gateway.md | 4 ++-- crates/openshell-server/src/storage_proto.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/architecture/gateway.md b/architecture/gateway.md index ac47301868..fc56477f08 100644 --- a/architecture/gateway.md +++ b/architecture/gateway.md @@ -328,8 +328,8 @@ public descriptor set generated by `openshell-core`; a fingerprint test in Compute-driver, credential-driver, gateway-interceptor, and supervisor-middleware services are compiled contracts for internal extension boundaries, not public gateway RPCs. The current public inventory has 74 -methods, 278 messages, and 12 enums -(`0f14943574349d02bdc61076c8c5a59a98b627325564ef1a6d21d7941825dc46`). +methods, 291 messages, and 15 enums +(`e173ad118e822557efcfc92ace7042bbc7bdd35e709c503abb123de378e9e7cb`). Storage-only messages live in the private, versioned `openshell.storage.v1` package under `crates/openshell-server/proto`. The server diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index 8f7c55914f..8ee216d161 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -119,7 +119,7 @@ mod tests { const STORAGE_V1_SCHEMA_SHA256: &str = "79c72615d957fc0653c672f61998bf7d8d21b757bc05d07b3fff92bd70fc8f52"; const PUBLIC_RPC_SCHEMA_SHA256: &str = - "0f14943574349d02bdc61076c8c5a59a98b627325564ef1a6d21d7941825dc46"; + "e173ad118e822557efcfc92ace7042bbc7bdd35e709c503abb123de378e9e7cb"; const DURABLE_SCHEMA_SHA256: &str = "920a5243dfb37ce709f0f562a47d17791a5ede90fd7f662ed01542abd60a0dfb"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = @@ -487,7 +487,7 @@ mod tests { assert_eq!( (public_closure.messages.len(), public_closure.enums.len()), - (278, 12) + (291, 15) ); assert_eq!( (durable_closure.messages.len(), durable_closure.enums.len()), From 1e4991307a0e54ab21e459a223e1583dd3d1319d Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Thu, 17 Sep 2026 21:02:26 -0700 Subject: [PATCH 10/15] test(server): assert repairable invalid policy snapshot Signed-off-by: Piotr Mlocek --- crates/openshell-server/src/grpc/policy.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/openshell-server/src/grpc/policy.rs b/crates/openshell-server/src/grpc/policy.rs index b9d8c7980e..ffb117f2bd 100644 --- a/crates/openshell-server/src/grpc/policy.rs +++ b/crates/openshell-server/src/grpc/policy.rs @@ -12973,7 +12973,7 @@ mod tests { "invalid stored policy must not be persisted as history" ); - let error = handle_get_sandbox_config( + let rejected = handle_get_sandbox_config( &state, with_sandbox( Request::new(GetSandboxConfigRequest { @@ -12983,8 +12983,15 @@ mod tests { ), ) .await - .expect_err("invalid stored policy still fails only its own config read"); - assert_eq!(error.code(), Code::FailedPrecondition); + .expect("invalid stored policy returns a repairable admission snapshot") + .into_inner(); + assert!(!rejected.configuration_admitted); + assert!(rejected.policy.is_none()); + assert_eq!(rejected.workspace, "default"); + assert_eq!( + rejected.configuration_error, + "Stored policy structure or safety validation failed; submit a complete valid replacement policy" + ); } #[tokio::test] From 7f88f5d6eb84147cbbd35cb5b2966f31a9718c34 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Mon, 21 Sep 2026 09:36:34 -0700 Subject: [PATCH 11/15] docs(architecture): correct configuration snapshot boundaries Signed-off-by: Piotr Mlocek --- architecture/gateway.md | 19 ++++++++----------- architecture/security-policy.md | 5 +++++ crates/openshell-server/README.md | 27 +++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 crates/openshell-server/README.md diff --git a/architecture/gateway.md b/architecture/gateway.md index 5341aa3f6e..2f7fce0e4f 100644 --- a/architecture/gateway.md +++ b/architecture/gateway.md @@ -402,9 +402,8 @@ public descriptor set generated by `openshell-core`; a fingerprint test in `openshell-server` requires this inventory to be reviewed whenever it changes. Compute-driver, credential-driver, gateway-interceptor, and supervisor-middleware services are compiled contracts for internal extension -boundaries, not public gateway RPCs. The current public inventory has 75 -methods, 310 messages, and 22 enums -(`0fd806310d90513ff74cb077465aebcd5a9490094e149343876103aef78d3f91`). +boundaries, not public gateway RPCs. The descriptor-derived test is the +authority for current counts and fingerprints. `ReportEndpointStatus` is a sandbox-authenticated public gateway RPC. Its request, response, and `EndpointObservation` messages belong only to the public closure. `EndpointStatus` and `EndpointResult` also belong to the durable closure because `Sandbox.status.endpoint_statuses` persists them. The repeated status field uses a new wire tag; stored sandboxes without it decode with an empty endpoint list and retain their lifecycle fields. A fixed payload encoded with the earlier sandbox schema verifies that no database rewrite is required. Allow and deny append requests carry `L7RuleTarget` to declare the rule, endpoint, and complete affected scope. The removed `host` and `port` fields remain reserved by number and name, and requests without a target are rejected. These mutation requests are not persisted formats. @@ -472,11 +471,9 @@ Stored settings JSON also carries per-key change IDs and commit timestamps, including deletion tombstones. Legacy values acquire stable source identities on read; a subsequent write preserves them. These clocks distinguish effective edits from no-op writes without treating status updates as configuration edits. -With timestamp types, deletion outcomes, and optional mutation request IDs, the -admission contract brings the public closure to 298 messages and 21 enums, the -durable closure to 92 messages and 16 enums, and their overlap to 80 messages -and 16 enums. Mutation request IDs extend public request fields without adding -messages to these closures or changing the durable protobuf schema. +Mutation request IDs extend public request fields without changing the durable +protobuf schema. The descriptor-derived test records the resulting public and +durable closures. | Dual-purpose encoded root | Current decision | |---|---| @@ -837,9 +834,9 @@ refresh bootstrap material; sandboxes receive minted access tokens instead. Committed configuration mutations publish component and scope identifiers, never configuration payloads, to a bounded coalescing scheduler. The scheduler -admits a fixed number of delivery workers and builds the latest full snapshot -for each affected active sandbox. Fleet fanout waits for worker capacity before -admitting another recipient. An async router owns session lookup, message +builds the latest full snapshot for each affected active sandbox. Repeated +mutations coalesce, concurrency is bounded, and periodic reconciliation repairs +build, route, or session failures. An async router owns session lookup, message sizing, sequence allocation, and enqueue. Its local implementation uses the process-local supervisor registry. A future HA implementation can resolve the gateway that owns a session and forward the same typed message without changing diff --git a/architecture/security-policy.md b/architecture/security-policy.md index 5164ec4233..a28da8c32e 100644 --- a/architecture/security-policy.md +++ b/architecture/security-policy.md @@ -55,6 +55,11 @@ file-compatible rights. This avoids rejecting valid mixed-path policies without weakening `hard_requirement`: genuine unsupported ABI capabilities and preparation failures still fail sandbox startup. +During startup policy preparation, an authenticated supervisor may propose any +complete policy for its own sandbox. The gateway does not constrain that proposal +relative to the candidate it sent. It applies the normal sandbox policy +authorization, validation, safety, and composition checks before persistence. + ## Network Decisions Ordinary network traffic follows this order: diff --git a/crates/openshell-server/README.md b/crates/openshell-server/README.md new file mode 100644 index 0000000000..5abc8a5739 --- /dev/null +++ b/crates/openshell-server/README.md @@ -0,0 +1,27 @@ + + + +# OpenShell server + +`openshell-server` implements the gateway control plane. The stable gateway +boundaries and data flows are documented in +[`architecture/gateway.md`](../../architecture/gateway.md). + +## Configuration delivery scheduler + +Configuration publishers enqueue sandbox/component keys rather than payloads. +The scheduler retains at most 1,024 running or queued keys. Repeated requests +for one key coalesce, and a mutation that arrives during delivery returns that +key to the FIFO tail for another pass. + +Delivery admission allows at least 64 workers. Snapshot build concurrency is +also limited by the database pool, so a scoped burst cannot create the same +number of concurrent database and credential-backend reads. Fanout waits for +pending capacity. If direct publication overflows, the scheduler requests one +coalesced all-connected repair pass. Two reserved fanout scopes keep that repair +path available when workspace fanout is full. + +The router owns session lookup, encoded-size checks, sequence allocation, and +enqueue. Delivery workers build current state only after they obtain capacity. +The owner reconciler remains the fallback for build, routing, or session +failures. From c01364531e83323351315b38bed4ecd3cc6975d7 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Thu, 1 Oct 2026 15:51:54 -0700 Subject: [PATCH 12/15] feat(config): route shadow push through HA owners behind gateway mode Signed-off-by: Piotr Mlocek --- .../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_name_fallback_integration.rs | 7 + crates/openshell-core/src/config.rs | 50 +- crates/openshell-sdk/tests/client_mock.rs | 7 + .../openshell-server/src/auth/method_authz.rs | 1 + crates/openshell-server/src/auth/peer.rs | 3 +- crates/openshell-server/src/cli.rs | 13 +- .../openshell-server/src/config_delivery.rs | 437 ++++- crates/openshell-server/src/config_file.rs | 26 + crates/openshell-server/src/grpc/mod.rs | 10 +- crates/openshell-server/src/grpc/policy.rs | 21 +- crates/openshell-server/src/storage_proto.rs | 28 +- .../openshell-server/src/supervisor_owner.rs | 108 +- .../src/supervisor_session.rs | 110 +- crates/openshell-server/tests/common/mod.rs | 7 + .../tests/supervisor_relay_integration.rs | 7 + deploy/helm/openshell/README.md | 1 + .../openshell/templates/gateway-config.yaml | 7 + deploy/helm/openshell/values.yaml | 3 + docs/how-it-works/gateways/configuration.mdx | 4 +- proto/openshell.proto | 32 + sdk/go/proto/openshellv1/openshell.pb.go | 1478 ++++++++++------- sdk/go/proto/openshellv1/openshell_grpc.pb.go | 42 + skills/debug-openshell-cluster/SKILL.md | 9 + 27 files changed, 1761 insertions(+), 678 deletions(-) diff --git a/crates/openshell-cli/tests/ensure_providers_integration.rs b/crates/openshell-cli/tests/ensure_providers_integration.rs index e7221e0079..38b2b6d48d 100644 --- a/crates/openshell-cli/tests/ensure_providers_integration.rs +++ b/crates/openshell-cli/tests/ensure_providers_integration.rs @@ -79,6 +79,13 @@ impl TestOpenShell { #[tonic::async_trait] impl OpenShell for TestOpenShell { + async fn peer_notify_config_update( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test server")) + } + 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 ca969dde13..1155ef762d 100644 --- a/crates/openshell-cli/tests/mtls_integration.rs +++ b/crates/openshell-cli/tests/mtls_integration.rs @@ -32,6 +32,13 @@ struct TestOpenShell; #[tonic::async_trait] impl OpenShell for TestOpenShell { + async fn peer_notify_config_update( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test server")) + } + 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 2cbeaffdf6..5d6e8c8190 100644 --- a/crates/openshell-cli/tests/provider_commands_integration.rs +++ b/crates/openshell-cli/tests/provider_commands_integration.rs @@ -232,6 +232,13 @@ impl TestOpenShell { #[tonic::async_trait] impl OpenShell for TestOpenShell { + async fn peer_notify_config_update( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test server")) + } + 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 964559a8ad..b2fa432bde 100644 --- a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs +++ b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs @@ -92,6 +92,13 @@ struct TestOpenShell { #[tonic::async_trait] impl OpenShell for TestOpenShell { + async fn peer_notify_config_update( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test server")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs index 7a5780d7f3..d8e0e80088 100644 --- a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs +++ b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs @@ -47,6 +47,13 @@ struct TestOpenShell { #[tonic::async_trait] impl OpenShell for TestOpenShell { + async fn peer_notify_config_update( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test server")) + } + 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 820b4a9476..7057a19b1d 100644 --- a/crates/openshell-core/src/config.rs +++ b/crates/openshell-core/src/config.rs @@ -46,6 +46,30 @@ pub const DEFAULT_DOCKER_NETWORK_NAME: &str = "openshell-docker"; /// Default domain used for browser-facing sandbox service URLs. pub const DEFAULT_SERVICE_ROUTING_DOMAIN: &str = "openshell.localhost"; +/// Gateway delivery path for supervisor configuration. +/// `Push` is a shadow stream until supervisors support applying snapshots. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum ConfigDeliveryMode { + #[default] + Poll, + Push, +} + +impl FromStr for ConfigDeliveryMode { + type Err = String; + + fn from_str(value: &str) -> Result { + match value { + "poll" => Ok(Self::Poll), + "push" => Ok(Self::Push), + _ => Err(format!( + "invalid config delivery mode '{value}'; expected poll or push" + )), + } + } +} + /// Gateway posture when a sandbox rejects a candidate policy generation. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] @@ -185,6 +209,9 @@ pub struct Config { /// Security posture for rejected sandbox policy generations. pub policy_validation_failure_mode: PolicyValidationFailureMode, + /// Optional shadow push of complete supervisor configuration snapshots. + pub config_delivery_mode: ConfigDeliveryMode, + /// TLS configuration. When `None`, the server listens on plaintext HTTP. pub tls: Option, @@ -851,6 +878,7 @@ impl Config { metrics_bind_address: None, log_level: default_log_level(), policy_validation_failure_mode: PolicyValidationFailureMode::default(), + config_delivery_mode: ConfigDeliveryMode::default(), tls, oidc: None, auth: GatewayAuthConfig::default(), @@ -1116,10 +1144,11 @@ const fn default_ssh_session_ttl_secs() -> u64 { #[cfg(test)] mod tests { use super::{ - AppArmorProfile, Config, DEFAULT_SERVICE_ROUTING_DOMAIN, GatewayInterceptorBindingPolicy, - GatewayInterceptorConfig, GatewayInterceptorFailurePolicy, GatewayJwtConfig, - GatewayProviderProfileSourceConfig, ImagePullPolicy, PolicyValidationFailureMode, - UpstreamProxyConfig, default_sandbox_pids_limit, normalize_compute_driver_name, + AppArmorProfile, Config, ConfigDeliveryMode, DEFAULT_SERVICE_ROUTING_DOMAIN, + GatewayInterceptorBindingPolicy, GatewayInterceptorConfig, GatewayInterceptorFailurePolicy, + GatewayJwtConfig, GatewayProviderProfileSourceConfig, ImagePullPolicy, + PolicyValidationFailureMode, UpstreamProxyConfig, default_sandbox_pids_limit, + normalize_compute_driver_name, }; use std::net::SocketAddr; use std::time::Duration; @@ -1139,6 +1168,19 @@ mod tests { assert!("keep_old".parse::().is_err()); } + #[test] + fn config_delivery_defaults_to_poll_and_rejects_unknown_modes() { + assert_eq!( + Config::new(None).config_delivery_mode, + ConfigDeliveryMode::Poll + ); + assert_eq!( + "push".parse::().unwrap(), + ConfigDeliveryMode::Push + ); + assert!("enabled".parse::().is_err()); + } + #[test] fn compute_driver_name_normalization_accepts_builtin_and_custom_names() { assert_eq!(normalize_compute_driver_name(" VM ").unwrap(), "vm"); diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index 9506160f07..e28bfc107f 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -229,6 +229,13 @@ fn workload_template_proto(name: &str, workspace: &str) -> proto::SandboxWorkloa #[tonic::async_trait] impl OpenShell for TestOpenShell { + async fn peer_notify_config_update( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test server")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/crates/openshell-server/src/auth/method_authz.rs b/crates/openshell-server/src/auth/method_authz.rs index 06f6784cc8..544d2197c9 100644 --- a/crates/openshell-server/src/auth/method_authz.rs +++ b/crates/openshell-server/src/auth/method_authz.rs @@ -155,6 +155,7 @@ mod tests { "/openshell.v1.OpenShell/PeerReportProviderReadiness", "/openshell.v1.OpenShell/PeerReportEndpointStatus", "/openshell.v1.OpenShell/PeerGetSandboxProviderStatus", + "/openshell.v1.OpenShell/PeerNotifyConfigUpdate", ] { assert!(!is_user_callable(path)); assert!(is_peer_callable(path)); diff --git a/crates/openshell-server/src/auth/peer.rs b/crates/openshell-server/src/auth/peer.rs index e9053649a8..06911398a4 100644 --- a/crates/openshell-server/src/auth/peer.rs +++ b/crates/openshell-server/src/auth/peer.rs @@ -715,6 +715,7 @@ mod tests { "/openshell.v1.OpenShell/PeerReportProviderReadiness", "/openshell.v1.OpenShell/PeerReportEndpointStatus", "/openshell.v1.OpenShell/PeerGetSandboxProviderStatus", + "/openshell.v1.OpenShell/PeerNotifyConfigUpdate", ] { assert!(matches!( auth.authenticate(&headers, path).await.unwrap(), @@ -727,7 +728,7 @@ mod tests { .unwrap() .is_none() ); - assert_eq!(resolver.seen_tokens.lock().unwrap().len(), 4); + assert_eq!(resolver.seen_tokens.lock().unwrap().len(), 5); } fn identity() -> ResolvedGatewayPeerIdentity { diff --git a/crates/openshell-server/src/cli.rs b/crates/openshell-server/src/cli.rs index 87b67f5e8a..6418ca316a 100644 --- a/crates/openshell-server/src/cli.rs +++ b/crates/openshell-server/src/cli.rs @@ -6,7 +6,7 @@ use clap::parser::ValueSource; use clap::{ArgAction, ArgMatches, Command, CommandFactory, FromArgMatches, Parser}; use miette::{IntoDiagnostic, Result}; -use openshell_core::config::{DEFAULT_GATEWAY_NAME, DEFAULT_SERVER_PORT}; +use openshell_core::config::{ConfigDeliveryMode, DEFAULT_GATEWAY_NAME, DEFAULT_SERVER_PORT}; use std::collections::BTreeMap; use std::ffi::OsString; use std::net::{IpAddr, SocketAddr}; @@ -239,6 +239,10 @@ struct RunArgs { #[arg(long, env = "OPENSHELL_GRPC_RATE_LIMIT_WINDOW_SECONDS")] grpc_rate_limit_window_seconds: Option, + /// Supervisor configuration delivery. Push sends shadow snapshots in this release. + #[arg(long, env = "OPENSHELL_CONFIG_DELIVERY_MODE")] + config_delivery_mode: Option, + /// Subject Alternative Names configured on the gateway server certificate. /// Wildcard DNS SANs also enable sandbox service URLs under that domain. #[arg( @@ -550,6 +554,13 @@ fn prepare_server_config_with_drivers( { config.policy_validation_failure_mode = mode; } + config.config_delivery_mode = args + .config_delivery_mode + .or_else(|| { + file.as_ref() + .and_then(|f| f.openshell.gateway.config_delivery_mode) + }) + .unwrap_or_default(); if let Some(issuer) = args.oidc_issuer.clone() { config = config.with_oidc(openshell_core::OidcConfig { diff --git a/crates/openshell-server/src/config_delivery.rs b/crates/openshell-server/src/config_delivery.rs index 2437ada722..c9be03d0af 100644 --- a/crates/openshell-server/src/config_delivery.rs +++ b/crates/openshell-server/src/config_delivery.rs @@ -9,17 +9,23 @@ use std::fmt; use std::sync::{Arc, Mutex}; use std::time::Duration; +use futures::StreamExt; use metrics::counter; +use openshell_core::config::ConfigDeliveryMode; use openshell_core::proto::{ - ConfigBootstrap, ProviderEnvironmentSnapshot, Sandbox, SandboxConfigSnapshot, + ConfigBootstrap, PeerConfigSandboxTarget, PeerConfigUpdateHintRequest, + PeerConfigUpdateHintResponse, ProviderEnvironmentSnapshot, Sandbox, SandboxConfigSnapshot, + peer_config_update_hint_request, }; use tokio::sync::{OwnedSemaphorePermit, Semaphore}; -use tonic::{Code, Status}; +use tonic::{Code, Request, Response, Status}; use tracing::warn; use crate::ServerState; +use crate::auth::principal::Principal; use crate::grpc::policy::{build_provider_environment_snapshot, build_sandbox_config_snapshot}; use crate::persistence::ObjectWorkspace; +use crate::supervisor_owner::{OWNER_TTL, SupervisorOwnerIndex}; use crate::supervisor_session::SupervisorSessionRegistry; /// Leaves headroom below tonic's default 4 MiB decode limit for framing and @@ -66,6 +72,7 @@ impl fmt::Debug for SupervisorConfigMessage { pub enum DeliveryDisposition { Enqueued, NoActiveSession, + UnsupportedSession, QueueFull, SessionClosed, PayloadTooLarge, @@ -164,6 +171,7 @@ impl ConfigComponentKind { struct DeliveryKey { sandbox_id: String, component: ConfigComponentKind, + route_remote: bool, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -176,6 +184,7 @@ enum FanoutScope { struct FanoutKey { scope: FanoutScope, component: ConfigComponentKind, + route_remote: bool, } /// Coalesces publications and bounds workers per sandbox and component. @@ -405,14 +414,24 @@ pub fn publish_sandbox_components( sandbox_id: &str, components: ConfigComponents, ) { - enqueue_sandbox(state, sandbox_id, components); + if state.config.config_delivery_mode != ConfigDeliveryMode::Push { + return; + } + enqueue_sandbox(state, sandbox_id, components, true); } -fn enqueue_sandbox(state: &Arc, sandbox_id: &str, components: ConfigComponents) { +fn enqueue_sandbox( + state: &Arc, + sandbox_id: &str, + components: ConfigComponents, + route_remote: bool, +) -> bool { + let mut accepted = true; for component in components.selected() { let key = DeliveryKey { sandbox_id: sandbox_id.to_string(), component, + route_remote, }; match state.config_delivery_queue.enqueue(key.clone()) { DeliveryEnqueue::StartWorker(permit) => { @@ -420,10 +439,12 @@ fn enqueue_sandbox(state: &Arc, sandbox_id: &str, components: Confi } DeliveryEnqueue::Coalesced => {} DeliveryEnqueue::Full => { + accepted = false; record_delivery_worker_full(sandbox_id, component.name()); } } } + accepted } fn spawn_delivery_worker(state: &Arc, key: DeliveryKey, permit: OwnedSemaphorePermit) { @@ -448,6 +469,7 @@ async fn enqueue_sandbox_from_fanout( let key = DeliveryKey { sandbox_id: sandbox_id.to_string(), component, + route_remote: false, }; match state .config_delivery_queue @@ -461,6 +483,18 @@ async fn enqueue_sandbox_from_fanout( } async fn publish_sandbox_component_now(state: &Arc, key: &DeliveryKey) { + if key.route_remote && route_remote_sandbox_component(state, key).await { + return; + } + if !key.route_remote && !is_current_local_owner(state, &key.sandbox_id).await { + return; + } + if !state + .supervisor_sessions + .is_config_push_capable(&key.sandbox_id) + { + return; + } let component = key.component.name(); let build = async { let sandbox = state @@ -501,27 +535,135 @@ async fn publish_sandbox_component_now(state: &Arc, key: &DeliveryK } } +async fn is_current_local_owner(state: &Arc, sandbox_id: &str) -> bool { + let owners = SupervisorOwnerIndex::new(Arc::clone(&state.store), OWNER_TTL); + match owners.read(sandbox_id).await { + Ok(Some(owner)) => { + owner.is_fresh(OWNER_TTL) + && owner.owner_replica_id == state.replica_id + && state + .supervisor_sessions + .is_current_session(sandbox_id, &owner.session_id) + } + Ok(None) => false, + Err(error) => { + warn!(sandbox_id, error = %error, "configuration owner lookup failed"); + false + } + } +} + +/// Return true when the current owner is remote or the session is gone. +/// The owner builds its own snapshot after receiving this secret-free hint. +async fn route_remote_sandbox_component(state: &Arc, key: &DeliveryKey) -> bool { + let owners = SupervisorOwnerIndex::new(Arc::clone(&state.store), OWNER_TTL); + let mut final_outcome = "stale_owner"; + for attempt in 0..2 { + let owner = match owners.read(&key.sandbox_id).await { + Ok(Some(owner)) if owner.is_fresh(OWNER_TTL) => owner, + Ok(_) => return true, + Err(error) => { + warn!(sandbox_id = %key.sandbox_id, error = %error, "configuration owner lookup failed"); + return true; + } + }; + if owner.owner_replica_id == state.replica_id { + return !state + .supervisor_sessions + .is_current_session(&key.sandbox_id, &owner.session_id); + } + if !owner.owner_peer_endpoint.starts_with("http://") + && !owner.owner_peer_endpoint.starts_with("https://") + { + warn!(sandbox_id = %key.sandbox_id, owner = %owner.owner_replica_id, "configuration owner has no reachable peer endpoint"); + return true; + } + let request = PeerConfigUpdateHintRequest { + scope: Some(peer_config_update_hint_request::Scope::Sandbox( + PeerConfigSandboxTarget { + sandbox_id: key.sandbox_id.clone(), + session_id: owner.session_id, + }, + )), + sandbox_config: key.component == ConfigComponentKind::SandboxConfig, + provider_environment: key.component == ConfigComponentKind::ProviderEnvironment, + }; + let result = tokio::time::timeout( + Duration::from_secs(5), + crate::supervisor_session::forward_config_hint_to_peer( + state, + &owner.owner_peer_endpoint, + request, + ), + ) + .await; + match result { + Ok(Ok(response)) if !response.stale_owner && !response.queue_full => { + counter!("openshell_supervisor_config_peer_hints_total", "outcome" => "accepted") + .increment(1); + return true; + } + Ok(Ok(response)) if response.queue_full => { + counter!("openshell_supervisor_config_peer_hints_total", "outcome" => "queue_full") + .increment(1); + return true; + } + Ok(Err(error)) if error.code() == Code::Unimplemented => { + counter!("openshell_supervisor_config_peer_hints_total", "outcome" => "unsupported_peer") + .increment(1); + return true; + } + Ok(Err(error)) => { + final_outcome = "peer_error"; + warn!(sandbox_id = %key.sandbox_id, owner = %owner.owner_replica_id, attempt, code = ?error.code(), "configuration peer hint failed"); + } + Err(_) => { + final_outcome = "timeout"; + warn!(sandbox_id = %key.sandbox_id, owner = %owner.owner_replica_id, attempt, "configuration peer hint timed out"); + } + Ok(Ok(_)) => final_outcome = "stale_owner", + } + } + counter!("openshell_supervisor_config_peer_hints_total", "outcome" => final_outcome) + .increment(1); + true +} + pub fn publish_workspace_components( state: &Arc, workspace: &str, components: ConfigComponents, ) { + if state.config.config_delivery_mode != ConfigDeliveryMode::Push { + return; + } enqueue_fanout( state, FanoutScope::Workspace(workspace.to_string()), components, + true, ); } pub fn publish_all_connected(state: &Arc, components: ConfigComponents) { - enqueue_fanout(state, FanoutScope::AllConnected, components); + if state.config.config_delivery_mode != ConfigDeliveryMode::Push { + return; + } + enqueue_fanout(state, FanoutScope::AllConnected, components, true); } -fn enqueue_fanout(state: &Arc, scope: FanoutScope, components: ConfigComponents) { +fn enqueue_fanout( + state: &Arc, + scope: FanoutScope, + components: ConfigComponents, + route_remote: bool, +) -> bool { + let mut accepted = true; for component in components.selected() { let key = FanoutKey { scope: scope.clone(), component, + route_remote, }; match state.config_delivery_queue.enqueue_fanout(key.clone()) { FanoutEnqueue::StartWorker => { @@ -538,6 +680,7 @@ fn enqueue_fanout(state: &Arc, scope: FanoutScope, components: Conf } FanoutEnqueue::Coalesced => {} FanoutEnqueue::Full => { + accepted = false; counter!("openshell_supervisor_config_fanout_total", "outcome" => "queue_full") .increment(1); warn!( @@ -547,9 +690,13 @@ fn enqueue_fanout(state: &Arc, scope: FanoutScope, components: Conf } } } + accepted } async fn publish_fanout_now(state: &Arc, key: &FanoutKey) { + if key.route_remote { + notify_remote_fanout(state, key).await; + } let sandbox_ids = state .supervisor_config_router() .routable_sandbox_ids() @@ -572,6 +719,126 @@ async fn publish_fanout_now(state: &Arc, key: &FanoutKey) { } } +async fn notify_remote_fanout(state: &Arc, key: &FanoutKey) { + let owners = SupervisorOwnerIndex::new(Arc::clone(&state.store), OWNER_TTL); + let endpoints = match owners.list_fresh_peer_endpoints(&state.replica_id).await { + Ok(endpoints) => endpoints, + Err(error) => { + warn!(error = %error, "configuration peer fanout owner listing failed"); + return; + } + }; + futures::stream::iter(endpoints) + .for_each_concurrent(8, |endpoint| async move { + let scope = match &key.scope { + FanoutScope::Workspace(workspace) => { + peer_config_update_hint_request::Scope::Workspace(workspace.clone()) + } + FanoutScope::AllConnected => { + peer_config_update_hint_request::Scope::AllConnected(true) + } + }; + let request = PeerConfigUpdateHintRequest { + scope: Some(scope), + sandbox_config: key.component == ConfigComponentKind::SandboxConfig, + provider_environment: key.component == ConfigComponentKind::ProviderEnvironment, + }; + let result = tokio::time::timeout( + Duration::from_secs(5), + crate::supervisor_session::forward_config_hint_to_peer(state, &endpoint, request), + ) + .await; + match result { + Ok(Ok(response)) if !response.queue_full => { + counter!("openshell_supervisor_config_peer_hints_total", "outcome" => "accepted") + .increment(1); + } + Ok(Ok(_)) => { + counter!("openshell_supervisor_config_peer_hints_total", "outcome" => "queue_full") + .increment(1); + } + Ok(Err(error)) => { + warn!(endpoint = %endpoint, code = ?error.code(), "configuration peer fanout hint failed"); + } + Err(_) => { + warn!(endpoint = %endpoint, "configuration peer fanout hint timed out"); + } + } + }) + .await; +} + +pub async fn handle_peer_config_update_hint( + state: &Arc, + request: Request, +) -> Result, Status> { + if !matches!( + request.extensions().get::(), + Some(Principal::Peer(_)) + ) { + return Err(Status::permission_denied("gateway peer principal required")); + } + if state.config.config_delivery_mode != ConfigDeliveryMode::Push { + return Err(Status::failed_precondition( + "configuration push is disabled", + )); + } + let hint = request.into_inner(); + let components = ConfigComponents { + sandbox_config: hint.sandbox_config, + provider_environment: hint.provider_environment, + }; + if !components.sandbox_config && !components.provider_environment { + return Err(Status::invalid_argument( + "at least one configuration component is required", + )); + } + let mut response = PeerConfigUpdateHintResponse::default(); + match hint.scope { + Some(peer_config_update_hint_request::Scope::Sandbox(target)) => { + if target.sandbox_id.is_empty() || target.session_id.is_empty() { + return Err(Status::invalid_argument( + "sandbox and session IDs are required", + )); + } + let owners = SupervisorOwnerIndex::new(Arc::clone(&state.store), OWNER_TTL); + let owner = owners + .read(&target.sandbox_id) + .await + .map_err(|_| Status::unavailable("configuration owner lookup failed"))?; + response.stale_owner = owner.is_none_or(|owner| { + !owner.is_fresh(OWNER_TTL) + || owner.owner_replica_id != state.replica_id + || owner.session_id != target.session_id + || !state + .supervisor_sessions + .is_current_session(&target.sandbox_id, &target.session_id) + }); + if !response.stale_owner { + response.queue_full = + !enqueue_sandbox(state, &target.sandbox_id, components, false); + } + } + Some(peer_config_update_hint_request::Scope::Workspace(workspace)) => { + if workspace.is_empty() { + return Err(Status::invalid_argument("workspace is required")); + } + response.queue_full = + !enqueue_fanout(state, FanoutScope::Workspace(workspace), components, false); + } + Some(peer_config_update_hint_request::Scope::AllConnected(true)) => { + response.queue_full = + !enqueue_fanout(state, FanoutScope::AllConnected, components, false); + } + _ => { + return Err(Status::invalid_argument( + "configuration hint scope is required", + )); + } + } + Ok(Response::new(response)) +} + fn record_delivery_worker_full(sandbox_id: &str, component: &'static str) { counter!( "openshell_supervisor_config_delivery_workers_total", @@ -588,6 +855,7 @@ fn record_delivery(component: &'static str, disposition: DeliveryDisposition) { let outcome = match disposition { DeliveryDisposition::Enqueued => "enqueued", DeliveryDisposition::NoActiveSession => "no_active_session", + DeliveryDisposition::UnsupportedSession => "unsupported_session", DeliveryDisposition::QueueFull => "queue_full", DeliveryDisposition::SessionClosed => "session_closed", DeliveryDisposition::PayloadTooLarge => "payload_too_large", @@ -622,10 +890,111 @@ mod tests { use crate::grpc::test_support::{connect_supervisor_stream, test_server_state}; use openshell_core::proto::{GatewayMessage, ObjectMeta, SandboxSpec, gateway_message}; + fn peer_hint(sandbox_id: &str, session_id: &str) -> Request { + let mut request = Request::new(PeerConfigUpdateHintRequest { + scope: Some(peer_config_update_hint_request::Scope::Sandbox( + PeerConfigSandboxTarget { + sandbox_id: sandbox_id.into(), + session_id: session_id.into(), + }, + )), + sandbox_config: true, + provider_environment: false, + }); + request + .extensions_mut() + .insert(Principal::Peer(crate::auth::principal::PeerPrincipal { + replica_id: "other-replica".into(), + pod_uid: "peer-pod".into(), + })); + request + } + + #[tokio::test] + async fn peer_hint_requires_push_and_current_session() { + let mut state = test_server_state().await; + let error = handle_peer_config_update_hint(&state, peer_hint("sandbox", "old-session")) + .await + .unwrap_err(); + assert_eq!(error.code(), Code::FailedPrecondition); + + Arc::get_mut(&mut state) + .unwrap() + .config + .config_delivery_mode = ConfigDeliveryMode::Push; + let response = handle_peer_config_update_hint(&state, peer_hint("sandbox", "old-session")) + .await + .unwrap() + .into_inner(); + assert!(response.stale_owner); + assert!(!response.queue_full); + + let error = handle_peer_config_update_hint( + &state, + Request::new(PeerConfigUpdateHintRequest::default()), + ) + .await + .unwrap_err(); + assert_eq!(error.code(), Code::PermissionDenied); + } + + #[tokio::test] + async fn peer_hint_rebuilds_snapshot_on_the_session_owner() { + let mut state = test_server_state().await; + Arc::get_mut(&mut state) + .unwrap() + .config + .config_delivery_mode = ConfigDeliveryMode::Push; + state + .store + .put_message(&Sandbox { + metadata: Some(ObjectMeta { + id: "owned-sandbox".into(), + name: "owned-sandbox".into(), + workspace: "default".into(), + ..Default::default() + }), + spec: Some(SandboxSpec::default()), + ..Default::default() + }) + .await + .unwrap(); + + let mut harness = connect_supervisor_stream( + &state, + "owned-sandbox", + openshell_core::proto::SUPERVISOR_PROTOCOL_REVISION, + ) + .await + .unwrap(); + let accepted = harness.inbound.message().await.unwrap().unwrap(); + let Some(gateway_message::Payload::SessionAccepted(accepted)) = accepted.payload else { + panic!("expected SessionAccepted"); + }; + let response = handle_peer_config_update_hint( + &state, + peer_hint("owned-sandbox", &accepted.session_id), + ) + .await + .unwrap() + .into_inner(); + assert!(!response.stale_owner && !response.queue_full); + let update = tokio::time::timeout(Duration::from_secs(5), harness.inbound.message()) + .await + .unwrap() + .unwrap() + .unwrap(); + assert!(matches!( + update.payload, + Some(gateway_message::Payload::ConfigUpdate(_)) + )); + } + fn key(sandbox_id: &str, component: ConfigComponentKind) -> DeliveryKey { DeliveryKey { sandbox_id: sandbox_id.to_string(), component, + route_remote: true, } } @@ -784,6 +1153,7 @@ mod tests { let first = FanoutKey { scope: FanoutScope::Workspace("workspace-0".into()), component: ConfigComponentKind::SandboxConfig, + route_remote: true, }; assert_eq!( queue.enqueue_fanout(first.clone()), @@ -801,6 +1171,7 @@ mod tests { queue.enqueue_fanout(FanoutKey { scope: FanoutScope::Workspace(format!("workspace-{index}")), component: ConfigComponentKind::SandboxConfig, + route_remote: true, }), FanoutEnqueue::StartWorker ); @@ -809,6 +1180,7 @@ mod tests { queue.enqueue_fanout(FanoutKey { scope: FanoutScope::Workspace("overflow".into()), component: ConfigComponentKind::SandboxConfig, + route_remote: true, }), FanoutEnqueue::Full ); @@ -829,7 +1201,11 @@ mod tests { #[tokio::test] async fn session_acceptance_precedes_live_configuration_updates() { - let state = test_server_state().await; + let mut state = test_server_state().await; + Arc::get_mut(&mut state) + .unwrap() + .config + .config_delivery_mode = ConfigDeliveryMode::Push; state .store .put_message(&Sandbox { @@ -877,6 +1253,47 @@ mod tests { )); } + #[tokio::test] + async fn legacy_supervisor_keeps_polling_when_gateway_shadow_push_is_enabled() { + let mut state = test_server_state().await; + Arc::get_mut(&mut state) + .unwrap() + .config + .config_delivery_mode = ConfigDeliveryMode::Push; + state + .store + .put_message(&Sandbox { + metadata: Some(ObjectMeta { + id: "legacy-sandbox".into(), + name: "legacy-sandbox".into(), + workspace: "default".into(), + ..Default::default() + }), + spec: Some(SandboxSpec::default()), + ..Default::default() + }) + .await + .unwrap(); + let mut harness = connect_supervisor_stream( + &state, + "legacy-sandbox", + openshell_core::proto::LEGACY_SUPERVISOR_PROTOCOL_REVISION, + ) + .await + .unwrap(); + let first = harness.inbound.message().await.unwrap().unwrap(); + let Some(gateway_message::Payload::SessionAccepted(accepted)) = first.payload else { + panic!("expected SessionAccepted"); + }; + assert!(accepted.bootstrap.is_none()); + publish_sandbox_components(&state, "legacy-sandbox", ConfigComponents::SANDBOX_CONFIG); + assert!( + tokio::time::timeout(Duration::from_millis(100), harness.inbound.message()) + .await + .is_err() + ); + } + #[test] fn bootstrap_requires_matching_provider_revision_fence() { let mut bootstrap = ConfigBootstrap { @@ -902,7 +1319,11 @@ mod tests { async fn stalled_credentials_do_not_block_session_acceptance() { use openshell_core::proto::{CredentialHandle, Provider}; - let state = test_server_state().await; + let mut state = test_server_state().await; + Arc::get_mut(&mut state) + .unwrap() + .config + .config_delivery_mode = ConfigDeliveryMode::Push; state .store .put_message(&Provider { diff --git a/crates/openshell-server/src/config_file.rs b/crates/openshell-server/src/config_file.rs index e442607d9d..cd9700c5ef 100644 --- a/crates/openshell-server/src/config_file.rs +++ b/crates/openshell-server/src/config_file.rs @@ -123,6 +123,9 @@ pub struct GatewayFileSection { /// Security posture when a sandbox rejects a candidate policy generation. #[serde(default)] pub policy_validation_failure_mode: Option, + /// Supervisor configuration delivery; omitted uses the release default. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub config_delivery_mode: Option, // ── Service routing ────────────────────────────────────────────────── /// Subject Alternative Names configured on the gateway server certificate. @@ -1030,6 +1033,29 @@ policy_validation_failure_mode = "keep_old" assert!(error.to_string().contains("policy_validation_failure_mode")); } + #[test] + fn parses_delivery_mode_and_rejects_unknown_value() { + let tmp = write_tmp( + r#" +[openshell.gateway] +config_delivery_mode = "push" +"#, + ); + let file = load(tmp.path()).unwrap(); + assert_eq!( + file.openshell.gateway.config_delivery_mode, + Some(openshell_core::config::ConfigDeliveryMode::Push) + ); + + let tmp = write_tmp( + r#" +[openshell.gateway] +config_delivery_mode = "enabled" +"#, + ); + assert!(load(tmp.path()).is_err()); + } + #[test] fn parses_gateway_auth_config() { let toml = r" diff --git a/crates/openshell-server/src/grpc/mod.rs b/crates/openshell-server/src/grpc/mod.rs index 7ab180b236..3794ac51d8 100644 --- a/crates/openshell-server/src/grpc/mod.rs +++ b/crates/openshell-server/src/grpc/mod.rs @@ -50,7 +50,8 @@ use openshell_core::proto::{ ListSandboxProvidersResponse, ListSandboxTemplatesRequest, ListSandboxTemplatesResponse, ListSandboxesRequest, ListSandboxesResponse, ListServicesRequest, ListServicesResponse, ListWorkspaceMembersRequest, ListWorkspaceMembersResponse, ListWorkspacesRequest, - ListWorkspacesResponse, MemoryResourceCapabilities, NegotiatedExtensionInfo, PeerRelayFrame, + ListWorkspacesResponse, MemoryResourceCapabilities, NegotiatedExtensionInfo, + PeerConfigUpdateHintRequest, PeerConfigUpdateHintResponse, PeerRelayFrame, ProviderProfileResponse, ProviderResponse, PushSandboxLogsRequest, PushSandboxLogsResponse, RefreshSandboxTokenRequest, RefreshSandboxTokenResponse, RejectDraftChunkRequest, RejectDraftChunkResponse, RelayFrame, RemoveWorkspaceMemberRequest, @@ -889,6 +890,13 @@ impl OpenShell for OpenShellService { ) -> Result, Status> { provider_readiness::handle_peer_get_sandbox_provider_status(&self.state, request).await } + + async fn peer_notify_config_update( + &self, + request: Request, + ) -> Result, Status> { + crate::config_delivery::handle_peer_config_update_hint(&self.state, request).await + } } fn public_extension_info(extension: &NegotiatedExtension) -> NegotiatedExtensionInfo { diff --git a/crates/openshell-server/src/grpc/policy.rs b/crates/openshell-server/src/grpc/policy.rs index 451c40e4bb..2356770d9e 100644 --- a/crates/openshell-server/src/grpc/policy.rs +++ b/crates/openshell-server/src/grpc/policy.rs @@ -12732,7 +12732,11 @@ mod tests { #[tokio::test] async fn committed_policy_update_publishes_complete_snapshot() { - let state = test_server_state().await; + let mut state = test_server_state().await; + Arc::get_mut(&mut state) + .unwrap() + .config + .config_delivery_mode = openshell_core::config::ConfigDeliveryMode::Push; let mut sandbox = test_sandbox( "sb-published-policy", "published-policy", @@ -12750,6 +12754,21 @@ mod tests { tx, shutdown_tx, ); + let owner_index = crate::supervisor_owner::SupervisorOwnerIndex::new( + Arc::clone(&state.store), + crate::supervisor_owner::OWNER_TTL, + ); + owner_index + .publish( + "sb-published-policy", + "session-1", + "test-supervisor", + 1, + &state.replica_id, + "local://test", + ) + .await + .unwrap(); handle_update_config( &state, diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index 7feb137cf2..eef3bc0fa3 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -123,13 +123,14 @@ mod tests { // Unspecified (treated as Never), zero count, and absent timestamps. // ProviderProfileFile is reachable from stored provider profiles. Its // additive declaration changes the durable and public/durable overlap - // inventories; the provider-environment file map is public-only. The + // inventories; the provider-environment file map and peer configuration + // hint are public-only. The // request has no provider-file capability field: older supervisors ignore // the additive file map while retaining the rest of the response. // Service authorization also extends both schemas additively. Legacy // payloads retain the safe Strip default. const PUBLIC_RPC_SCHEMA_SHA256: &str = - "746daba65fb2df4b60ba35b7e982946c98cd2c7d3c449f4b6b4f43de5152b3b7"; + "73d5454909634839151b6d47fe4b62793d5426a783517541e91972766cf81aef"; const DURABLE_SCHEMA_SHA256: &str = "38165d9d76f49fcfe98a12f241e032838a2376c1d1a87ea2796fd33b9b1a3541"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = @@ -175,6 +176,9 @@ mod tests { "openshell.v1.OpenShell/PeerReportEndpointStatus|.openshell.v1.ReportEndpointStatusRequest|.openshell.v1.ReportEndpointStatusResponse|false|false", "openshell.v1.OpenShell/PeerReportProviderReadiness|.openshell.v1.ReportProviderReadinessRequest|.openshell.v1.ReportProviderReadinessResponse|false|false", ]; + const PEER_CONFIG_RPC_SIGNATURES: [&str; 1] = [ + "openshell.v1.OpenShell/PeerNotifyConfigUpdate|.openshell.v1.PeerConfigUpdateHintRequest|.openshell.v1.PeerConfigUpdateHintResponse|false|false", + ]; // Synthetic SandboxSpec bytes with log level, provider, and command fields, // emitted before the gateway-owned attachment epoch field was introduced. const PRE_READINESS_SANDBOX_SPEC: &str = @@ -539,14 +543,24 @@ mod tests { "peer owner RPC is missing or changed: {signature}" ); } + for signature in PEER_CONFIG_RPC_SIGNATURES { + assert!( + methods.iter().any(|method| method == signature), + "peer config RPC is missing or changed: {signature}" + ); + } assert_eq!( compiled_method_count, - 102 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len(), + 102 + PROVIDER_READINESS_RPC_SIGNATURES.len() + + PEER_OWNER_RPC_SIGNATURES.len() + + PEER_CONFIG_RPC_SIGNATURES.len(), "classify every compiled RPC" ); assert_eq!( methods.len(), - 77 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len(), + 77 + PROVIDER_READINESS_RPC_SIGNATURES.len() + + PEER_OWNER_RPC_SIGNATURES.len() + + PEER_CONFIG_RPC_SIGNATURES.len(), "inventory every public gateway RPC" ); assert_eq!( @@ -554,7 +568,9 @@ mod tests { .iter() .filter(|method| method.starts_with("openshell.v1.OpenShell/")) .count(), - 77 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len() + 77 + PROVIDER_READINESS_RPC_SIGNATURES.len() + + PEER_OWNER_RPC_SIGNATURES.len() + + PEER_CONFIG_RPC_SIGNATURES.len() ); assert!(methods.iter().all(|method| !method.contains(".storage."))); @@ -598,7 +614,7 @@ mod tests { overlap_hash.as_str(), ), ( - (318, 28), + (321, 28), (93, 21), (81, 21), PUBLIC_RPC_SCHEMA_SHA256, diff --git a/crates/openshell-server/src/supervisor_owner.rs b/crates/openshell-server/src/supervisor_owner.rs index a517bce0fa..dfd2bcb000 100644 --- a/crates/openshell-server/src/supervisor_owner.rs +++ b/crates/openshell-server/src/supervisor_owner.rs @@ -3,12 +3,14 @@ //! Shared supervisor-session ownership index for HA gateway replicas. -use crate::persistence::{PersistenceError, Store, WriteCondition}; +use crate::persistence::{ObjectCursor, ObjectRecord, PersistenceError, Store, WriteCondition}; use openshell_core::time::now_ms; use serde::{Deserialize, Serialize}; +use std::collections::HashSet; use std::sync::Arc; use std::time::{Duration, Instant}; use thiserror::Error; +use tracing::warn; const OWNER_OBJECT_TYPE: &str = "supervisor_session_owner"; @@ -211,18 +213,48 @@ impl SupervisorOwnerIndex { return Ok(None); }; - let payload: OwnerPayload = serde_json::from_slice(&record.payload) - .map_err(|err| PersistenceError::Decode(err.to_string()))?; - Ok(Some(OwnerRecord { - session_id: payload.session_id, - supervisor_instance_id: payload.supervisor_instance_id, - connection_epoch: payload.connection_epoch, - owner_replica_id: payload.owner_replica_id, - owner_peer_endpoint: payload.owner_peer_endpoint, - connected_at_ms: payload.connected_at_ms, - updated_at_ms: record.updated_at_ms, - resource_version: record.resource_version, - })) + Ok(Some(decode_owner_record(&record)?.1)) + } + + /// Return distinct reachable peer endpoints from fresh owner records. + /// The scan uses bounded pages and retains only one endpoint per peer. + pub async fn list_fresh_peer_endpoints( + &self, + local_replica_id: &str, + ) -> Result, OwnerError> { + const PAGE_SIZE: u32 = 256; + let mut after = None; + let mut endpoints = HashSet::new(); + loop { + let page = self + .store + .list_by_type_after(OWNER_OBJECT_TYPE, after.as_ref(), PAGE_SIZE) + .await?; + if page.is_empty() { + break; + } + after = page.last().map(ObjectCursor::from); + for record in &page { + match decode_owner_record(record) { + Ok((_, owner)) + if owner.is_fresh(self.ttl) + && owner.owner_replica_id != local_replica_id + && (owner.owner_peer_endpoint.starts_with("http://") + || owner.owner_peer_endpoint.starts_with("https://")) => + { + endpoints.insert(owner.owner_peer_endpoint); + } + Ok(_) => {} + Err(error) => { + warn!(record_id = %record.id, error = %error, "skipping invalid supervisor owner record"); + } + } + } + if page.len() < PAGE_SIZE as usize { + break; + } + } + Ok(endpoints.into_iter().collect()) } async fn write_payload( @@ -255,6 +287,29 @@ impl SupervisorOwnerIndex { } } +fn decode_owner_record(record: &ObjectRecord) -> Result<(String, OwnerRecord), OwnerError> { + let payload: OwnerPayload = serde_json::from_slice(&record.payload) + .map_err(|err| PersistenceError::Decode(err.to_string()))?; + if payload.sandbox_id != record.name || record.id != owner_object_id(&payload.sandbox_id) { + return Err(OwnerError::Store(PersistenceError::Decode( + "supervisor owner identity mismatch".to_string(), + ))); + } + Ok(( + payload.sandbox_id, + OwnerRecord { + session_id: payload.session_id, + supervisor_instance_id: payload.supervisor_instance_id, + connection_epoch: payload.connection_epoch, + owner_replica_id: payload.owner_replica_id, + owner_peer_endpoint: payload.owner_peer_endpoint, + connected_at_ms: payload.connected_at_ms, + updated_at_ms: record.updated_at_ms, + resource_version: record.resource_version, + }, + )) +} + fn can_supersede( existing: &OwnerRecord, supervisor_instance_id: &str, @@ -348,6 +403,33 @@ mod tests { assert_eq!(record.owner_replica_id, "gw-1"); } + #[tokio::test] + async fn fresh_peer_scan_deduplicates_and_excludes_local_owner() { + let index = test_index(OWNER_TTL).await; + for (sandbox, replica, endpoint) in [ + ("sbx-1", "gw-1", "http://gw-1"), + ("sbx-2", "gw-2", "http://gw-2"), + ("sbx-3", "gw-2", "http://gw-2"), + ("sbx-4", "gw-3", "local://unreachable"), + ] { + index + .publish(sandbox, "session", sandbox, 1, replica, endpoint) + .await + .unwrap(); + } + for index_number in 0..260 { + let sandbox = format!("paged-sandbox-{index_number}"); + index + .publish(&sandbox, "session", &sandbox, 1, "gw-2", "http://gw-2") + .await + .unwrap(); + } + assert_eq!( + index.list_fresh_peer_endpoints("gw-1").await.unwrap(), + vec!["http://gw-2"] + ); + } + #[tokio::test] async fn publish_does_not_collide_with_sandbox_object_id() { let index = test_index(OWNER_TTL).await; diff --git a/crates/openshell-server/src/supervisor_session.rs b/crates/openshell-server/src/supervisor_session.rs index 0bee61b3a0..61d2acd5e2 100644 --- a/crates/openshell-server/src/supervisor_session.rs +++ b/crates/openshell-server/src/supervisor_session.rs @@ -19,12 +19,13 @@ use uuid::Uuid; use openshell_core::proto::{ ConfigUpdate, GatewayMessage, GetSandboxProviderStatusRequest, - GetSandboxProviderStatusResponse, PeerRelayFrame, PeerRelayInit, ProviderReadinessObservation, - RelayFrame, RelayInit, RelayOpen, ReportEndpointStatusRequest, ReportEndpointStatusResponse, - ReportMainProcessExitRequest, ReportMainProcessExitResponse, ReportProviderReadinessRequest, - ReportProviderReadinessResponse, Sandbox, SandboxPhase, SessionAccepted, SshRelayTarget, - SupervisorHello, SupervisorMessage, config_update, gateway_message, open_shell_client, - peer_relay_frame, relay_open, supervisor_message, + GetSandboxProviderStatusResponse, PeerConfigUpdateHintRequest, PeerConfigUpdateHintResponse, + PeerRelayFrame, PeerRelayInit, ProviderReadinessObservation, RelayFrame, RelayInit, RelayOpen, + ReportEndpointStatusRequest, ReportEndpointStatusResponse, ReportMainProcessExitRequest, + ReportMainProcessExitResponse, ReportProviderReadinessRequest, ReportProviderReadinessResponse, + Sandbox, SandboxPhase, SessionAccepted, SshRelayTarget, SupervisorHello, SupervisorMessage, + config_update, gateway_message, open_shell_client, peer_relay_frame, relay_open, + supervisor_message, }; use openshell_core::proto::{LEGACY_SUPERVISOR_PROTOCOL_REVISION, SUPERVISOR_PROTOCOL_REVISION}; use openshell_core::transport_errors::is_expected_transport_close_status; @@ -282,6 +283,7 @@ struct LiveSession { /// Uniquely identifies this session instance. Used by cleanup to avoid /// removing a session that has since been superseded by a reconnect. session_id: String, + config_push_capable: bool, tx: mpsc::Sender, config_sequences: ConfigSequences, /// Fires when this session is superseded by a reconnect so the old session @@ -419,6 +421,17 @@ impl SupervisorSessionRegistry { session_id: String, tx: mpsc::Sender, shutdown: oneshot::Sender<()>, + ) -> bool { + self.register_with_config_push(sandbox_id, session_id, tx, shutdown, true) + } + + pub fn register_with_config_push( + &self, + sandbox_id: String, + session_id: String, + tx: mpsc::Sender, + shutdown: oneshot::Sender<()>, + config_push_capable: bool, ) -> bool { let mut sessions = self.sessions.lock().unwrap(); let previous = sessions.remove(&sandbox_id); @@ -427,6 +440,7 @@ impl SupervisorSessionRegistry { LiveSession { sandbox_id, session_id, + config_push_capable, tx, config_sequences: ConfigSequences::default(), shutdown, @@ -545,7 +559,21 @@ impl SupervisorSessionRegistry { } pub(crate) fn connected_sandbox_ids(&self) -> Vec { - self.sessions.lock().unwrap().keys().cloned().collect() + self.sessions + .lock() + .unwrap() + .iter() + .filter(|(_, session)| session.config_push_capable) + .map(|(sandbox_id, _)| sandbox_id.clone()) + .collect() + } + + pub(crate) fn is_config_push_capable(&self, sandbox_id: &str) -> bool { + self.sessions + .lock() + .unwrap() + .get(sandbox_id) + .is_some_and(|session| session.config_push_capable) } pub(crate) fn deliver_config( @@ -558,6 +586,9 @@ impl SupervisorSessionRegistry { let Some(session) = sessions.get_mut(sandbox_id) else { return DeliveryDisposition::NoActiveSession; }; + if !session.config_push_capable { + return DeliveryDisposition::UnsupportedSession; + } let sequence = match &message { SupervisorConfigMessage::SandboxConfig(_) => { &mut session.config_sequences.sandbox_config @@ -1420,6 +1451,19 @@ async fn peer_rpc_client( )) } +pub(crate) async fn forward_config_hint_to_peer( + state: &Arc, + endpoint: &str, + request: PeerConfigUpdateHintRequest, +) -> Result { + let mut client = peer_rpc_client(state, endpoint).await?; + client + .peer_notify_config_update(request) + .await + .map(Response::into_inner) + .inspect_err(|_| state.peer_routes.evict_channel(endpoint)) +} + pub(crate) async fn remote_supervisor_owner( state: &Arc, sandbox_id: &str, @@ -1947,27 +1991,34 @@ pub async fn handle_connect_supervisor( } let sandbox = require_persisted_sandbox(&state.store, &sandbox_id).await?; - let bootstrap = match crate::config_delivery::build_config_bootstrap(state, &sandbox).await { - Ok(bootstrap) => { - counter!( - "openshell_supervisor_config_bootstrap_total", - "outcome" => "built" - ) - .increment(1); - Some(bootstrap) - } - Err(error) => { - counter!( - "openshell_supervisor_config_bootstrap_total", - "outcome" => "build_failed" - ) - .increment(1); - warn!( - sandbox_id = %sandbox_id, - error_code = ?error.code(), - "failed to build supervisor configuration bootstrap" - ); - None + let bootstrap = if state.config.config_delivery_mode + == openshell_core::config::ConfigDeliveryMode::Poll + || hello.protocol_revision == LEGACY_SUPERVISOR_PROTOCOL_REVISION + { + None + } else { + match crate::config_delivery::build_config_bootstrap(state, &sandbox).await { + Ok(bootstrap) => { + counter!( + "openshell_supervisor_config_bootstrap_total", + "outcome" => "built" + ) + .increment(1); + Some(bootstrap) + } + Err(error) => { + counter!( + "openshell_supervisor_config_bootstrap_total", + "outcome" => "build_failed" + ) + .increment(1); + warn!( + sandbox_id = %sandbox_id, + error_code = ?error.code(), + "failed to build supervisor configuration bootstrap" + ); + None + } } }; // Validate readiness identities before replacing a healthy session. Older @@ -2065,11 +2116,12 @@ async fn establish_supervisor_session( return Err(Status::internal("failed to send session accepted")); } - let superseded = state.supervisor_sessions.register( + let superseded = state.supervisor_sessions.register_with_config_push( sandbox_id.clone(), session_id.clone(), tx.clone(), shutdown_tx, + hello.protocol_revision == SUPERVISOR_PROTOCOL_REVISION, ); if superseded { info!( diff --git a/crates/openshell-server/tests/common/mod.rs b/crates/openshell-server/tests/common/mod.rs index 414251734d..92029347e6 100644 --- a/crates/openshell-server/tests/common/mod.rs +++ b/crates/openshell-server/tests/common/mod.rs @@ -53,6 +53,13 @@ pub struct TestOpenShell; #[tonic::async_trait] impl OpenShell for TestOpenShell { + async fn peer_notify_config_update( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test server")) + } + 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 5856acbbda..4327f31456 100644 --- a/crates/openshell-server/tests/supervisor_relay_integration.rs +++ b/crates/openshell-server/tests/supervisor_relay_integration.rs @@ -48,6 +48,13 @@ struct RelayGateway { #[tonic::async_trait] impl OpenShell for RelayGateway { + async fn peer_notify_config_update( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test server")) + } + async fn peer_report_provider_readiness( &self, _request: tonic::Request, diff --git a/deploy/helm/openshell/README.md b/deploy/helm/openshell/README.md index df3ea173ad..5829e1c964 100644 --- a/deploy/helm/openshell/README.md +++ b/deploy/helm/openshell/README.md @@ -391,6 +391,7 @@ discovery endpoint or its TLS CA. | securityContext.runAsNonRoot | bool | `true` | Require the gateway container to run as a non-root user. | | securityContext.runAsUser | int | `1000` | UID assigned to the gateway container. | | server.auth.allowUnauthenticatedUsers | bool | `false` | UNSAFE: accept unauthenticated CLI/user requests as a local developer principal. Intended only for trusted local Skaffold/k3d development or a fully trusted fronting proxy. Leave false for shared or production clusters. | +| server.configDeliveryMode | string | `""` | Supervisor configuration delivery. Empty uses the gateway release default (poll in 0.1.x). Push enables shadow snapshots in the Stage 1 gateway. | | server.credentialDrivers.kubernetesSecrets.createNamespace | bool | `false` | Create the credential namespace. Requires a namespace other than the release namespace. The Namespace is retained on uninstall so stored credentials survive; an existing Namespace not owned by this release is left untouched. | | server.credentialDrivers.kubernetesSecrets.enabled | bool | `false` | Enable the in-tree Kubernetes Secret credential driver. WARNING: The RBAC Role grants read/write access to ALL Secrets in the configured namespace. Use a dedicated namespace to limit blast radius. | | server.credentialDrivers.kubernetesSecrets.namespace | string | `""` | Namespace where OpenShell-managed provider Secret objects are stored. Empty = Helm release namespace. A dedicated namespace is RECOMMENDED to isolate OpenShell-managed Secrets from other workloads. | diff --git a/deploy/helm/openshell/templates/gateway-config.yaml b/deploy/helm/openshell/templates/gateway-config.yaml index a3e0210a35..6b7b2d2b71 100644 --- a/deploy/helm/openshell/templates/gateway-config.yaml +++ b/deploy/helm/openshell/templates/gateway-config.yaml @@ -46,6 +46,13 @@ data: {{- end }} log_level = {{ .Values.server.logLevel | quote }} compute_driver = "kubernetes" + {{- $configDeliveryMode := .Values.server.configDeliveryMode | default "" }} + {{- if not (has $configDeliveryMode (list "" "poll" "push")) }} + {{- fail "server.configDeliveryMode must be empty, poll, or push" }} + {{- end }} + {{- if $configDeliveryMode }} + config_delivery_mode = {{ $configDeliveryMode | quote }} + {{- end }} {{- if $credentialDrivers }} credential_drivers = [{{- range $i, $driver := $credentialDrivers }}{{ if $i }}, {{ end }}{{ $driver | quote }}{{- end }}] {{- end }} diff --git a/deploy/helm/openshell/values.yaml b/deploy/helm/openshell/values.yaml index 4bf21b88a8..01538f0ac9 100644 --- a/deploy/helm/openshell/values.yaml +++ b/deploy/helm/openshell/values.yaml @@ -258,6 +258,9 @@ affinity: {} # Server configuration server: + # -- Supervisor configuration delivery. Empty uses the gateway release default + # (poll in 0.1.x). Push enables shadow snapshots in the Stage 1 gateway. + configDeliveryMode: "" # -- Operator-facing gateway name. Defaults to the chart fullname so all # replicas in one installation share an identity. Set explicitly when one # telemetry collector receives spans from multiple namespaces or clusters. diff --git a/docs/how-it-works/gateways/configuration.mdx b/docs/how-it-works/gateways/configuration.mdx index d5100071f4..445b6974c5 100644 --- a/docs/how-it-works/gateways/configuration.mdx +++ b/docs/how-it-works/gateways/configuration.mdx @@ -24,7 +24,9 @@ On-disk SQLite databases run in WAL mode with `synchronous=FULL`: the gateway ke ## Supervisor connections and policy recovery -During supervisor reconnects, the gateway waits at most one second for the optional configuration bootstrap. If a credential backend stalls, the gateway accepts the session without that bootstrap so SSH, exec, and service connections can resume. Supervisor polling continues to supply configuration. +When shadow push is enabled, the gateway waits at most one second for an optional configuration bootstrap during supervisor reconnects. If a credential backend stalls, the gateway accepts the session without that bootstrap so SSH, exec, and service connections can resume. Supervisor polling continues to supply configuration. + +In 0.1.x, `[openshell.gateway].config_delivery_mode` defaults to `poll`. Set it to `push` to enable experimental shadow configuration snapshots over the supervisor session. Supervisors in this release still apply configuration by polling, including when the gateway sends shadow snapshots. Set the mode with `--config-delivery-mode`, `OPENSHELL_CONFIG_DELIVERY_MODE`, or Helm `server.configDeliveryMode`. The Helm value is empty by default, so the chart omits the TOML key. During an upgrade, enable `push` only after every gateway replica supports this setting; an older gateway rejects the new TOML key. Keep the mode the same on all HA replicas. On startup, the gateway repairs missing legacy policy history and skips invalid stored policies. A valid global policy can still override an invalid local policy; otherwise, that sandbox's configuration reads continue to report the validation failure. diff --git a/proto/openshell.proto b/proto/openshell.proto index acff5ae5ed..4e76b4afdc 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -623,6 +623,15 @@ service OpenShell { }; } + // Best-effort notification to the replica that owns a supervisor session. + // The receiver rebuilds snapshots from authoritative state. + rpc PeerNotifyConfigUpdate(PeerConfigUpdateHintRequest) + returns (PeerConfigUpdateHintResponse) { + option (openshell.options.v1.authorization) = { + auth_mode: "peer" + }; + } + // Watch a sandbox and stream updates. // // This stream can include: @@ -3210,6 +3219,29 @@ message PeerRelayFrame { } } +message PeerConfigSandboxTarget { + string sandbox_id = 1; + // Fences a targeted hint to the session observed by the sending replica. + string session_id = 2; +} + +message PeerConfigUpdateHintRequest { + oneof scope { + PeerConfigSandboxTarget sandbox = 1; + string workspace = 2; + bool all_connected = 3; + } + bool sandbox_config = 4; + bool provider_environment = 5; +} + +message PeerConfigUpdateHintResponse { + // The targeted session moved before the receiving replica accepted the hint. + bool stale_owner = 1; + // The bounded local delivery or fanout queue could not accept the hint. + bool queue_full = 2; +} + // Supervisor reports the result of a relay open request. message RelayOpenResult { // Channel identifier from the RelayOpen request. diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index 0fc99cf5c1..1167707d5c 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -14999,6 +14999,227 @@ func (*PeerRelayFrame_Init) isPeerRelayFrame_Payload() {} func (*PeerRelayFrame_Data) isPeerRelayFrame_Payload() {} +type PeerConfigSandboxTarget struct { + state protoimpl.MessageState `protogen:"open.v1"` + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + // Fences a targeted hint to the session observed by the sending replica. + SessionId string `protobuf:"bytes,2,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PeerConfigSandboxTarget) Reset() { + *x = PeerConfigSandboxTarget{} + mi := &file_openshell_proto_msgTypes[190] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PeerConfigSandboxTarget) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PeerConfigSandboxTarget) ProtoMessage() {} + +func (x *PeerConfigSandboxTarget) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[190] + 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 PeerConfigSandboxTarget.ProtoReflect.Descriptor instead. +func (*PeerConfigSandboxTarget) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{190} +} + +func (x *PeerConfigSandboxTarget) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +func (x *PeerConfigSandboxTarget) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +type PeerConfigUpdateHintRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Scope: + // + // *PeerConfigUpdateHintRequest_Sandbox + // *PeerConfigUpdateHintRequest_Workspace + // *PeerConfigUpdateHintRequest_AllConnected + Scope isPeerConfigUpdateHintRequest_Scope `protobuf_oneof:"scope"` + SandboxConfig bool `protobuf:"varint,4,opt,name=sandbox_config,json=sandboxConfig,proto3" json:"sandbox_config,omitempty"` + ProviderEnvironment bool `protobuf:"varint,5,opt,name=provider_environment,json=providerEnvironment,proto3" json:"provider_environment,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PeerConfigUpdateHintRequest) Reset() { + *x = PeerConfigUpdateHintRequest{} + mi := &file_openshell_proto_msgTypes[191] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PeerConfigUpdateHintRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PeerConfigUpdateHintRequest) ProtoMessage() {} + +func (x *PeerConfigUpdateHintRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[191] + 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 PeerConfigUpdateHintRequest.ProtoReflect.Descriptor instead. +func (*PeerConfigUpdateHintRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{191} +} + +func (x *PeerConfigUpdateHintRequest) GetScope() isPeerConfigUpdateHintRequest_Scope { + if x != nil { + return x.Scope + } + return nil +} + +func (x *PeerConfigUpdateHintRequest) GetSandbox() *PeerConfigSandboxTarget { + if x != nil { + if x, ok := x.Scope.(*PeerConfigUpdateHintRequest_Sandbox); ok { + return x.Sandbox + } + } + return nil +} + +func (x *PeerConfigUpdateHintRequest) GetWorkspace() string { + if x != nil { + if x, ok := x.Scope.(*PeerConfigUpdateHintRequest_Workspace); ok { + return x.Workspace + } + } + return "" +} + +func (x *PeerConfigUpdateHintRequest) GetAllConnected() bool { + if x != nil { + if x, ok := x.Scope.(*PeerConfigUpdateHintRequest_AllConnected); ok { + return x.AllConnected + } + } + return false +} + +func (x *PeerConfigUpdateHintRequest) GetSandboxConfig() bool { + if x != nil { + return x.SandboxConfig + } + return false +} + +func (x *PeerConfigUpdateHintRequest) GetProviderEnvironment() bool { + if x != nil { + return x.ProviderEnvironment + } + return false +} + +type isPeerConfigUpdateHintRequest_Scope interface { + isPeerConfigUpdateHintRequest_Scope() +} + +type PeerConfigUpdateHintRequest_Sandbox struct { + Sandbox *PeerConfigSandboxTarget `protobuf:"bytes,1,opt,name=sandbox,proto3,oneof"` +} + +type PeerConfigUpdateHintRequest_Workspace struct { + Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3,oneof"` +} + +type PeerConfigUpdateHintRequest_AllConnected struct { + AllConnected bool `protobuf:"varint,3,opt,name=all_connected,json=allConnected,proto3,oneof"` +} + +func (*PeerConfigUpdateHintRequest_Sandbox) isPeerConfigUpdateHintRequest_Scope() {} + +func (*PeerConfigUpdateHintRequest_Workspace) isPeerConfigUpdateHintRequest_Scope() {} + +func (*PeerConfigUpdateHintRequest_AllConnected) isPeerConfigUpdateHintRequest_Scope() {} + +type PeerConfigUpdateHintResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The targeted session moved before the receiving replica accepted the hint. + StaleOwner bool `protobuf:"varint,1,opt,name=stale_owner,json=staleOwner,proto3" json:"stale_owner,omitempty"` + // The bounded local delivery or fanout queue could not accept the hint. + QueueFull bool `protobuf:"varint,2,opt,name=queue_full,json=queueFull,proto3" json:"queue_full,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PeerConfigUpdateHintResponse) Reset() { + *x = PeerConfigUpdateHintResponse{} + mi := &file_openshell_proto_msgTypes[192] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PeerConfigUpdateHintResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PeerConfigUpdateHintResponse) ProtoMessage() {} + +func (x *PeerConfigUpdateHintResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[192] + 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 PeerConfigUpdateHintResponse.ProtoReflect.Descriptor instead. +func (*PeerConfigUpdateHintResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{192} +} + +func (x *PeerConfigUpdateHintResponse) GetStaleOwner() bool { + if x != nil { + return x.StaleOwner + } + return false +} + +func (x *PeerConfigUpdateHintResponse) GetQueueFull() bool { + if x != nil { + return x.QueueFull + } + return false +} + // Supervisor reports the result of a relay open request. type RelayOpenResult struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -15014,7 +15235,7 @@ type RelayOpenResult struct { func (x *RelayOpenResult) Reset() { *x = RelayOpenResult{} - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15026,7 +15247,7 @@ func (x *RelayOpenResult) String() string { func (*RelayOpenResult) ProtoMessage() {} func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[193] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15039,7 +15260,7 @@ func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpenResult.ProtoReflect.Descriptor instead. func (*RelayOpenResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{190} + return file_openshell_proto_rawDescGZIP(), []int{193} } func (x *RelayOpenResult) GetChannelId() string { @@ -15076,7 +15297,7 @@ type RelayClose struct { func (x *RelayClose) Reset() { *x = RelayClose{} - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15088,7 +15309,7 @@ func (x *RelayClose) String() string { func (*RelayClose) ProtoMessage() {} func (x *RelayClose) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[194] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15101,7 +15322,7 @@ func (x *RelayClose) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayClose.ProtoReflect.Descriptor instead. func (*RelayClose) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{191} + return file_openshell_proto_rawDescGZIP(), []int{194} } func (x *RelayClose) GetChannelId() string { @@ -15135,7 +15356,7 @@ type L7RequestSample struct { func (x *L7RequestSample) Reset() { *x = L7RequestSample{} - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15147,7 +15368,7 @@ func (x *L7RequestSample) String() string { func (*L7RequestSample) ProtoMessage() {} func (x *L7RequestSample) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[195] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15160,7 +15381,7 @@ func (x *L7RequestSample) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RequestSample.ProtoReflect.Descriptor instead. func (*L7RequestSample) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{192} + return file_openshell_proto_rawDescGZIP(), []int{195} } func (x *L7RequestSample) GetMethod() string { @@ -15234,7 +15455,7 @@ type DenialSummary struct { func (x *DenialSummary) Reset() { *x = DenialSummary{} - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15246,7 +15467,7 @@ func (x *DenialSummary) String() string { func (*DenialSummary) ProtoMessage() {} func (x *DenialSummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[196] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15259,7 +15480,7 @@ func (x *DenialSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialSummary.ProtoReflect.Descriptor instead. func (*DenialSummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{193} + return file_openshell_proto_rawDescGZIP(), []int{196} } func (x *DenialSummary) GetSandboxId() string { @@ -15394,7 +15615,7 @@ type DenialGroupCount struct { func (x *DenialGroupCount) Reset() { *x = DenialGroupCount{} - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15406,7 +15627,7 @@ func (x *DenialGroupCount) String() string { func (*DenialGroupCount) ProtoMessage() {} func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[197] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15419,7 +15640,7 @@ func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialGroupCount.ProtoReflect.Descriptor instead. func (*DenialGroupCount) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{194} + return file_openshell_proto_rawDescGZIP(), []int{197} } func (x *DenialGroupCount) GetDenyGroup() string { @@ -15452,7 +15673,7 @@ type NetworkActivitySummary struct { func (x *NetworkActivitySummary) Reset() { *x = NetworkActivitySummary{} - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15464,7 +15685,7 @@ func (x *NetworkActivitySummary) String() string { func (*NetworkActivitySummary) ProtoMessage() {} func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[198] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15477,7 +15698,7 @@ func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkActivitySummary.ProtoReflect.Descriptor instead. func (*NetworkActivitySummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{195} + return file_openshell_proto_rawDescGZIP(), []int{198} } func (x *NetworkActivitySummary) GetNetworkActivityCount() uint32 { @@ -15565,7 +15786,7 @@ type PolicyChunk struct { func (x *PolicyChunk) Reset() { *x = PolicyChunk{} - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15577,7 +15798,7 @@ func (x *PolicyChunk) String() string { func (*PolicyChunk) ProtoMessage() {} func (x *PolicyChunk) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[199] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15590,7 +15811,7 @@ func (x *PolicyChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyChunk.ProtoReflect.Descriptor instead. func (*PolicyChunk) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{196} + return file_openshell_proto_rawDescGZIP(), []int{199} } func (x *PolicyChunk) GetId() string { @@ -15778,7 +15999,7 @@ type DraftPolicyUpdate struct { func (x *DraftPolicyUpdate) Reset() { *x = DraftPolicyUpdate{} - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[200] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15790,7 +16011,7 @@ func (x *DraftPolicyUpdate) String() string { func (*DraftPolicyUpdate) ProtoMessage() {} func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[200] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15803,7 +16024,7 @@ func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftPolicyUpdate.ProtoReflect.Descriptor instead. func (*DraftPolicyUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{197} + return file_openshell_proto_rawDescGZIP(), []int{200} } func (x *DraftPolicyUpdate) GetDraftVersion() uint64 { @@ -15862,7 +16083,7 @@ type SubmitPolicyAnalysisRequest struct { func (x *SubmitPolicyAnalysisRequest) Reset() { *x = SubmitPolicyAnalysisRequest{} - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[201] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15874,7 +16095,7 @@ func (x *SubmitPolicyAnalysisRequest) String() string { func (*SubmitPolicyAnalysisRequest) ProtoMessage() {} func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[201] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15887,7 +16108,7 @@ func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisRequest.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{198} + return file_openshell_proto_rawDescGZIP(), []int{201} } func (x *SubmitPolicyAnalysisRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -15950,7 +16171,7 @@ type SubmitPolicyAnalysisResponse struct { func (x *SubmitPolicyAnalysisResponse) Reset() { *x = SubmitPolicyAnalysisResponse{} - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[202] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15962,7 +16183,7 @@ func (x *SubmitPolicyAnalysisResponse) String() string { func (*SubmitPolicyAnalysisResponse) ProtoMessage() {} func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[202] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15975,7 +16196,7 @@ func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisResponse.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{199} + return file_openshell_proto_rawDescGZIP(), []int{202} } func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunks() uint32 { @@ -16020,7 +16241,7 @@ type GetDraftPolicyRequest struct { func (x *GetDraftPolicyRequest) Reset() { *x = GetDraftPolicyRequest{} - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[203] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16032,7 +16253,7 @@ func (x *GetDraftPolicyRequest) String() string { func (*GetDraftPolicyRequest) ProtoMessage() {} func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[203] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16045,7 +16266,7 @@ func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyRequest.ProtoReflect.Descriptor instead. func (*GetDraftPolicyRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{200} + return file_openshell_proto_rawDescGZIP(), []int{203} } func (x *GetDraftPolicyRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16085,7 +16306,7 @@ type GetDraftPolicyResponse struct { func (x *GetDraftPolicyResponse) Reset() { *x = GetDraftPolicyResponse{} - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[204] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16097,7 +16318,7 @@ func (x *GetDraftPolicyResponse) String() string { func (*GetDraftPolicyResponse) ProtoMessage() {} func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[204] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16110,7 +16331,7 @@ func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyResponse.ProtoReflect.Descriptor instead. func (*GetDraftPolicyResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{201} + return file_openshell_proto_rawDescGZIP(), []int{204} } func (x *GetDraftPolicyResponse) GetChunks() []*PolicyChunk { @@ -16161,7 +16382,7 @@ type ApproveDraftChunkRequest struct { func (x *ApproveDraftChunkRequest) Reset() { *x = ApproveDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[205] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16173,7 +16394,7 @@ func (x *ApproveDraftChunkRequest) String() string { func (*ApproveDraftChunkRequest) ProtoMessage() {} func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[205] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16186,7 +16407,7 @@ func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkRequest.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{202} + return file_openshell_proto_rawDescGZIP(), []int{205} } func (x *ApproveDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16236,7 +16457,7 @@ type ApproveDraftChunkResponse struct { func (x *ApproveDraftChunkResponse) Reset() { *x = ApproveDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[206] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16248,7 +16469,7 @@ func (x *ApproveDraftChunkResponse) String() string { func (*ApproveDraftChunkResponse) ProtoMessage() {} func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[206] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16261,7 +16482,7 @@ func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkResponse.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{203} + return file_openshell_proto_rawDescGZIP(), []int{206} } func (x *ApproveDraftChunkResponse) GetPolicyVersion() uint32 { @@ -16297,7 +16518,7 @@ type RejectDraftChunkRequest struct { func (x *RejectDraftChunkRequest) Reset() { *x = RejectDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[207] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16309,7 +16530,7 @@ func (x *RejectDraftChunkRequest) String() string { func (*RejectDraftChunkRequest) ProtoMessage() {} func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[207] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16322,7 +16543,7 @@ func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkRequest.ProtoReflect.Descriptor instead. func (*RejectDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{204} + return file_openshell_proto_rawDescGZIP(), []int{207} } func (x *RejectDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16368,7 +16589,7 @@ type RejectDraftChunkResponse struct { func (x *RejectDraftChunkResponse) Reset() { *x = RejectDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[208] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16380,7 +16601,7 @@ func (x *RejectDraftChunkResponse) String() string { func (*RejectDraftChunkResponse) ProtoMessage() {} func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[208] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16393,7 +16614,7 @@ func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkResponse.ProtoReflect.Descriptor instead. func (*RejectDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{205} + return file_openshell_proto_rawDescGZIP(), []int{208} } // Approve all pending chunks. @@ -16407,7 +16628,7 @@ type DraftChunkApproval struct { func (x *DraftChunkApproval) Reset() { *x = DraftChunkApproval{} - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[209] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16419,7 +16640,7 @@ func (x *DraftChunkApproval) String() string { func (*DraftChunkApproval) ProtoMessage() {} func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[209] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16432,7 +16653,7 @@ func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftChunkApproval.ProtoReflect.Descriptor instead. func (*DraftChunkApproval) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{206} + return file_openshell_proto_rawDescGZIP(), []int{209} } func (x *DraftChunkApproval) GetChunkId() string { @@ -16468,7 +16689,7 @@ type ApproveAllDraftChunksRequest struct { func (x *ApproveAllDraftChunksRequest) Reset() { *x = ApproveAllDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[210] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16480,7 +16701,7 @@ func (x *ApproveAllDraftChunksRequest) String() string { func (*ApproveAllDraftChunksRequest) ProtoMessage() {} func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[210] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16493,7 +16714,7 @@ func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{207} + return file_openshell_proto_rawDescGZIP(), []int{210} } func (x *ApproveAllDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16548,7 +16769,7 @@ type ApproveAllDraftChunksResponse struct { func (x *ApproveAllDraftChunksResponse) Reset() { *x = ApproveAllDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[211] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16560,7 +16781,7 @@ func (x *ApproveAllDraftChunksResponse) String() string { func (*ApproveAllDraftChunksResponse) ProtoMessage() {} func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[211] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16573,7 +16794,7 @@ func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{208} + return file_openshell_proto_rawDescGZIP(), []int{211} } func (x *ApproveAllDraftChunksResponse) GetPolicyVersion() uint32 { @@ -16623,7 +16844,7 @@ type EditDraftChunkRequest struct { func (x *EditDraftChunkRequest) Reset() { *x = EditDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[212] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16635,7 +16856,7 @@ func (x *EditDraftChunkRequest) String() string { func (*EditDraftChunkRequest) ProtoMessage() {} func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[212] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16648,7 +16869,7 @@ func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkRequest.ProtoReflect.Descriptor instead. func (*EditDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{209} + return file_openshell_proto_rawDescGZIP(), []int{212} } func (x *EditDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16694,7 +16915,7 @@ type EditDraftChunkResponse struct { func (x *EditDraftChunkResponse) Reset() { *x = EditDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[213] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16706,7 +16927,7 @@ func (x *EditDraftChunkResponse) String() string { func (*EditDraftChunkResponse) ProtoMessage() {} func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[213] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16719,7 +16940,7 @@ func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkResponse.ProtoReflect.Descriptor instead. func (*EditDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{210} + return file_openshell_proto_rawDescGZIP(), []int{213} } // Reverse an approval (remove merged rule from active policy). @@ -16739,7 +16960,7 @@ type UndoDraftChunkRequest struct { func (x *UndoDraftChunkRequest) Reset() { *x = UndoDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[214] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16751,7 +16972,7 @@ func (x *UndoDraftChunkRequest) String() string { func (*UndoDraftChunkRequest) ProtoMessage() {} func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[214] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16764,7 +16985,7 @@ func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkRequest.ProtoReflect.Descriptor instead. func (*UndoDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{211} + return file_openshell_proto_rawDescGZIP(), []int{214} } func (x *UndoDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16807,7 +17028,7 @@ type UndoDraftChunkResponse struct { func (x *UndoDraftChunkResponse) Reset() { *x = UndoDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[215] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16819,7 +17040,7 @@ func (x *UndoDraftChunkResponse) String() string { func (*UndoDraftChunkResponse) ProtoMessage() {} func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[215] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16832,7 +17053,7 @@ func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkResponse.ProtoReflect.Descriptor instead. func (*UndoDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{212} + return file_openshell_proto_rawDescGZIP(), []int{215} } func (x *UndoDraftChunkResponse) GetPolicyVersion() uint32 { @@ -16864,7 +17085,7 @@ type ClearDraftChunksRequest struct { func (x *ClearDraftChunksRequest) Reset() { *x = ClearDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[216] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16876,7 +17097,7 @@ func (x *ClearDraftChunksRequest) String() string { func (*ClearDraftChunksRequest) ProtoMessage() {} func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[216] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16889,7 +17110,7 @@ func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ClearDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{213} + return file_openshell_proto_rawDescGZIP(), []int{216} } func (x *ClearDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16923,7 +17144,7 @@ type ClearDraftChunksResponse struct { func (x *ClearDraftChunksResponse) Reset() { *x = ClearDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[217] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16935,7 +17156,7 @@ func (x *ClearDraftChunksResponse) String() string { func (*ClearDraftChunksResponse) ProtoMessage() {} func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[217] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16948,7 +17169,7 @@ func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ClearDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{214} + return file_openshell_proto_rawDescGZIP(), []int{217} } func (x *ClearDraftChunksResponse) GetChunksCleared() uint32 { @@ -16970,7 +17191,7 @@ type GetDraftHistoryRequest struct { func (x *GetDraftHistoryRequest) Reset() { *x = GetDraftHistoryRequest{} - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[218] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16982,7 +17203,7 @@ func (x *GetDraftHistoryRequest) String() string { func (*GetDraftHistoryRequest) ProtoMessage() {} func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[218] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16995,7 +17216,7 @@ func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryRequest.ProtoReflect.Descriptor instead. func (*GetDraftHistoryRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{215} + return file_openshell_proto_rawDescGZIP(), []int{218} } func (x *GetDraftHistoryRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17029,7 +17250,7 @@ type DraftHistoryEntry struct { func (x *DraftHistoryEntry) Reset() { *x = DraftHistoryEntry{} - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[219] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17041,7 +17262,7 @@ func (x *DraftHistoryEntry) String() string { func (*DraftHistoryEntry) ProtoMessage() {} func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[219] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17054,7 +17275,7 @@ func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftHistoryEntry.ProtoReflect.Descriptor instead. func (*DraftHistoryEntry) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{216} + return file_openshell_proto_rawDescGZIP(), []int{219} } func (x *DraftHistoryEntry) GetEventTime() *timestamppb.Timestamp { @@ -17095,7 +17316,7 @@ type GetDraftHistoryResponse struct { func (x *GetDraftHistoryResponse) Reset() { *x = GetDraftHistoryResponse{} - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[220] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17107,7 +17328,7 @@ func (x *GetDraftHistoryResponse) String() string { func (*GetDraftHistoryResponse) ProtoMessage() {} func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[220] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17120,7 +17341,7 @@ func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryResponse.ProtoReflect.Descriptor instead. func (*GetDraftHistoryResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{217} + return file_openshell_proto_rawDescGZIP(), []int{220} } func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry { @@ -17145,7 +17366,7 @@ type CreateWorkspaceRequest struct { func (x *CreateWorkspaceRequest) Reset() { *x = CreateWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[221] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17157,7 +17378,7 @@ func (x *CreateWorkspaceRequest) String() string { func (*CreateWorkspaceRequest) ProtoMessage() {} func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[221] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17170,7 +17391,7 @@ func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceRequest.ProtoReflect.Descriptor instead. func (*CreateWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{218} + return file_openshell_proto_rawDescGZIP(), []int{221} } func (x *CreateWorkspaceRequest) GetName() string { @@ -17204,7 +17425,7 @@ type CreateWorkspaceResponse struct { func (x *CreateWorkspaceResponse) Reset() { *x = CreateWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[222] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17216,7 +17437,7 @@ func (x *CreateWorkspaceResponse) String() string { func (*CreateWorkspaceResponse) ProtoMessage() {} func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[222] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17229,7 +17450,7 @@ func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceResponse.ProtoReflect.Descriptor instead. func (*CreateWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{219} + return file_openshell_proto_rawDescGZIP(), []int{222} } func (x *CreateWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -17250,7 +17471,7 @@ type GetWorkspaceRequest struct { func (x *GetWorkspaceRequest) Reset() { *x = GetWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[223] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17262,7 +17483,7 @@ func (x *GetWorkspaceRequest) String() string { func (*GetWorkspaceRequest) ProtoMessage() {} func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[223] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17275,7 +17496,7 @@ func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceRequest.ProtoReflect.Descriptor instead. func (*GetWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{220} + return file_openshell_proto_rawDescGZIP(), []int{223} } func (x *GetWorkspaceRequest) GetName() string { @@ -17295,7 +17516,7 @@ type GetWorkspaceResponse struct { func (x *GetWorkspaceResponse) Reset() { *x = GetWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[224] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17307,7 +17528,7 @@ func (x *GetWorkspaceResponse) String() string { func (*GetWorkspaceResponse) ProtoMessage() {} func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[224] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17320,7 +17541,7 @@ func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceResponse.ProtoReflect.Descriptor instead. func (*GetWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{221} + return file_openshell_proto_rawDescGZIP(), []int{224} } func (x *GetWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -17347,7 +17568,7 @@ type ListWorkspacesRequest struct { func (x *ListWorkspacesRequest) Reset() { *x = ListWorkspacesRequest{} - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[225] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17359,7 +17580,7 @@ func (x *ListWorkspacesRequest) String() string { func (*ListWorkspacesRequest) ProtoMessage() {} func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[225] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17372,7 +17593,7 @@ func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesRequest.ProtoReflect.Descriptor instead. func (*ListWorkspacesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{222} + return file_openshell_proto_rawDescGZIP(), []int{225} } func (x *ListWorkspacesRequest) GetPageSize() int32 { @@ -17408,7 +17629,7 @@ type ListWorkspacesResponse struct { func (x *ListWorkspacesResponse) Reset() { *x = ListWorkspacesResponse{} - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[226] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17420,7 +17641,7 @@ func (x *ListWorkspacesResponse) String() string { func (*ListWorkspacesResponse) ProtoMessage() {} func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[226] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17433,7 +17654,7 @@ func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesResponse.ProtoReflect.Descriptor instead. func (*ListWorkspacesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{223} + return file_openshell_proto_rawDescGZIP(), []int{226} } func (x *ListWorkspacesResponse) GetWorkspaces() []*datamodelv1.Workspace { @@ -17464,7 +17685,7 @@ type DeleteWorkspaceRequest struct { func (x *DeleteWorkspaceRequest) Reset() { *x = DeleteWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[227] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17476,7 +17697,7 @@ func (x *DeleteWorkspaceRequest) String() string { func (*DeleteWorkspaceRequest) ProtoMessage() {} func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[227] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17489,7 +17710,7 @@ func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{224} + return file_openshell_proto_rawDescGZIP(), []int{227} } func (x *DeleteWorkspaceRequest) GetName() string { @@ -17523,7 +17744,7 @@ type DeleteWorkspaceResponse struct { func (x *DeleteWorkspaceResponse) Reset() { *x = DeleteWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[228] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17535,7 +17756,7 @@ func (x *DeleteWorkspaceResponse) String() string { func (*DeleteWorkspaceResponse) ProtoMessage() {} func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[228] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17548,7 +17769,7 @@ func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceResponse.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{225} + return file_openshell_proto_rawDescGZIP(), []int{228} } func (x *DeleteWorkspaceResponse) GetOutcome() DeletionOutcome { @@ -17572,7 +17793,7 @@ type WorkspaceMember struct { func (x *WorkspaceMember) Reset() { *x = WorkspaceMember{} - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[229] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17584,7 +17805,7 @@ func (x *WorkspaceMember) String() string { func (*WorkspaceMember) ProtoMessage() {} func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[229] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17597,7 +17818,7 @@ func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkspaceMember.ProtoReflect.Descriptor instead. func (*WorkspaceMember) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{226} + return file_openshell_proto_rawDescGZIP(), []int{229} } func (x *WorkspaceMember) GetMetadata() *datamodelv1.ObjectMeta { @@ -17638,7 +17859,7 @@ type AddWorkspaceMemberRequest struct { func (x *AddWorkspaceMemberRequest) Reset() { *x = AddWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[230] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17650,7 +17871,7 @@ func (x *AddWorkspaceMemberRequest) String() string { func (*AddWorkspaceMemberRequest) ProtoMessage() {} func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[230] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17663,7 +17884,7 @@ func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{227} + return file_openshell_proto_rawDescGZIP(), []int{230} } func (x *AddWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17704,7 +17925,7 @@ type AddWorkspaceMemberResponse struct { func (x *AddWorkspaceMemberResponse) Reset() { *x = AddWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[231] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17716,7 +17937,7 @@ func (x *AddWorkspaceMemberResponse) String() string { func (*AddWorkspaceMemberResponse) ProtoMessage() {} func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[231] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17729,7 +17950,7 @@ func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{228} + return file_openshell_proto_rawDescGZIP(), []int{231} } func (x *AddWorkspaceMemberResponse) GetMember() *WorkspaceMember { @@ -17755,7 +17976,7 @@ type RemoveWorkspaceMemberRequest struct { func (x *RemoveWorkspaceMemberRequest) Reset() { *x = RemoveWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[232] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17767,7 +17988,7 @@ func (x *RemoveWorkspaceMemberRequest) String() string { func (*RemoveWorkspaceMemberRequest) ProtoMessage() {} func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[232] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17780,7 +18001,7 @@ func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{229} + return file_openshell_proto_rawDescGZIP(), []int{232} } func (x *RemoveWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17821,7 +18042,7 @@ type RemoveWorkspaceMemberResponse struct { func (x *RemoveWorkspaceMemberResponse) Reset() { *x = RemoveWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[233] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17833,7 +18054,7 @@ func (x *RemoveWorkspaceMemberResponse) String() string { func (*RemoveWorkspaceMemberResponse) ProtoMessage() {} func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[233] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17846,7 +18067,7 @@ func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{230} + return file_openshell_proto_rawDescGZIP(), []int{233} } func (x *RemoveWorkspaceMemberResponse) GetOutcome() DeletionOutcome { @@ -17873,7 +18094,7 @@ type ListWorkspaceMembersRequest struct { func (x *ListWorkspaceMembersRequest) Reset() { *x = ListWorkspaceMembersRequest{} - mi := &file_openshell_proto_msgTypes[231] + mi := &file_openshell_proto_msgTypes[234] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17885,7 +18106,7 @@ func (x *ListWorkspaceMembersRequest) String() string { func (*ListWorkspaceMembersRequest) ProtoMessage() {} func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[231] + mi := &file_openshell_proto_msgTypes[234] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17898,7 +18119,7 @@ func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersRequest.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{231} + return file_openshell_proto_rawDescGZIP(), []int{234} } func (x *ListWorkspaceMembersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17934,7 +18155,7 @@ type ListWorkspaceMembersResponse struct { func (x *ListWorkspaceMembersResponse) Reset() { *x = ListWorkspaceMembersResponse{} - mi := &file_openshell_proto_msgTypes[232] + mi := &file_openshell_proto_msgTypes[235] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17946,7 +18167,7 @@ func (x *ListWorkspaceMembersResponse) String() string { func (*ListWorkspaceMembersResponse) ProtoMessage() {} func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[232] + mi := &file_openshell_proto_msgTypes[235] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17959,7 +18180,7 @@ func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersResponse.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{232} + return file_openshell_proto_rawDescGZIP(), []int{235} } func (x *ListWorkspaceMembersResponse) GetMembers() []*WorkspaceMember { @@ -17994,7 +18215,7 @@ type ExtensionServiceCredential struct { func (x *ExtensionServiceCredential) Reset() { *x = ExtensionServiceCredential{} - mi := &file_openshell_proto_msgTypes[233] + mi := &file_openshell_proto_msgTypes[236] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18006,7 +18227,7 @@ func (x *ExtensionServiceCredential) String() string { func (*ExtensionServiceCredential) ProtoMessage() {} func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[233] + mi := &file_openshell_proto_msgTypes[236] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18019,7 +18240,7 @@ func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionServiceCredential.ProtoReflect.Descriptor instead. func (*ExtensionServiceCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{233} + return file_openshell_proto_rawDescGZIP(), []int{236} } func (x *ExtensionServiceCredential) GetServiceName() string { @@ -18056,7 +18277,7 @@ type EndpointObservation struct { func (x *EndpointObservation) Reset() { *x = EndpointObservation{} - mi := &file_openshell_proto_msgTypes[234] + mi := &file_openshell_proto_msgTypes[237] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18068,7 +18289,7 @@ func (x *EndpointObservation) String() string { func (*EndpointObservation) ProtoMessage() {} func (x *EndpointObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[234] + mi := &file_openshell_proto_msgTypes[237] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18081,7 +18302,7 @@ func (x *EndpointObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointObservation.ProtoReflect.Descriptor instead. func (*EndpointObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{234} + return file_openshell_proto_rawDescGZIP(), []int{237} } func (x *EndpointObservation) GetEndpointId() string { @@ -18124,7 +18345,7 @@ type ReportEndpointStatusRequest struct { func (x *ReportEndpointStatusRequest) Reset() { *x = ReportEndpointStatusRequest{} - mi := &file_openshell_proto_msgTypes[235] + mi := &file_openshell_proto_msgTypes[238] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18136,7 +18357,7 @@ func (x *ReportEndpointStatusRequest) String() string { func (*ReportEndpointStatusRequest) ProtoMessage() {} func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[235] + mi := &file_openshell_proto_msgTypes[238] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18149,7 +18370,7 @@ func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusRequest.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{235} + return file_openshell_proto_rawDescGZIP(), []int{238} } func (x *ReportEndpointStatusRequest) GetSandboxId() string { @@ -18210,7 +18431,7 @@ type ReportEndpointStatusResponse struct { func (x *ReportEndpointStatusResponse) Reset() { *x = ReportEndpointStatusResponse{} - mi := &file_openshell_proto_msgTypes[236] + mi := &file_openshell_proto_msgTypes[239] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18222,7 +18443,7 @@ func (x *ReportEndpointStatusResponse) String() string { func (*ReportEndpointStatusResponse) ProtoMessage() {} func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[236] + mi := &file_openshell_proto_msgTypes[239] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18235,7 +18456,7 @@ func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusResponse.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{236} + return file_openshell_proto_rawDescGZIP(), []int{239} } // A configured endpoint and its last accepted network result in one record. @@ -18264,7 +18485,7 @@ type EndpointStatus struct { func (x *EndpointStatus) Reset() { *x = EndpointStatus{} - mi := &file_openshell_proto_msgTypes[237] + mi := &file_openshell_proto_msgTypes[240] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18276,7 +18497,7 @@ func (x *EndpointStatus) String() string { func (*EndpointStatus) ProtoMessage() {} func (x *EndpointStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[237] + mi := &file_openshell_proto_msgTypes[240] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18289,7 +18510,7 @@ func (x *EndpointStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointStatus.ProtoReflect.Descriptor instead. func (*EndpointStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{237} + return file_openshell_proto_rawDescGZIP(), []int{240} } func (x *EndpointStatus) GetEndpointId() string { @@ -18359,7 +18580,7 @@ type SandboxProvisioning struct { func (x *SandboxProvisioning) Reset() { *x = SandboxProvisioning{} - mi := &file_openshell_proto_msgTypes[238] + mi := &file_openshell_proto_msgTypes[241] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18371,7 +18592,7 @@ func (x *SandboxProvisioning) String() string { func (*SandboxProvisioning) ProtoMessage() {} func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[238] + mi := &file_openshell_proto_msgTypes[241] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18384,7 +18605,7 @@ func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxProvisioning.ProtoReflect.Descriptor instead. func (*SandboxProvisioning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{238} + return file_openshell_proto_rawDescGZIP(), []int{241} } func (x *SandboxProvisioning) GetAttemptId() string { @@ -18479,7 +18700,7 @@ type SandboxServiceExposure struct { func (x *SandboxServiceExposure) Reset() { *x = SandboxServiceExposure{} - mi := &file_openshell_proto_msgTypes[239] + mi := &file_openshell_proto_msgTypes[242] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18491,7 +18712,7 @@ func (x *SandboxServiceExposure) String() string { func (*SandboxServiceExposure) ProtoMessage() {} func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[239] + mi := &file_openshell_proto_msgTypes[242] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18504,7 +18725,7 @@ func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxServiceExposure.ProtoReflect.Descriptor instead. func (*SandboxServiceExposure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{239} + return file_openshell_proto_rawDescGZIP(), []int{242} } func (x *SandboxServiceExposure) GetService() string { @@ -19636,7 +19857,24 @@ const file_openshell_proto_rawDesc = "" + "\x0ePeerRelayFrame\x121\n" + "\x04init\x18\x01 \x01(\v2\x1b.openshell.v1.PeerRelayInitH\x00R\x04init\x12\x14\n" + "\x04data\x18\x02 \x01(\fH\x00R\x04dataB\t\n" + - "\apayload\"`\n" + + "\apayload\"W\n" + + "\x17PeerConfigSandboxTarget\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x1d\n" + + "\n" + + "session_id\x18\x02 \x01(\tR\tsessionId\"\x8a\x02\n" + + "\x1bPeerConfigUpdateHintRequest\x12A\n" + + "\asandbox\x18\x01 \x01(\v2%.openshell.v1.PeerConfigSandboxTargetH\x00R\asandbox\x12\x1e\n" + + "\tworkspace\x18\x02 \x01(\tH\x00R\tworkspace\x12%\n" + + "\rall_connected\x18\x03 \x01(\bH\x00R\fallConnected\x12%\n" + + "\x0esandbox_config\x18\x04 \x01(\bR\rsandboxConfig\x121\n" + + "\x14provider_environment\x18\x05 \x01(\bR\x13providerEnvironmentB\a\n" + + "\x05scope\"^\n" + + "\x1cPeerConfigUpdateHintResponse\x12\x1f\n" + + "\vstale_owner\x18\x01 \x01(\bR\n" + + "staleOwner\x12\x1d\n" + + "\n" + + "queue_full\x18\x02 \x01(\bR\tqueueFull\"`\n" + "\x0fRelayOpenResult\x12\x1d\n" + "\n" + "channel_id\x18\x01 \x01(\tR\tchannelId\x12\x18\n" + @@ -20065,7 +20303,7 @@ const file_openshell_proto_rawDesc = "" + "\x18ServiceAuthorizationMode\x12*\n" + "&SERVICE_AUTHORIZATION_MODE_UNSPECIFIED\x10\x00\x12$\n" + " SERVICE_AUTHORIZATION_MODE_STRIP\x10\x01\x121\n" + - "-SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH\x10\x022\xafU\n" + + "-SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH\x10\x022\xacV\n" + "\tOpenShell\x12Z\n" + "\x06Health\x12\x1b.openshell.v1.HealthRequest\x1a\x1c.openshell.v1.HealthResponse\"\x15\x82\xb5\x18\x11\n" + "\x0funauthenticated\x12i\n" + @@ -20199,6 +20437,9 @@ const file_openshell_proto_rawDesc = "" + "\x04peer\x12\x89\x01\n" + "\x1cPeerGetSandboxProviderStatus\x12-.openshell.v1.GetSandboxProviderStatusRequest\x1a..openshell.v1.GetSandboxProviderStatusResponse\"\n" + "\x82\xb5\x18\x06\n" + + "\x04peer\x12{\n" + + "\x16PeerNotifyConfigUpdate\x12).openshell.v1.PeerConfigUpdateHintRequest\x1a*.openshell.v1.PeerConfigUpdateHintResponse\"\n" + + "\x82\xb5\x18\x06\n" + "\x04peer\x12w\n" + "\fWatchSandbox\x12!.openshell.v1.WatchSandboxRequest\x1a .openshell.v1.SandboxStreamEvent\" \x82\xb5\x18\x1c\n" + "\x06bearer\x12\x04user\"\fsandbox:read0\x01\x12|\n" + @@ -20252,7 +20493,7 @@ func file_openshell_proto_rawDescGZIP() []byte { } var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 21) -var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 265) +var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 268) var file_openshell_proto_goTypes = []any{ (ExtensionKind)(0), // 0: openshell.v1.ExtensionKind (SandboxPhase)(0), // 1: openshell.v1.SandboxPhase @@ -20465,107 +20706,110 @@ var file_openshell_proto_goTypes = []any{ (*RelayFrame)(nil), // 208: openshell.v1.RelayFrame (*PeerRelayInit)(nil), // 209: openshell.v1.PeerRelayInit (*PeerRelayFrame)(nil), // 210: openshell.v1.PeerRelayFrame - (*RelayOpenResult)(nil), // 211: openshell.v1.RelayOpenResult - (*RelayClose)(nil), // 212: openshell.v1.RelayClose - (*L7RequestSample)(nil), // 213: openshell.v1.L7RequestSample - (*DenialSummary)(nil), // 214: openshell.v1.DenialSummary - (*DenialGroupCount)(nil), // 215: openshell.v1.DenialGroupCount - (*NetworkActivitySummary)(nil), // 216: openshell.v1.NetworkActivitySummary - (*PolicyChunk)(nil), // 217: openshell.v1.PolicyChunk - (*DraftPolicyUpdate)(nil), // 218: openshell.v1.DraftPolicyUpdate - (*SubmitPolicyAnalysisRequest)(nil), // 219: openshell.v1.SubmitPolicyAnalysisRequest - (*SubmitPolicyAnalysisResponse)(nil), // 220: openshell.v1.SubmitPolicyAnalysisResponse - (*GetDraftPolicyRequest)(nil), // 221: openshell.v1.GetDraftPolicyRequest - (*GetDraftPolicyResponse)(nil), // 222: openshell.v1.GetDraftPolicyResponse - (*ApproveDraftChunkRequest)(nil), // 223: openshell.v1.ApproveDraftChunkRequest - (*ApproveDraftChunkResponse)(nil), // 224: openshell.v1.ApproveDraftChunkResponse - (*RejectDraftChunkRequest)(nil), // 225: openshell.v1.RejectDraftChunkRequest - (*RejectDraftChunkResponse)(nil), // 226: openshell.v1.RejectDraftChunkResponse - (*DraftChunkApproval)(nil), // 227: openshell.v1.DraftChunkApproval - (*ApproveAllDraftChunksRequest)(nil), // 228: openshell.v1.ApproveAllDraftChunksRequest - (*ApproveAllDraftChunksResponse)(nil), // 229: openshell.v1.ApproveAllDraftChunksResponse - (*EditDraftChunkRequest)(nil), // 230: openshell.v1.EditDraftChunkRequest - (*EditDraftChunkResponse)(nil), // 231: openshell.v1.EditDraftChunkResponse - (*UndoDraftChunkRequest)(nil), // 232: openshell.v1.UndoDraftChunkRequest - (*UndoDraftChunkResponse)(nil), // 233: openshell.v1.UndoDraftChunkResponse - (*ClearDraftChunksRequest)(nil), // 234: openshell.v1.ClearDraftChunksRequest - (*ClearDraftChunksResponse)(nil), // 235: openshell.v1.ClearDraftChunksResponse - (*GetDraftHistoryRequest)(nil), // 236: openshell.v1.GetDraftHistoryRequest - (*DraftHistoryEntry)(nil), // 237: openshell.v1.DraftHistoryEntry - (*GetDraftHistoryResponse)(nil), // 238: openshell.v1.GetDraftHistoryResponse - (*CreateWorkspaceRequest)(nil), // 239: openshell.v1.CreateWorkspaceRequest - (*CreateWorkspaceResponse)(nil), // 240: openshell.v1.CreateWorkspaceResponse - (*GetWorkspaceRequest)(nil), // 241: openshell.v1.GetWorkspaceRequest - (*GetWorkspaceResponse)(nil), // 242: openshell.v1.GetWorkspaceResponse - (*ListWorkspacesRequest)(nil), // 243: openshell.v1.ListWorkspacesRequest - (*ListWorkspacesResponse)(nil), // 244: openshell.v1.ListWorkspacesResponse - (*DeleteWorkspaceRequest)(nil), // 245: openshell.v1.DeleteWorkspaceRequest - (*DeleteWorkspaceResponse)(nil), // 246: openshell.v1.DeleteWorkspaceResponse - (*WorkspaceMember)(nil), // 247: openshell.v1.WorkspaceMember - (*AddWorkspaceMemberRequest)(nil), // 248: openshell.v1.AddWorkspaceMemberRequest - (*AddWorkspaceMemberResponse)(nil), // 249: openshell.v1.AddWorkspaceMemberResponse - (*RemoveWorkspaceMemberRequest)(nil), // 250: openshell.v1.RemoveWorkspaceMemberRequest - (*RemoveWorkspaceMemberResponse)(nil), // 251: openshell.v1.RemoveWorkspaceMemberResponse - (*ListWorkspaceMembersRequest)(nil), // 252: openshell.v1.ListWorkspaceMembersRequest - (*ListWorkspaceMembersResponse)(nil), // 253: openshell.v1.ListWorkspaceMembersResponse - (*ExtensionServiceCredential)(nil), // 254: openshell.v1.ExtensionServiceCredential - (*EndpointObservation)(nil), // 255: openshell.v1.EndpointObservation - (*ReportEndpointStatusRequest)(nil), // 256: openshell.v1.ReportEndpointStatusRequest - (*ReportEndpointStatusResponse)(nil), // 257: openshell.v1.ReportEndpointStatusResponse - (*EndpointStatus)(nil), // 258: openshell.v1.EndpointStatus - (*SandboxProvisioning)(nil), // 259: openshell.v1.SandboxProvisioning - (*SandboxServiceExposure)(nil), // 260: openshell.v1.SandboxServiceExposure - nil, // 261: openshell.v1.SandboxSpec.EnvironmentEntry - nil, // 262: openshell.v1.SandboxTemplate.LabelsEntry - nil, // 263: openshell.v1.SandboxTemplate.AnnotationsEntry - nil, // 264: openshell.v1.SandboxTemplate.EnvironmentEntry - nil, // 265: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - nil, // 266: openshell.v1.PlatformEvent.MetadataEntry - nil, // 267: openshell.v1.CreateSandboxRequest.LabelsEntry - nil, // 268: openshell.v1.CreateSandboxRequest.AnnotationsEntry - nil, // 269: openshell.v1.SandboxResponse.ServiceUrlsEntry - nil, // 270: openshell.v1.ExecSandboxRequest.EnvironmentEntry - nil, // 271: openshell.v1.SandboxLogLine.FieldsEntry - nil, // 272: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - nil, // 273: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - nil, // 274: openshell.v1.ProviderProfile.AnnotationsEntry - nil, // 275: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - nil, // 276: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - nil, // 277: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - nil, // 278: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - nil, // 279: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - nil, // 280: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry - nil, // 281: openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - nil, // 282: openshell.v1.UpdateConfigRequest.AnnotationsEntry - nil, // 283: openshell.v1.UpdateConfigResponse.AnnotationsEntry - nil, // 284: openshell.v1.SandboxPolicyRevision.ProvenanceEntry - nil, // 285: openshell.v1.CreateWorkspaceRequest.LabelsEntry - (*timestamppb.Timestamp)(nil), // 286: google.protobuf.Timestamp - (*datamodelv1.ObjectMeta)(nil), // 287: openshell.datamodel.v1.ObjectMeta - (*sandboxv1.SandboxPolicy)(nil), // 288: openshell.sandbox.v1.SandboxPolicy - (*structpb.Struct)(nil), // 289: google.protobuf.Struct - (*durationpb.Duration)(nil), // 290: google.protobuf.Duration - (*datamodelv1.WorkspaceSelector)(nil), // 291: openshell.datamodel.v1.WorkspaceSelector - (*datamodelv1.Provider)(nil), // 292: openshell.datamodel.v1.Provider - (sandboxv1.PolicySource)(0), // 293: openshell.sandbox.v1.PolicySource - (*sandboxv1.NetworkEndpoint)(nil), // 294: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 295: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 296: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 297: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 298: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 299: openshell.sandbox.v1.L7Rule - (*sandboxv1.SandboxConfigSnapshot)(nil), // 300: openshell.sandbox.v1.SandboxConfigSnapshot - (*datamodelv1.Workspace)(nil), // 301: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 302: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 303: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 304: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 305: openshell.sandbox.v1.GetGatewayConfigResponse + (*PeerConfigSandboxTarget)(nil), // 211: openshell.v1.PeerConfigSandboxTarget + (*PeerConfigUpdateHintRequest)(nil), // 212: openshell.v1.PeerConfigUpdateHintRequest + (*PeerConfigUpdateHintResponse)(nil), // 213: openshell.v1.PeerConfigUpdateHintResponse + (*RelayOpenResult)(nil), // 214: openshell.v1.RelayOpenResult + (*RelayClose)(nil), // 215: openshell.v1.RelayClose + (*L7RequestSample)(nil), // 216: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 217: openshell.v1.DenialSummary + (*DenialGroupCount)(nil), // 218: openshell.v1.DenialGroupCount + (*NetworkActivitySummary)(nil), // 219: openshell.v1.NetworkActivitySummary + (*PolicyChunk)(nil), // 220: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 221: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 222: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 223: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 224: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 225: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 226: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 227: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 228: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 229: openshell.v1.RejectDraftChunkResponse + (*DraftChunkApproval)(nil), // 230: openshell.v1.DraftChunkApproval + (*ApproveAllDraftChunksRequest)(nil), // 231: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 232: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 233: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 234: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 235: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 236: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 237: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 238: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 239: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 240: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 241: openshell.v1.GetDraftHistoryResponse + (*CreateWorkspaceRequest)(nil), // 242: openshell.v1.CreateWorkspaceRequest + (*CreateWorkspaceResponse)(nil), // 243: openshell.v1.CreateWorkspaceResponse + (*GetWorkspaceRequest)(nil), // 244: openshell.v1.GetWorkspaceRequest + (*GetWorkspaceResponse)(nil), // 245: openshell.v1.GetWorkspaceResponse + (*ListWorkspacesRequest)(nil), // 246: openshell.v1.ListWorkspacesRequest + (*ListWorkspacesResponse)(nil), // 247: openshell.v1.ListWorkspacesResponse + (*DeleteWorkspaceRequest)(nil), // 248: openshell.v1.DeleteWorkspaceRequest + (*DeleteWorkspaceResponse)(nil), // 249: openshell.v1.DeleteWorkspaceResponse + (*WorkspaceMember)(nil), // 250: openshell.v1.WorkspaceMember + (*AddWorkspaceMemberRequest)(nil), // 251: openshell.v1.AddWorkspaceMemberRequest + (*AddWorkspaceMemberResponse)(nil), // 252: openshell.v1.AddWorkspaceMemberResponse + (*RemoveWorkspaceMemberRequest)(nil), // 253: openshell.v1.RemoveWorkspaceMemberRequest + (*RemoveWorkspaceMemberResponse)(nil), // 254: openshell.v1.RemoveWorkspaceMemberResponse + (*ListWorkspaceMembersRequest)(nil), // 255: openshell.v1.ListWorkspaceMembersRequest + (*ListWorkspaceMembersResponse)(nil), // 256: openshell.v1.ListWorkspaceMembersResponse + (*ExtensionServiceCredential)(nil), // 257: openshell.v1.ExtensionServiceCredential + (*EndpointObservation)(nil), // 258: openshell.v1.EndpointObservation + (*ReportEndpointStatusRequest)(nil), // 259: openshell.v1.ReportEndpointStatusRequest + (*ReportEndpointStatusResponse)(nil), // 260: openshell.v1.ReportEndpointStatusResponse + (*EndpointStatus)(nil), // 261: openshell.v1.EndpointStatus + (*SandboxProvisioning)(nil), // 262: openshell.v1.SandboxProvisioning + (*SandboxServiceExposure)(nil), // 263: openshell.v1.SandboxServiceExposure + nil, // 264: openshell.v1.SandboxSpec.EnvironmentEntry + nil, // 265: openshell.v1.SandboxTemplate.LabelsEntry + nil, // 266: openshell.v1.SandboxTemplate.AnnotationsEntry + nil, // 267: openshell.v1.SandboxTemplate.EnvironmentEntry + nil, // 268: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + nil, // 269: openshell.v1.PlatformEvent.MetadataEntry + nil, // 270: openshell.v1.CreateSandboxRequest.LabelsEntry + nil, // 271: openshell.v1.CreateSandboxRequest.AnnotationsEntry + nil, // 272: openshell.v1.SandboxResponse.ServiceUrlsEntry + nil, // 273: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 274: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 275: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + nil, // 276: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + nil, // 277: openshell.v1.ProviderProfile.AnnotationsEntry + nil, // 278: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + nil, // 279: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + nil, // 280: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + nil, // 281: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + nil, // 282: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + nil, // 283: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + nil, // 284: openshell.v1.ProviderEnvironmentSnapshot.FilesEntry + nil, // 285: openshell.v1.UpdateConfigRequest.AnnotationsEntry + nil, // 286: openshell.v1.UpdateConfigResponse.AnnotationsEntry + nil, // 287: openshell.v1.SandboxPolicyRevision.ProvenanceEntry + nil, // 288: openshell.v1.CreateWorkspaceRequest.LabelsEntry + (*timestamppb.Timestamp)(nil), // 289: google.protobuf.Timestamp + (*datamodelv1.ObjectMeta)(nil), // 290: openshell.datamodel.v1.ObjectMeta + (*sandboxv1.SandboxPolicy)(nil), // 291: openshell.sandbox.v1.SandboxPolicy + (*structpb.Struct)(nil), // 292: google.protobuf.Struct + (*durationpb.Duration)(nil), // 293: google.protobuf.Duration + (*datamodelv1.WorkspaceSelector)(nil), // 294: openshell.datamodel.v1.WorkspaceSelector + (*datamodelv1.Provider)(nil), // 295: openshell.datamodel.v1.Provider + (sandboxv1.PolicySource)(0), // 296: openshell.sandbox.v1.PolicySource + (*sandboxv1.NetworkEndpoint)(nil), // 297: openshell.sandbox.v1.NetworkEndpoint + (*sandboxv1.NetworkBinary)(nil), // 298: openshell.sandbox.v1.NetworkBinary + (*sandboxv1.SettingValue)(nil), // 299: openshell.sandbox.v1.SettingValue + (*sandboxv1.NetworkPolicyRule)(nil), // 300: openshell.sandbox.v1.NetworkPolicyRule + (*sandboxv1.L7DenyRule)(nil), // 301: openshell.sandbox.v1.L7DenyRule + (*sandboxv1.L7Rule)(nil), // 302: openshell.sandbox.v1.L7Rule + (*sandboxv1.SandboxConfigSnapshot)(nil), // 303: openshell.sandbox.v1.SandboxConfigSnapshot + (*datamodelv1.Workspace)(nil), // 304: openshell.datamodel.v1.Workspace + (*sandboxv1.GetSandboxConfigRequest)(nil), // 305: openshell.sandbox.v1.GetSandboxConfigRequest + (*sandboxv1.GetGatewayConfigRequest)(nil), // 306: openshell.sandbox.v1.GetGatewayConfigRequest + (*sandboxv1.GetSandboxConfigResponse)(nil), // 307: openshell.sandbox.v1.GetSandboxConfigResponse + (*sandboxv1.GetGatewayConfigResponse)(nil), // 308: openshell.sandbox.v1.GetGatewayConfigResponse } var file_openshell_proto_depIdxs = []int32{ - 286, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 286, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 254, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential - 286, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp + 289, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 289, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 257, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential + 289, // 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 32, // 6: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo @@ -20576,115 +20820,115 @@ var file_openshell_proto_depIdxs = []int32{ 35, // 11: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities 36, // 12: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities 37, // 13: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities - 287, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 290, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 39, // 15: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec 50, // 16: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus 49, // 17: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance - 261, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry + 264, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry 42, // 19: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate - 288, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 291, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy 40, // 21: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements 17, // 22: openshell.v1.SandboxSpec.restart_policy:type_name -> openshell.v1.SandboxRestartPolicy 41, // 23: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements - 262, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry - 263, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry - 264, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry - 289, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct - 289, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct - 287, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 265, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry + 266, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry + 267, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry + 292, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 292, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct + 290, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 44, // 30: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec 45, // 31: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig - 289, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct + 292, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct 47, // 33: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel - 265, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + 268, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry 46, // 35: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources 41, // 36: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements 48, // 37: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup - 290, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 293, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration 51, // 39: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition 1, // 40: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 258, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus + 261, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus 179, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 259, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning - 286, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp - 286, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp - 286, // 46: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp - 286, // 47: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp - 266, // 48: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 291, // 49: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 262, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning + 289, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp + 289, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp + 289, // 46: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp + 289, // 47: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp + 269, // 48: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 294, // 49: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 39, // 50: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 267, // 51: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 268, // 52: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 260, // 53: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure - 291, // 54: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 270, // 51: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 271, // 52: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 263, // 53: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure + 294, // 54: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 43, // 55: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 291, // 56: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 57: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 58: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 56: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 57: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 58: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 43, // 59: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate 43, // 60: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate 18, // 61: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 291, // 62: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 286, // 63: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp - 291, // 64: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 65: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 66: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 67: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 68: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 69: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 70: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 71: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 62: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 289, // 63: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp + 294, // 64: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 65: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 66: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 67: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 68: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 69: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 70: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 71: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 38, // 72: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 269, // 73: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry + 272, // 73: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry 38, // 74: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 292, // 75: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 295, // 75: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider 38, // 76: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox 80, // 77: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt 38, // 78: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox 80, // 79: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt 78, // 80: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision 76, // 81: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity - 293, // 82: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 296, // 82: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource 5, // 83: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent 77, // 84: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision 7, // 85: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState 6, // 86: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 286, // 87: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp - 286, // 88: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp - 286, // 89: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp + 289, // 87: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp + 289, // 88: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp + 289, // 89: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp 2, // 90: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind 76, // 91: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity - 286, // 92: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp + 289, // 92: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp 4, // 93: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason 80, // 94: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt 3, // 95: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState 4, // 96: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason 81, // 97: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation - 286, // 98: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp - 286, // 99: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp + 289, // 98: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp + 289, // 99: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp 79, // 100: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation - 291, // 101: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 101: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 82, // 102: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus 81, // 103: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation - 290, // 104: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration - 290, // 105: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration + 293, // 104: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration + 293, // 105: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration 18, // 106: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 291, // 107: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 286, // 108: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp - 291, // 109: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 107: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 289, // 108: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp + 294, // 109: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 20, // 110: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 291, // 111: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 112: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 111: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 112: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 97, // 113: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 291, // 114: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 114: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 18, // 115: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 287, // 116: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 290, // 116: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 20, // 117: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode 96, // 118: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint 18, // 119: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 291, // 120: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 270, // 121: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 290, // 122: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration + 294, // 120: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 273, // 121: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 293, // 122: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration 101, // 123: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout 102, // 124: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr 103, // 125: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit @@ -20693,148 +20937,148 @@ var file_openshell_proto_depIdxs = []int32{ 105, // 128: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit 100, // 129: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest 108, // 130: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 287, // 131: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 286, // 132: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp - 291, // 133: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 286, // 134: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp + 290, // 131: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 289, // 132: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp + 294, // 133: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 289, // 134: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp 38, // 135: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox 112, // 136: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine 52, // 137: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent 113, // 138: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 218, // 139: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 286, // 140: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp - 271, // 141: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 291, // 142: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 292, // 143: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 291, // 144: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 145: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 146: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 292, // 147: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 272, // 148: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - 291, // 149: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 292, // 150: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 221, // 139: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 289, // 140: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp + 274, // 141: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 294, // 142: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 295, // 143: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 294, // 144: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 145: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 146: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 295, // 147: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 275, // 148: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + 294, // 149: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 295, // 150: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider 80, // 151: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt - 292, // 152: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 291, // 153: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 154: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 295, // 152: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 294, // 153: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 154: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 142, // 155: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 290, // 156: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration + 293, // 156: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration 125, // 157: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride 8, // 158: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType 126, // 159: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken 131, // 160: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh 127, // 161: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant 9, // 162: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 290, // 163: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration - 290, // 164: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration + 293, // 163: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration + 293, // 164: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration 129, // 165: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial 130, // 166: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput 9, // 167: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 286, // 168: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp - 286, // 169: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp - 286, // 170: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp + 289, // 168: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp + 289, // 169: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp + 289, // 170: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp 16, // 171: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 286, // 172: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp - 291, // 173: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 289, // 172: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp + 294, // 173: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 132, // 174: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 291, // 175: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 175: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 9, // 176: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 273, // 177: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 286, // 178: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp + 276, // 177: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 289, // 178: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp 132, // 179: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 291, // 180: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 180: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 132, // 181: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 291, // 182: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 182: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 18, // 183: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome 10, // 184: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory 128, // 185: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 294, // 186: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 295, // 187: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 297, // 186: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 298, // 187: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary 133, // 188: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 274, // 189: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 277, // 189: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry 143, // 190: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile 142, // 191: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile 142, // 192: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 291, // 193: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 193: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 123, // 194: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem 124, // 195: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic 142, // 196: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 291, // 197: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 197: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 123, // 198: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem 124, // 199: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic 142, // 200: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 291, // 201: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 201: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 123, // 202: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem 124, // 203: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic 18, // 204: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 291, // 205: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 205: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 18, // 206: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome 156, // 207: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 275, // 208: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 276, // 209: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - 277, // 210: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 278, // 211: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 278, // 208: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 279, // 209: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + 280, // 210: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 281, // 211: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry 4, // 212: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 279, // 213: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + 282, // 213: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry 11, // 214: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification 157, // 215: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding - 286, // 216: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp + 289, // 216: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp 159, // 217: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue - 280, // 218: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + 283, // 218: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry 4, // 219: openshell.v1.ProviderEnvironmentSnapshot.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 281, // 220: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - 290, // 221: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration - 291, // 222: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 288, // 223: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 296, // 224: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 284, // 220: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry + 293, // 221: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration + 294, // 222: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 291, // 223: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 299, // 224: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue 164, // 225: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 282, // 226: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 285, // 226: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry 165, // 227: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule 166, // 228: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint 167, // 229: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule 169, // 230: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules 170, // 231: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules 171, // 232: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 297, // 233: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 295, // 234: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 298, // 235: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 300, // 233: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 298, // 234: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 301, // 235: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule 168, // 236: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget - 299, // 237: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 302, // 237: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule 168, // 238: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget - 283, // 239: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 291, // 240: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 286, // 239: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 294, // 240: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 182, // 241: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 291, // 242: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 242: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 182, // 243: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision 13, // 244: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus 12, // 245: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState 179, // 246: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission 13, // 247: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 286, // 248: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp - 286, // 249: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp - 288, // 250: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 284, // 251: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 291, // 252: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 286, // 253: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp + 289, // 248: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp + 289, // 249: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp + 291, // 250: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 287, // 251: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 294, // 252: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 289, // 253: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp 112, // 254: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine 112, // 255: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine 189, // 256: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello 198, // 257: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 211, // 258: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 212, // 259: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 214, // 258: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 215, // 259: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose 195, // 260: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult 196, // 261: openshell.v1.SupervisorMessage.config_bootstrap_result:type_name -> openshell.v1.ConfigBootstrapResult 190, // 262: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted 197, // 263: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected 199, // 264: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat 204, // 265: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 212, // 266: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 215, // 266: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose 192, // 267: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate 191, // 268: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigBootstrap - 290, // 269: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration - 300, // 270: openshell.v1.ConfigBootstrap.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot + 293, // 269: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration + 303, // 270: openshell.v1.ConfigBootstrap.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot 160, // 271: openshell.v1.ConfigBootstrap.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot - 300, // 272: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot + 303, // 272: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot 160, // 273: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot 5, // 274: openshell.v1.ConfigComponentApplyResult.component:type_name -> openshell.v1.ConfigComponent 77, // 275: openshell.v1.ConfigComponentApplyResult.requested_revision:type_name -> openshell.v1.ConfigSnapshotRevision @@ -20848,236 +21092,239 @@ var file_openshell_proto_depIdxs = []int32{ 207, // 283: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit 204, // 284: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen 209, // 285: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit - 286, // 286: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp - 286, // 287: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp - 213, // 288: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 215, // 289: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 297, // 290: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 286, // 291: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp - 286, // 292: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp - 286, // 293: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp - 286, // 294: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp - 288, // 295: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 288, // 296: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 291, // 297: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 214, // 298: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 217, // 299: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 216, // 300: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 291, // 301: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 217, // 302: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 286, // 303: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp - 291, // 304: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 305: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 306: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 227, // 307: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval - 291, // 308: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 297, // 309: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 291, // 310: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 311: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 291, // 312: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 286, // 313: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp - 237, // 314: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 285, // 315: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 301, // 316: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 301, // 317: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 301, // 318: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 18, // 319: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 287, // 320: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 15, // 321: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 291, // 322: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 15, // 323: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 247, // 324: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 291, // 325: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 326: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 291, // 327: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 247, // 328: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 286, // 329: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp - 19, // 330: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult - 255, // 331: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation - 19, // 332: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult - 286, // 333: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp - 286, // 334: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp - 286, // 335: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp - 286, // 336: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp - 286, // 337: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp - 286, // 338: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp - 286, // 339: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp - 286, // 340: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp - 20, // 341: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 286, // 342: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 286, // 343: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 128, // 344: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 157, // 345: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 128, // 346: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 25, // 347: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 27, // 348: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 29, // 349: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 53, // 350: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 61, // 351: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest - 63, // 352: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 64, // 353: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 54, // 354: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 55, // 355: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 56, // 356: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 57, // 357: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 65, // 358: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 66, // 359: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 67, // 360: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 83, // 361: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 68, // 362: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 69, // 363: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 70, // 364: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 88, // 365: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 90, // 366: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 91, // 367: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 92, // 368: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 94, // 369: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 98, // 370: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 100, // 371: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 106, // 372: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 107, // 373: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 114, // 374: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 115, // 375: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 116, // 376: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 121, // 377: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 122, // 378: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 146, // 379: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 148, // 380: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 150, // 381: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 117, // 382: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 134, // 383: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 136, // 384: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 138, // 385: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 140, // 386: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 118, // 387: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 153, // 388: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 302, // 389: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 303, // 390: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 163, // 391: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 173, // 392: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 175, // 393: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 177, // 394: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 256, // 395: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 85, // 396: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 180, // 397: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest - 155, // 398: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 161, // 399: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest - 183, // 400: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 184, // 401: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 187, // 402: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 200, // 403: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest - 202, // 404: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest - 208, // 405: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 210, // 406: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame - 85, // 407: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 256, // 408: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 83, // 409: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 110, // 410: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 219, // 411: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 221, // 412: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 223, // 413: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 225, // 414: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 228, // 415: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 230, // 416: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 232, // 417: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 234, // 418: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 236, // 419: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 21, // 420: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 23, // 421: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 239, // 422: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 241, // 423: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 243, // 424: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 245, // 425: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 248, // 426: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 250, // 427: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 252, // 428: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 26, // 429: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 28, // 430: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 30, // 431: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 71, // 432: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 62, // 433: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse - 71, // 434: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 72, // 435: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 58, // 436: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 58, // 437: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 59, // 438: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 60, // 439: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 73, // 440: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 74, // 441: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 75, // 442: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 84, // 443: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 87, // 444: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 71, // 445: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 71, // 446: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 89, // 447: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 97, // 448: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 97, // 449: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 93, // 450: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 95, // 451: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 99, // 452: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 104, // 453: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 106, // 454: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 104, // 455: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 119, // 456: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 119, // 457: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 120, // 458: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 145, // 459: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 144, // 460: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 147, // 461: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 149, // 462: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 151, // 463: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 119, // 464: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 135, // 465: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 137, // 466: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 139, // 467: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 141, // 468: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 152, // 469: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 154, // 470: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 304, // 471: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 305, // 472: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 172, // 473: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 174, // 474: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 176, // 475: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 178, // 476: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 257, // 477: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 86, // 478: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 181, // 479: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse - 158, // 480: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 162, // 481: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse - 186, // 482: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 185, // 483: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 188, // 484: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 201, // 485: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse - 203, // 486: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse - 208, // 487: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 210, // 488: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame - 86, // 489: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 257, // 490: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 84, // 491: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 111, // 492: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 220, // 493: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 222, // 494: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 224, // 495: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 226, // 496: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 229, // 497: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 231, // 498: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 233, // 499: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 235, // 500: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 238, // 501: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 22, // 502: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 24, // 503: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 240, // 504: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 242, // 505: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 244, // 506: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 246, // 507: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 249, // 508: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 251, // 509: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 253, // 510: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 429, // [429:511] is the sub-list for method output_type - 347, // [347:429] is the sub-list for method input_type - 347, // [347:347] is the sub-list for extension type_name - 347, // [347:347] is the sub-list for extension extendee - 0, // [0:347] is the sub-list for field type_name + 211, // 286: openshell.v1.PeerConfigUpdateHintRequest.sandbox:type_name -> openshell.v1.PeerConfigSandboxTarget + 289, // 287: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp + 289, // 288: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp + 216, // 289: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 218, // 290: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 300, // 291: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 289, // 292: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp + 289, // 293: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp + 289, // 294: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp + 289, // 295: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp + 291, // 296: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 291, // 297: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 294, // 298: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 217, // 299: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 220, // 300: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 219, // 301: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 294, // 302: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 220, // 303: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 289, // 304: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp + 294, // 305: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 306: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 307: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 230, // 308: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval + 294, // 309: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 300, // 310: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 294, // 311: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 312: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 294, // 313: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 289, // 314: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp + 240, // 315: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 288, // 316: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 304, // 317: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 304, // 318: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 304, // 319: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 18, // 320: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 290, // 321: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 15, // 322: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 294, // 323: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 15, // 324: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 250, // 325: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 294, // 326: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 327: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 294, // 328: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 250, // 329: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 289, // 330: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp + 19, // 331: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult + 258, // 332: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation + 19, // 333: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult + 289, // 334: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp + 289, // 335: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp + 289, // 336: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp + 289, // 337: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp + 289, // 338: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp + 289, // 339: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp + 289, // 340: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp + 289, // 341: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp + 20, // 342: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 289, // 343: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 289, // 344: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 128, // 345: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 157, // 346: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 128, // 347: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 25, // 348: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 27, // 349: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 29, // 350: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 53, // 351: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 61, // 352: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest + 63, // 353: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 64, // 354: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 54, // 355: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 55, // 356: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 56, // 357: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 57, // 358: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 65, // 359: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 66, // 360: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 67, // 361: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 83, // 362: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 68, // 363: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 69, // 364: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 70, // 365: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 88, // 366: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 90, // 367: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 91, // 368: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 92, // 369: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 94, // 370: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 98, // 371: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 100, // 372: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 106, // 373: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 107, // 374: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 114, // 375: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 115, // 376: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 116, // 377: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 121, // 378: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 122, // 379: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 146, // 380: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 148, // 381: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 150, // 382: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 117, // 383: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 134, // 384: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 136, // 385: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 138, // 386: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 140, // 387: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 118, // 388: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 153, // 389: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 305, // 390: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 306, // 391: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 163, // 392: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 173, // 393: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 175, // 394: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 177, // 395: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 259, // 396: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 85, // 397: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 180, // 398: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest + 155, // 399: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 161, // 400: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest + 183, // 401: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 184, // 402: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 187, // 403: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 200, // 404: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest + 202, // 405: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest + 208, // 406: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 210, // 407: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame + 85, // 408: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 259, // 409: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 83, // 410: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 212, // 411: openshell.v1.OpenShell.PeerNotifyConfigUpdate:input_type -> openshell.v1.PeerConfigUpdateHintRequest + 110, // 412: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 222, // 413: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 224, // 414: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 226, // 415: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 228, // 416: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 231, // 417: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 233, // 418: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 235, // 419: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 237, // 420: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 239, // 421: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 21, // 422: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 23, // 423: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 242, // 424: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 244, // 425: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 246, // 426: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 248, // 427: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 251, // 428: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 253, // 429: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 255, // 430: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 26, // 431: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 28, // 432: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 30, // 433: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 71, // 434: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 62, // 435: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse + 71, // 436: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 72, // 437: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 58, // 438: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 58, // 439: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 59, // 440: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 60, // 441: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 73, // 442: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 74, // 443: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 75, // 444: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 84, // 445: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 87, // 446: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 71, // 447: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 71, // 448: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 89, // 449: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 97, // 450: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 97, // 451: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 93, // 452: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 95, // 453: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 99, // 454: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 104, // 455: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 106, // 456: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 104, // 457: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 119, // 458: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 119, // 459: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 120, // 460: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 145, // 461: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 144, // 462: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 147, // 463: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 149, // 464: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 151, // 465: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 119, // 466: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 135, // 467: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 137, // 468: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 139, // 469: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 141, // 470: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 152, // 471: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 154, // 472: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 307, // 473: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 308, // 474: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 172, // 475: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 174, // 476: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 176, // 477: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 178, // 478: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 260, // 479: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 86, // 480: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 181, // 481: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse + 158, // 482: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 162, // 483: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse + 186, // 484: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 185, // 485: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 188, // 486: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 201, // 487: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse + 203, // 488: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse + 208, // 489: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 210, // 490: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame + 86, // 491: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 260, // 492: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 84, // 493: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 213, // 494: openshell.v1.OpenShell.PeerNotifyConfigUpdate:output_type -> openshell.v1.PeerConfigUpdateHintResponse + 111, // 495: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 223, // 496: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 225, // 497: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 227, // 498: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 229, // 499: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 232, // 500: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 234, // 501: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 236, // 502: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 238, // 503: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 241, // 504: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 22, // 505: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 24, // 506: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 243, // 507: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 245, // 508: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 247, // 509: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 249, // 510: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 252, // 511: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 254, // 512: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 256, // 513: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 431, // [431:514] is the sub-list for method output_type + 348, // [348:431] is the sub-list for method input_type + 348, // [348:348] is the sub-list for extension type_name + 348, // [348:348] is the sub-list for extension extendee + 0, // [0:348] is the sub-list for field type_name } func init() { file_openshell_proto_init() } @@ -21159,13 +21406,18 @@ func file_openshell_proto_init() { (*PeerRelayFrame_Init)(nil), (*PeerRelayFrame_Data)(nil), } + file_openshell_proto_msgTypes[191].OneofWrappers = []any{ + (*PeerConfigUpdateHintRequest_Sandbox)(nil), + (*PeerConfigUpdateHintRequest_Workspace)(nil), + (*PeerConfigUpdateHintRequest_AllConnected)(nil), + } 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: 21, - NumMessages: 265, + NumMessages: 268, 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 e69a8f663f..f8bccdd30b 100644 --- a/sdk/go/proto/openshellv1/openshell_grpc.pb.go +++ b/sdk/go/proto/openshellv1/openshell_grpc.pb.go @@ -86,6 +86,7 @@ const ( OpenShell_PeerReportProviderReadiness_FullMethodName = "/openshell.v1.OpenShell/PeerReportProviderReadiness" OpenShell_PeerReportEndpointStatus_FullMethodName = "/openshell.v1.OpenShell/PeerReportEndpointStatus" OpenShell_PeerGetSandboxProviderStatus_FullMethodName = "/openshell.v1.OpenShell/PeerGetSandboxProviderStatus" + OpenShell_PeerNotifyConfigUpdate_FullMethodName = "/openshell.v1.OpenShell/PeerNotifyConfigUpdate" OpenShell_WatchSandbox_FullMethodName = "/openshell.v1.OpenShell/WatchSandbox" OpenShell_SubmitPolicyAnalysis_FullMethodName = "/openshell.v1.OpenShell/SubmitPolicyAnalysis" OpenShell_GetDraftPolicy_FullMethodName = "/openshell.v1.OpenShell/GetDraftPolicy" @@ -284,6 +285,9 @@ type OpenShellClient interface { PeerReportProviderReadiness(ctx context.Context, in *ReportProviderReadinessRequest, opts ...grpc.CallOption) (*ReportProviderReadinessResponse, error) PeerReportEndpointStatus(ctx context.Context, in *ReportEndpointStatusRequest, opts ...grpc.CallOption) (*ReportEndpointStatusResponse, error) PeerGetSandboxProviderStatus(ctx context.Context, in *GetSandboxProviderStatusRequest, opts ...grpc.CallOption) (*GetSandboxProviderStatusResponse, error) + // Best-effort notification to the replica that owns a supervisor session. + // The receiver rebuilds snapshots from authoritative state. + PeerNotifyConfigUpdate(ctx context.Context, in *PeerConfigUpdateHintRequest, opts ...grpc.CallOption) (*PeerConfigUpdateHintResponse, error) // Watch a sandbox and stream updates. // // This stream can include: @@ -1003,6 +1007,16 @@ func (c *openShellClient) PeerGetSandboxProviderStatus(ctx context.Context, in * return out, nil } +func (c *openShellClient) PeerNotifyConfigUpdate(ctx context.Context, in *PeerConfigUpdateHintRequest, opts ...grpc.CallOption) (*PeerConfigUpdateHintResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PeerConfigUpdateHintResponse) + err := c.cc.Invoke(ctx, OpenShell_PeerNotifyConfigUpdate_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *openShellClient) WatchSandbox(ctx context.Context, in *WatchSandboxRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SandboxStreamEvent], error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) stream, err := c.cc.NewStream(ctx, &OpenShell_ServiceDesc.Streams[7], OpenShell_WatchSandbox_FullMethodName, cOpts...) @@ -1379,6 +1393,9 @@ type OpenShellServer interface { PeerReportProviderReadiness(context.Context, *ReportProviderReadinessRequest) (*ReportProviderReadinessResponse, error) PeerReportEndpointStatus(context.Context, *ReportEndpointStatusRequest) (*ReportEndpointStatusResponse, error) PeerGetSandboxProviderStatus(context.Context, *GetSandboxProviderStatusRequest) (*GetSandboxProviderStatusResponse, error) + // Best-effort notification to the replica that owns a supervisor session. + // The receiver rebuilds snapshots from authoritative state. + PeerNotifyConfigUpdate(context.Context, *PeerConfigUpdateHintRequest) (*PeerConfigUpdateHintResponse, error) // Watch a sandbox and stream updates. // // This stream can include: @@ -1630,6 +1647,9 @@ func (UnimplementedOpenShellServer) PeerReportEndpointStatus(context.Context, *R func (UnimplementedOpenShellServer) PeerGetSandboxProviderStatus(context.Context, *GetSandboxProviderStatusRequest) (*GetSandboxProviderStatusResponse, error) { return nil, status.Error(codes.Unimplemented, "method PeerGetSandboxProviderStatus not implemented") } +func (UnimplementedOpenShellServer) PeerNotifyConfigUpdate(context.Context, *PeerConfigUpdateHintRequest) (*PeerConfigUpdateHintResponse, error) { + return nil, status.Error(codes.Unimplemented, "method PeerNotifyConfigUpdate not implemented") +} func (UnimplementedOpenShellServer) WatchSandbox(*WatchSandboxRequest, grpc.ServerStreamingServer[SandboxStreamEvent]) error { return status.Error(codes.Unimplemented, "method WatchSandbox not implemented") } @@ -2769,6 +2789,24 @@ func _OpenShell_PeerGetSandboxProviderStatus_Handler(srv interface{}, ctx contex return interceptor(ctx, in, info, handler) } +func _OpenShell_PeerNotifyConfigUpdate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PeerConfigUpdateHintRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).PeerNotifyConfigUpdate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_PeerNotifyConfigUpdate_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).PeerNotifyConfigUpdate(ctx, req.(*PeerConfigUpdateHintRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _OpenShell_WatchSandbox_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(WatchSandboxRequest) if err := stream.RecvMsg(m); err != nil { @@ -3335,6 +3373,10 @@ var OpenShell_ServiceDesc = grpc.ServiceDesc{ MethodName: "PeerGetSandboxProviderStatus", Handler: _OpenShell_PeerGetSandboxProviderStatus_Handler, }, + { + MethodName: "PeerNotifyConfigUpdate", + Handler: _OpenShell_PeerNotifyConfigUpdate_Handler, + }, { MethodName: "SubmitPolicyAnalysis", Handler: _OpenShell_SubmitPolicyAnalysis_Handler, diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index 7faa3c590f..9a0b6f73b8 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -482,6 +482,15 @@ be served by a non-owner gateway replica and relayed to the current supervisor owner over the internal `PeerRelay` RPC. Check the headless peer Service, projected peer ServiceAccount token volume, and TokenReview RBAC: +The experimental `server.configDeliveryMode: push` sends configuration hints +to that same peer endpoint over `PeerNotifyConfigUpdate`. Check that every +gateway replica runs a version supporting the RPC and uses the same mode. +`poll` is the 0.1.x default; a push setting in this release sends shadow +snapshots while supervisors still poll. If hints fail, inspect +`openshell_supervisor_config_peer_hints_total` and peer authentication logs. +An old peer returns `UNIMPLEMENTED`, and a peer still set to `poll` returns +`FAILED_PRECONDITION`. + ```bash kubectl -n openshell get svc openshell-peer -o wide kubectl -n openshell get endpoints openshell-peer From 0e3d78b29503b2b635dd444a5d9d8ce99a4261fa Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Thu, 1 Oct 2026 15:58:20 -0700 Subject: [PATCH 13/15] fix(config): coalesce direct and fleet updates per component Signed-off-by: Piotr Mlocek --- .../openshell-server/src/config_delivery.rs | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/crates/openshell-server/src/config_delivery.rs b/crates/openshell-server/src/config_delivery.rs index c9be03d0af..a288782139 100644 --- a/crates/openshell-server/src/config_delivery.rs +++ b/crates/openshell-server/src/config_delivery.rs @@ -171,7 +171,6 @@ impl ConfigComponentKind { struct DeliveryKey { sandbox_id: String, component: ConfigComponentKind, - route_remote: bool, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -417,21 +416,19 @@ pub fn publish_sandbox_components( if state.config.config_delivery_mode != ConfigDeliveryMode::Push { return; } - enqueue_sandbox(state, sandbox_id, components, true); + enqueue_sandbox(state, sandbox_id, components); } fn enqueue_sandbox( state: &Arc, sandbox_id: &str, components: ConfigComponents, - route_remote: bool, ) -> bool { let mut accepted = true; for component in components.selected() { let key = DeliveryKey { sandbox_id: sandbox_id.to_string(), component, - route_remote, }; match state.config_delivery_queue.enqueue(key.clone()) { DeliveryEnqueue::StartWorker(permit) => { @@ -469,7 +466,6 @@ async fn enqueue_sandbox_from_fanout( let key = DeliveryKey { sandbox_id: sandbox_id.to_string(), component, - route_remote: false, }; match state .config_delivery_queue @@ -483,10 +479,10 @@ async fn enqueue_sandbox_from_fanout( } async fn publish_sandbox_component_now(state: &Arc, key: &DeliveryKey) { - if key.route_remote && route_remote_sandbox_component(state, key).await { + if route_remote_sandbox_component(state, key).await { return; } - if !key.route_remote && !is_current_local_owner(state, &key.sandbox_id).await { + if !is_current_local_owner(state, &key.sandbox_id).await { return; } if !state @@ -520,6 +516,9 @@ async fn publish_sandbox_component_now(state: &Arc, key: &DeliveryK match state.config_delivery_queue.run_bounded_build(build).await { Ok(Ok(None)) => {} Ok(Ok(Some(message))) => { + if !is_current_local_owner(state, &key.sandbox_id).await { + return; + } let disposition = state .supervisor_config_router() .deliver(&key.sandbox_id, message) @@ -815,8 +814,7 @@ pub async fn handle_peer_config_update_hint( .is_current_session(&target.sandbox_id, &target.session_id) }); if !response.stale_owner { - response.queue_full = - !enqueue_sandbox(state, &target.sandbox_id, components, false); + response.queue_full = !enqueue_sandbox(state, &target.sandbox_id, components); } } Some(peer_config_update_hint_request::Scope::Workspace(workspace)) => { @@ -994,7 +992,6 @@ mod tests { DeliveryKey { sandbox_id: sandbox_id.to_string(), component, - route_remote: true, } } @@ -1020,6 +1017,24 @@ mod tests { drop(permit); } + #[tokio::test] + async fn direct_and_fanout_updates_share_one_component_worker() { + let queue = ConfigDeliveryQueue::default(); + let key = key("sb-1", ConfigComponentKind::SandboxConfig); + let DeliveryEnqueue::StartWorker(permit) = queue.enqueue(key.clone()) else { + panic!("direct update must start a worker"); + }; + queue.take(&key); + assert!(matches!( + queue.enqueue_from_fanout(key.clone()).await, + DeliveryEnqueue::Coalesced + )); + assert!(queue.finish_pass(&key)); + queue.take(&key); + assert!(!queue.finish_pass(&key)); + drop(permit); + } + #[test] fn build_bound_is_sized_from_the_database_pool() { assert_eq!( From b04c20f3fb256fc151cf3c48eba7b06185809be4 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Fri, 2 Oct 2026 10:11:44 -0700 Subject: [PATCH 14/15] fix(config): use generic Helm gateway configuration Signed-off-by: Piotr Mlocek --- deploy/helm/openshell/README.md | 1 - .../openshell/templates/gateway-config.yaml | 7 -- deploy/helm/openshell/values.yaml | 3 - docs/how-it-works/gateways/configuration.mdx | 12 +++- docs/images/gateway-config-push-stage-1.svg | 72 +++++++++++++++++++ skills/debug-openshell-cluster/SKILL.md | 7 +- 6 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 docs/images/gateway-config-push-stage-1.svg diff --git a/deploy/helm/openshell/README.md b/deploy/helm/openshell/README.md index 5829e1c964..df3ea173ad 100644 --- a/deploy/helm/openshell/README.md +++ b/deploy/helm/openshell/README.md @@ -391,7 +391,6 @@ discovery endpoint or its TLS CA. | securityContext.runAsNonRoot | bool | `true` | Require the gateway container to run as a non-root user. | | securityContext.runAsUser | int | `1000` | UID assigned to the gateway container. | | server.auth.allowUnauthenticatedUsers | bool | `false` | UNSAFE: accept unauthenticated CLI/user requests as a local developer principal. Intended only for trusted local Skaffold/k3d development or a fully trusted fronting proxy. Leave false for shared or production clusters. | -| server.configDeliveryMode | string | `""` | Supervisor configuration delivery. Empty uses the gateway release default (poll in 0.1.x). Push enables shadow snapshots in the Stage 1 gateway. | | server.credentialDrivers.kubernetesSecrets.createNamespace | bool | `false` | Create the credential namespace. Requires a namespace other than the release namespace. The Namespace is retained on uninstall so stored credentials survive; an existing Namespace not owned by this release is left untouched. | | server.credentialDrivers.kubernetesSecrets.enabled | bool | `false` | Enable the in-tree Kubernetes Secret credential driver. WARNING: The RBAC Role grants read/write access to ALL Secrets in the configured namespace. Use a dedicated namespace to limit blast radius. | | server.credentialDrivers.kubernetesSecrets.namespace | string | `""` | Namespace where OpenShell-managed provider Secret objects are stored. Empty = Helm release namespace. A dedicated namespace is RECOMMENDED to isolate OpenShell-managed Secrets from other workloads. | diff --git a/deploy/helm/openshell/templates/gateway-config.yaml b/deploy/helm/openshell/templates/gateway-config.yaml index 6b7b2d2b71..a3e0210a35 100644 --- a/deploy/helm/openshell/templates/gateway-config.yaml +++ b/deploy/helm/openshell/templates/gateway-config.yaml @@ -46,13 +46,6 @@ data: {{- end }} log_level = {{ .Values.server.logLevel | quote }} compute_driver = "kubernetes" - {{- $configDeliveryMode := .Values.server.configDeliveryMode | default "" }} - {{- if not (has $configDeliveryMode (list "" "poll" "push")) }} - {{- fail "server.configDeliveryMode must be empty, poll, or push" }} - {{- end }} - {{- if $configDeliveryMode }} - config_delivery_mode = {{ $configDeliveryMode | quote }} - {{- end }} {{- if $credentialDrivers }} credential_drivers = [{{- range $i, $driver := $credentialDrivers }}{{ if $i }}, {{ end }}{{ $driver | quote }}{{- end }}] {{- end }} diff --git a/deploy/helm/openshell/values.yaml b/deploy/helm/openshell/values.yaml index 01538f0ac9..4bf21b88a8 100644 --- a/deploy/helm/openshell/values.yaml +++ b/deploy/helm/openshell/values.yaml @@ -258,9 +258,6 @@ affinity: {} # Server configuration server: - # -- Supervisor configuration delivery. Empty uses the gateway release default - # (poll in 0.1.x). Push enables shadow snapshots in the Stage 1 gateway. - configDeliveryMode: "" # -- Operator-facing gateway name. Defaults to the chart fullname so all # replicas in one installation share an identity. Set explicitly when one # telemetry collector receives spans from multiple namespaces or clusters. diff --git a/docs/how-it-works/gateways/configuration.mdx b/docs/how-it-works/gateways/configuration.mdx index 445b6974c5..c618942c34 100644 --- a/docs/how-it-works/gateways/configuration.mdx +++ b/docs/how-it-works/gateways/configuration.mdx @@ -26,7 +26,17 @@ On-disk SQLite databases run in WAL mode with `synchronous=FULL`: the gateway ke When shadow push is enabled, the gateway waits at most one second for an optional configuration bootstrap during supervisor reconnects. If a credential backend stalls, the gateway accepts the session without that bootstrap so SSH, exec, and service connections can resume. Supervisor polling continues to supply configuration. -In 0.1.x, `[openshell.gateway].config_delivery_mode` defaults to `poll`. Set it to `push` to enable experimental shadow configuration snapshots over the supervisor session. Supervisors in this release still apply configuration by polling, including when the gateway sends shadow snapshots. Set the mode with `--config-delivery-mode`, `OPENSHELL_CONFIG_DELIVERY_MODE`, or Helm `server.configDeliveryMode`. The Helm value is empty by default, so the chart omits the TOML key. During an upgrade, enable `push` only after every gateway replica supports this setting; an older gateway rejects the new TOML key. Keep the mode the same on all HA replicas. +In 0.1.x, `[openshell.gateway].config_delivery_mode` defaults to `poll`. Set it to `push` to enable experimental shadow snapshots over the supervisor session. Supervisors still apply configuration by polling in both modes. The gateway also accepts `--config-delivery-mode` and `OPENSHELL_CONFIG_DELIVERY_MODE`. + +With a Helm chart that supports `gatewayConfig`, set the same gateway TOML field through chart values: + +```yaml +gatewayConfig: + openshell.gateway: + config_delivery_mode: push +``` + +During an upgrade, enable `push` only after every gateway replica supports this setting. An older gateway rejects the new TOML key. Keep the mode the same on all HA replicas. On startup, the gateway repairs missing legacy policy history and skips invalid stored policies. A valid global policy can still override an invalid local policy; otherwise, that sandbox's configuration reads continue to report the validation failure. diff --git a/docs/images/gateway-config-push-stage-1.svg b/docs/images/gateway-config-push-stage-1.svg new file mode 100644 index 0000000000..10d5dcaf1f --- /dev/null +++ b/docs/images/gateway-config-push-stage-1.svg @@ -0,0 +1,72 @@ + + + + + Stage 1 gateway configuration delivery + A configuration change is saved in the shared database. With push mode enabled, a hint reaches each gateway that owns an affected supervisor session. The owner sends a full snapshot, which the supervisor receives but ignores. In both modes, the supervisor continues to poll and apply configuration every ten seconds. + + + + + + + + + + + + Stage 1: push observes; polling applies + The saved configuration is the source for both paths. + + + Configuration + change + + + Shared DB + saves latest state + + + OPTIONAL PUSH MODE · SHADOW DELIVERY + + + Route update hint + to session owner(s) + across HA gateways + + + Owning gateway + builds full snapshot + + + Supervisor + receives and ignores + + + BOTH MODES · AUTHORITATIVE POLLING + + + Supervisor + polls every 10 seconds + + + Gateway + reads saved state + + + Supervisor + applies configuration + diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index 9a0b6f73b8..597617ef38 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -482,9 +482,10 @@ be served by a non-owner gateway replica and relayed to the current supervisor owner over the internal `PeerRelay` RPC. Check the headless peer Service, projected peer ServiceAccount token volume, and TokenReview RBAC: -The experimental `server.configDeliveryMode: push` sends configuration hints -to that same peer endpoint over `PeerNotifyConfigUpdate`. Check that every -gateway replica runs a version supporting the RPC and uses the same mode. +The experimental `[openshell.gateway].config_delivery_mode = "push"` sends +configuration hints to that same peer endpoint over `PeerNotifyConfigUpdate`. +Check that every gateway replica runs a version supporting the RPC and uses +the same mode. `poll` is the 0.1.x default; a push setting in this release sends shadow snapshots while supervisors still poll. If hints fail, inspect `openshell_supervisor_config_peer_hints_total` and peer authentication logs. From f1e85038a0f8c137518e753ade4320078f285655 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Fri, 2 Oct 2026 10:31:12 -0700 Subject: [PATCH 15/15] docs(config): remove public guidance for internal push rollout Signed-off-by: Piotr Mlocek --- docs/how-it-works/gateways/configuration.mdx | 38 ++--------- docs/images/gateway-config-push-stage-1.svg | 72 -------------------- skills/debug-openshell-cluster/SKILL.md | 12 ---- 3 files changed, 4 insertions(+), 118 deletions(-) delete mode 100644 docs/images/gateway-config-push-stage-1.svg diff --git a/docs/how-it-works/gateways/configuration.mdx b/docs/how-it-works/gateways/configuration.mdx index c618942c34..3b70608661 100644 --- a/docs/how-it-works/gateways/configuration.mdx +++ b/docs/how-it-works/gateways/configuration.mdx @@ -22,24 +22,6 @@ On-disk SQLite databases run in WAL mode with `synchronous=FULL`: the gateway ke `name` assigns an operator-facing identity to the gateway installation. Set it with `[openshell.gateway].name`, `--name`, or `OPENSHELL_GATEWAY_NAME`. It defaults to `openshell`; the Helm chart defaults it to the chart fullname so all replicas in one installation share a name. Chart fullnames are only unique within their Kubernetes namespace, so set `server.name` explicitly when one collector receives telemetry from multiple namespaces or clusters. This identity is independent of client-side gateway aliases, TLS names, and `gateway_jwt.gateway_id`. -## Supervisor connections and policy recovery - -When shadow push is enabled, the gateway waits at most one second for an optional configuration bootstrap during supervisor reconnects. If a credential backend stalls, the gateway accepts the session without that bootstrap so SSH, exec, and service connections can resume. Supervisor polling continues to supply configuration. - -In 0.1.x, `[openshell.gateway].config_delivery_mode` defaults to `poll`. Set it to `push` to enable experimental shadow snapshots over the supervisor session. Supervisors still apply configuration by polling in both modes. The gateway also accepts `--config-delivery-mode` and `OPENSHELL_CONFIG_DELIVERY_MODE`. - -With a Helm chart that supports `gatewayConfig`, set the same gateway TOML field through chart values: - -```yaml -gatewayConfig: - openshell.gateway: - config_delivery_mode: push -``` - -During an upgrade, enable `push` only after every gateway replica supports this setting. An older gateway rejects the new TOML key. Keep the mode the same on all HA replicas. - -On startup, the gateway repairs missing legacy policy history and skips invalid stored policies. A valid global policy can still override an invalid local policy; otherwise, that sandbox's configuration reads continue to report the validation failure. - ## Package-Managed Locations Package-managed gateways use either built-in defaults or a package-seeded TOML file. Set `OPENSHELL_GATEWAY_CONFIG` in the launch environment to use a different file. @@ -267,10 +249,7 @@ namespace = "openshell" # Required in raw TOML; Helm derives this from the gateway Service. grpc_endpoint = "https://openshell-gateway.openshell.svc:8080" default_image = "nvcr.io/nvidia/base/ubuntu:24.04" -# Defaults to the gateway version. Custom builds must match the gateway's -# internal supervisor protocol revision; mismatched peers reject the session. -# Supervisors from releases before the handshake existed remain compatible for -# one release. +# Defaults to the gateway version; override to pin a specific build. # supervisor_image = "ghcr.io/nvidia/openshell/supervisor:" client_tls_secret_name = "openshell-client-tls" service_account_name = "openshell-sandbox" @@ -763,10 +742,7 @@ image_pull_secrets = ["regcred"] # Defaults to the gateway version; override to pin a specific build. # sandbox_runtime_image = "ghcr.io/nvidia/openshell/sandbox:" sandbox_runtime_image_pull_policy = "if_not_present" -# Defaults to the gateway version. Custom builds must match the gateway's -# internal supervisor protocol revision; mismatched peers reject the session. -# Supervisors from releases before the handshake existed remain compatible for -# one release. +# Defaults to the gateway version; override to pin a specific build. # supervisor_image = "ghcr.io/nvidia/openshell/supervisor:" supervisor_image_pull_policy = "if_not_present" @@ -934,10 +910,7 @@ sandbox_label = "docker-dev" grpc_endpoint = "https://127.0.0.1:17670" # Workload-side runtime. Defaults to the gateway version. # sandbox_runtime_image = "ghcr.io/nvidia/openshell/sandbox:" -# Supervisor runtime defaults to the gateway version. Custom builds must match -# the gateway's internal supervisor protocol revision; mismatched peers reject -# the session. Supervisors from releases before the handshake existed remain -# compatible for one release. +# Supervisor runtime. Defaults to the gateway version. # supervisor_image = "ghcr.io/nvidia/openshell/supervisor:" # Unsafe operator override. Host bind mounts, including Docker local-driver # bind-backed volumes, expose gateway-host paths inside sandboxes and can @@ -1031,10 +1004,7 @@ ssh_socket_path = "/run/openshell/ssh.sock" stop_timeout_secs = 45 # Statically linked workload-side runtime. Defaults to the gateway version. # sandbox_runtime_image = "ghcr.io/nvidia/openshell/sandbox:" -# Dynamically linked supervisor runtime defaults to the gateway version. Custom -# builds must match the gateway's internal supervisor protocol revision; -# mismatched peers reject the session. Supervisors from releases before the -# handshake existed remain compatible for one release. +# Dynamically linked supervisor runtime. Defaults to the gateway version. # supervisor_image = "ghcr.io/nvidia/openshell/supervisor:" # Unsafe operator override. Host bind mounts, including Podman local-driver # bind-backed volumes, expose gateway-host paths inside sandboxes and can diff --git a/docs/images/gateway-config-push-stage-1.svg b/docs/images/gateway-config-push-stage-1.svg deleted file mode 100644 index 10d5dcaf1f..0000000000 --- a/docs/images/gateway-config-push-stage-1.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - Stage 1 gateway configuration delivery - A configuration change is saved in the shared database. With push mode enabled, a hint reaches each gateway that owns an affected supervisor session. The owner sends a full snapshot, which the supervisor receives but ignores. In both modes, the supervisor continues to poll and apply configuration every ten seconds. - - - - - - - - - - - - Stage 1: push observes; polling applies - The saved configuration is the source for both paths. - - - Configuration - change - - - Shared DB - saves latest state - - - OPTIONAL PUSH MODE · SHADOW DELIVERY - - - Route update hint - to session owner(s) - across HA gateways - - - Owning gateway - builds full snapshot - - - Supervisor - receives and ignores - - - BOTH MODES · AUTHORITATIVE POLLING - - - Supervisor - polls every 10 seconds - - - Gateway - reads saved state - - - Supervisor - applies configuration - diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index 597617ef38..46d5abc254 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -19,8 +19,6 @@ The target deployment flow is: 4. The CLI registers a reachable gateway endpoint with `openshell gateway add`. 5. The gateway creates sandboxes through the selected compute driver. -If supervisor sessions fail with a protocol revision mismatch, check that custom supervisor images match the gateway release. Gateway and supervisor require the same internal protocol revision; authentication success does not make mismatched versions compatible. Supervisors that predate the handshake still connect for one release. The gateway logs a warning for each such session and counts them in the `openshell_supervisor_protocol_legacy_sessions_total` metric, so recreate those sandboxes before the next gateway upgrade. See the published [gateway configuration reference](https://docs.nvidia.com/openshell/latest/reference/gateway-config.md). - The `openshell-gateway` composition crate explicitly installs its compiled Docker, Podman, Kubernetes, and VM registrations at startup; `openshell-server` does not link compute-driver crates. Custom gateway binaries may include a @@ -482,16 +480,6 @@ be served by a non-owner gateway replica and relayed to the current supervisor owner over the internal `PeerRelay` RPC. Check the headless peer Service, projected peer ServiceAccount token volume, and TokenReview RBAC: -The experimental `[openshell.gateway].config_delivery_mode = "push"` sends -configuration hints to that same peer endpoint over `PeerNotifyConfigUpdate`. -Check that every gateway replica runs a version supporting the RPC and uses -the same mode. -`poll` is the 0.1.x default; a push setting in this release sends shadow -snapshots while supervisors still poll. If hints fail, inspect -`openshell_supervisor_config_peer_hints_total` and peer authentication logs. -An old peer returns `UNIMPLEMENTED`, and a peer still set to `poll` returns -`FAILED_PRECONDITION`. - ```bash kubectl -n openshell get svc openshell-peer -o wide kubectl -n openshell get endpoints openshell-peer