From ea6c6891dcdaaa97db4897ef438d6462d1cb3bbd Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Wed, 9 Sep 2026 12:37:57 -0700 Subject: [PATCH 01/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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]