diff --git a/crates/openshell-cli/src/commands/common.rs b/crates/openshell-cli/src/commands/common.rs index 1b02447b3f..4afeeb569c 100644 --- a/crates/openshell-cli/src/commands/common.rs +++ b/crates/openshell-cli/src/commands/common.rs @@ -66,6 +66,8 @@ pub fn phase_name(phase: i32) -> &'static str { Ok(SandboxPhase::Stopped) => "Stopped", Ok(SandboxPhase::Starting) => "Starting", Ok(SandboxPhase::Completed) => "Completed", + Ok(SandboxPhase::Suspending) => "Suspending", + Ok(SandboxPhase::Suspended) => "Suspended", Ok(SandboxPhase::Unknown) | Err(_) => "Unknown", } } diff --git a/crates/openshell-cli/src/main.rs b/crates/openshell-cli/src/main.rs index 6e58330ed6..7411629483 100644 --- a/crates/openshell-cli/src/main.rs +++ b/crates/openshell-cli/src/main.rs @@ -1714,6 +1714,25 @@ enum SandboxCommands { name: Option, }, + /// Suspend a ready sandbox and retain its memory state. + /// + /// Requires a compute driver and isolation backend that support + /// suspend and resume. Use `sandbox resume` to restore the sandbox. + #[command(help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")] + Suspend { + /// Sandbox name (defaults to last-used sandbox). + #[arg(add = ArgValueCompleter::new(completers::complete_sandbox_names))] + name: Option, + }, + + /// Resume a suspended sandbox from its retained memory state. + #[command(help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")] + Resume { + /// Sandbox name (defaults to last-used sandbox). + #[arg(add = ArgValueCompleter::new(completers::complete_sandbox_names))] + name: Option, + }, + /// Execute a command in a running sandbox. /// /// Runs a command inside an existing sandbox using the gRPC exec endpoint. @@ -3598,6 +3617,14 @@ async fn run_async() -> Result<()> { let name = resolve_sandbox_name(name, &ctx.name, &cli.workspace)?; run::sandbox_start(endpoint, &name, &cli.workspace, &tls).await?; } + SandboxCommands::Suspend { name } => { + let name = resolve_sandbox_name(name, &ctx.name, &cli.workspace)?; + run::sandbox_suspend(endpoint, &name, &cli.workspace, &tls).await?; + } + SandboxCommands::Resume { name } => { + let name = resolve_sandbox_name(name, &ctx.name, &cli.workspace)?; + run::sandbox_resume(endpoint, &name, &cli.workspace, &tls).await?; + } SandboxCommands::Connect { name, editor } => { let name = resolve_sandbox_name(name, &ctx.name, &cli.workspace)?; if let Some(editor) = editor.map(Into::into) { @@ -5542,6 +5569,38 @@ mod tests { )); } + #[test] + fn sandbox_suspend_and_resume_accept_optional_names() { + let suspend = Cli::try_parse_from(["openshell", "sandbox", "suspend", "demo"]) + .expect("suspend command should parse"); + assert!(matches!( + suspend.command, + Some(Commands::Sandbox { + command: Some(SandboxCommands::Suspend { name: Some(ref name) }), + }) if name == "demo" + )); + + let resume = Cli::try_parse_from(["openshell", "sandbox", "resume"]) + .expect("resume command should parse"); + assert!(matches!( + resume.command, + Some(Commands::Sandbox { + command: Some(SandboxCommands::Resume { name: None }), + }) + )); + + let named = Cli::try_parse_from(["openshell", "sandbox", "resume", "demo"]) + .expect("named resume should parse"); + assert!(matches!( + named.command, + Some(Commands::Sandbox { + command: Some(SandboxCommands::Resume { + name: Some(ref name), + }), + }) if name == "demo" + )); + } + #[test] fn sandbox_list_accepts_output_json() { let cli = Cli::try_parse_from(["openshell", "sandbox", "list", "-o", "json"]) diff --git a/crates/openshell-cli/src/run.rs b/crates/openshell-cli/src/run.rs index 8aca727b5c..ba31f35d87 100644 --- a/crates/openshell-cli/src/run.rs +++ b/crates/openshell-cli/src/run.rs @@ -57,12 +57,13 @@ use openshell_core::proto::{ GetSandboxTemplateRequest, GetServiceRequest, GpuResourceRequirements, ListSandboxPoliciesRequest, ListSandboxTemplatesRequest, ListSandboxesRequest, ListServicesRequest, PolicySource, PolicyStatus, RejectDraftChunkRequest, ResourceRequirements, - RevokeSshSessionRequest, Sandbox, SandboxCondition, SandboxPhase, SandboxPolicy, - SandboxResources, SandboxRestartPolicy, SandboxServiceExposure, SandboxServiceLevel, - SandboxSpec, SandboxStartup, SandboxTemplate, SandboxWorkloadConfig, SandboxWorkloadTemplate, - SandboxWorkloadTemplateSpec, ServiceAuthorizationMode, ServiceEndpointResponse, SettingScope, - StartSandboxRequest, StopSandboxRequest, TcpForwardFrame, TcpForwardInit, TcpRelayTarget, - UpdateConfigRequest, WatchSandboxRequest, exec_sandbox_event, tcp_forward_init, + ResumeSandboxRequest, RevokeSshSessionRequest, Sandbox, SandboxCondition, SandboxPhase, + SandboxPolicy, SandboxResources, SandboxRestartPolicy, SandboxServiceExposure, + SandboxServiceLevel, SandboxSpec, SandboxStartup, SandboxTemplate, SandboxWorkloadConfig, + SandboxWorkloadTemplate, SandboxWorkloadTemplateSpec, ServiceAuthorizationMode, + ServiceEndpointResponse, SettingScope, StartSandboxRequest, StopSandboxRequest, + SuspendSandboxRequest, TcpForwardFrame, TcpForwardInit, TcpRelayTarget, UpdateConfigRequest, + WatchSandboxRequest, exec_sandbox_event, tcp_forward_init, }; use openshell_core::settings; use openshell_core::{ObjectId, ObjectName, ObjectWorkspace}; @@ -2970,8 +2971,8 @@ pub async fn sandbox_list( { phase.red().to_string() } - Ok(SandboxPhase::Provisioning) => phase.yellow().to_string(), - Ok(SandboxPhase::Deleting) => phase.dimmed().to_string(), + Ok(SandboxPhase::Provisioning | SandboxPhase::Suspending) => phase.yellow().to_string(), + Ok(SandboxPhase::Deleting | SandboxPhase::Suspended) => phase.dimmed().to_string(), _ => phase.to_string(), }; let created = format_epoch_ms( @@ -4146,6 +4147,110 @@ pub async fn sandbox_start( Ok(()) } +/// Suspend a ready sandbox, retaining its memory state, and wait until it is suspended. +pub async fn sandbox_suspend( + server: &str, + name: &str, + workspace: &str, + tls: &TlsOptions, +) -> Result<()> { + let mut client = grpc_client(server, tls).await?; + let sandbox = client + .suspend_sandbox(SuspendSandboxRequest { + name: name.to_string(), + workspace_scope: Some(openshell_core::proto::workspace_selector( + workspace.to_string(), + )), + }) + .await + .into_diagnostic()? + .into_inner() + .sandbox + .ok_or_else(|| miette!("gateway returned no sandbox after suspend"))?; + wait_for_lifecycle_phase(&mut client, sandbox, SandboxPhase::Suspended).await?; + if let Ok(stopped) = stop_forwards_for_sandbox(workspace, name) { + for port in stopped { + eprintln!( + "{} Stopped forward of port {port} for sandbox {name}", + "✓".green().bold(), + ); + } + } + + println!("{} Suspended sandbox {name}", "✓".green().bold()); + Ok(()) +} + +/// Resume a suspended sandbox and wait until it is ready. +pub async fn sandbox_resume( + server: &str, + name: &str, + workspace: &str, + tls: &TlsOptions, +) -> Result<()> { + let mut client = grpc_client(server, tls).await?; + let sandbox = client + .resume_sandbox(ResumeSandboxRequest { + name: name.to_string(), + workspace_scope: Some(openshell_core::proto::workspace_selector( + workspace.to_string(), + )), + restart_if_restore_fails: false, + }) + .await + .into_diagnostic()? + .into_inner() + .sandbox + .ok_or_else(|| miette!("gateway returned no sandbox after resume"))?; + wait_for_lifecycle_phase(&mut client, sandbox, SandboxPhase::Ready).await?; + println!("{} Resumed sandbox {name}", "✓".green().bold()); + Ok(()) +} + +/// Whether `phase` means a lifecycle wait for `target` can no longer succeed +/// without another lifecycle request. +fn lifecycle_phase_blocks_target(target: SandboxPhase, phase: SandboxPhase) -> bool { + match target { + SandboxPhase::Ready => matches!( + phase, + SandboxPhase::Suspending | SandboxPhase::Suspended | SandboxPhase::Deleting + ), + SandboxPhase::Suspended => matches!( + phase, + SandboxPhase::Ready + | SandboxPhase::Starting + | SandboxPhase::Stopping + | SandboxPhase::Stopped + | SandboxPhase::Deleting + ), + SandboxPhase::Stopped => phase == SandboxPhase::Deleting, + _ => false, + } +} + +fn lifecycle_phase_error( + sandbox: &Sandbox, + target: SandboxPhase, + phase: SandboxPhase, +) -> Option { + if phase == SandboxPhase::Error { + let detail = ready_false_condition_message(sandbox.status.as_ref()) + .unwrap_or_else(|| "sandbox entered Error".to_string()); + return Some(miette!( + "{detail} while waiting for {}", + phase_name(target as i32) + )); + } + if lifecycle_phase_blocks_target(target, phase) { + return Some(miette!( + "sandbox entered {} while waiting for {}", + phase_name(phase as i32), + phase_name(target as i32) + )); + } + None +} + async fn wait_for_lifecycle_phase( client: &mut crate::tls::GrpcClient, sandbox: Sandbox, @@ -4155,10 +4260,8 @@ async fn wait_for_lifecycle_phase( if current == target { return Ok(sandbox); } - if current == SandboxPhase::Error { - let detail = ready_false_condition_message(sandbox.status.as_ref()) - .unwrap_or_else(|| "sandbox entered Error".to_string()); - return Err(miette!("{detail} while waiting for {target:?}")); + if let Some(err) = lifecycle_phase_error(&sandbox, target, current) { + return Err(err); } let timeout = Duration::from_secs( @@ -4214,10 +4317,8 @@ async fn wait_for_lifecycle_phase( if phase == target { return Ok(sandbox); } - if phase == SandboxPhase::Error { - let detail = ready_false_condition_message(sandbox.status.as_ref()) - .unwrap_or_else(|| "sandbox entered Error".to_string()); - return Err(miette!(detail)); + if let Some(err) = lifecycle_phase_error(&sandbox, target, phase) { + return Err(err); } } } @@ -7026,6 +7127,41 @@ mod tests { }; use openshell_core::proto::TcpForwardFrame; + #[test] + fn lifecycle_wait_fails_fast_on_phases_that_block_the_target() { + use super::lifecycle_phase_blocks_target; + use openshell_core::proto::SandboxPhase; + + assert!(lifecycle_phase_blocks_target( + SandboxPhase::Ready, + SandboxPhase::Suspended + )); + assert!(lifecycle_phase_blocks_target( + SandboxPhase::Ready, + SandboxPhase::Suspending + )); + assert!(!lifecycle_phase_blocks_target( + SandboxPhase::Ready, + SandboxPhase::Starting + )); + assert!(lifecycle_phase_blocks_target( + SandboxPhase::Suspended, + SandboxPhase::Stopped + )); + assert!(lifecycle_phase_blocks_target( + SandboxPhase::Suspended, + SandboxPhase::Ready + )); + assert!(!lifecycle_phase_blocks_target( + SandboxPhase::Suspended, + SandboxPhase::Suspending + )); + assert!(!lifecycle_phase_blocks_target( + SandboxPhase::Stopped, + SandboxPhase::Suspended + )); + } + #[test] fn draft_approval_error_explains_refreshed_evaluation() { use super::draft_approval_error; diff --git a/crates/openshell-cli/src/ssh.rs b/crates/openshell-cli/src/ssh.rs index a576d5a788..d161a4c165 100644 --- a/crates/openshell-cli/src/ssh.rs +++ b/crates/openshell-cli/src/ssh.rs @@ -490,6 +490,8 @@ async fn canonical_main_has_terminal_result( | SandboxPhase::Error | SandboxPhase::Stopping | SandboxPhase::Stopped + | SandboxPhase::Suspending + | SandboxPhase::Suspended | SandboxPhase::Deleting ) { diff --git a/crates/openshell-cli/tests/ensure_providers_integration.rs b/crates/openshell-cli/tests/ensure_providers_integration.rs index 53ccb70309..be3e4f2e49 100644 --- a/crates/openshell-cli/tests/ensure_providers_integration.rs +++ b/crates/openshell-cli/tests/ensure_providers_integration.rs @@ -183,6 +183,20 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("unused")) } + async fn suspend_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn resume_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + async fn get_sandbox( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/mtls_integration.rs b/crates/openshell-cli/tests/mtls_integration.rs index 2fd266941a..1017712035 100644 --- a/crates/openshell-cli/tests/mtls_integration.rs +++ b/crates/openshell-cli/tests/mtls_integration.rs @@ -137,6 +137,20 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("unused")) } + async fn suspend_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn resume_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + async fn get_sandbox( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/provider_commands_integration.rs b/crates/openshell-cli/tests/provider_commands_integration.rs index 8812daeefe..89247ba718 100644 --- a/crates/openshell-cli/tests/provider_commands_integration.rs +++ b/crates/openshell-cli/tests/provider_commands_integration.rs @@ -338,6 +338,20 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("unused")) } + async fn suspend_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn resume_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + async fn get_sandbox( &self, request: tonic::Request, diff --git a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs index 53f4ef3387..db9c02ffaf 100644 --- a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs +++ b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs @@ -241,6 +241,20 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("unused")) } + async fn suspend_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn resume_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + async fn get_sandbox( &self, request: tonic::Request, @@ -4159,3 +4173,45 @@ async fn service_forward_falls_back_to_session_tokens_once_for_a_legacy_gateway( ); forward.abort(); } + +#[tokio::test] +async fn rejected_suspend_preserves_active_forwards() { + let server = run_server().await; + let fake_ssh_dir = helpers::tempdir().unwrap(); + let xdg_dir = helpers::tempdir().unwrap(); + test_env(&fake_ssh_dir, &xdg_dir) + .run_async(async { + let mut forward = tokio::process::Command::new("sleep") + .arg("60") + .kill_on_drop(true) + .spawn() + .unwrap(); + let directory = xdg_dir.path().join("openshell/forwards/default"); + fs::create_dir_all(&directory).unwrap(); + let pid_file = directory.join("suspend-rejected-8080.pid"); + fs::write( + &pid_file, + format!("{}\tsb-forward\t127.0.0.1", forward.id().unwrap()), + ) + .unwrap(); + let error = run::sandbox_suspend( + &server.endpoint, + "suspend-rejected", + "default", + &test_tls(&server), + ) + .await + .unwrap_err(); + assert!(error.to_string().contains("unused"), "{error:?}"); + assert!( + pid_file.exists(), + "rejected suspension must preserve forward registration" + ); + assert!( + forward.try_wait().unwrap().is_none(), + "rejected suspension must keep the forward process alive" + ); + forward.kill().await.unwrap(); + }) + .await; +} diff --git a/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs b/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs index 48b84a3373..31e67baf0f 100644 --- a/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs +++ b/crates/openshell-cli/tests/sandbox_exec_streaming_integration.rs @@ -236,6 +236,8 @@ mock_gateway! { delete_sandbox(proto::DeleteSandboxRequest) -> proto::DeleteSandboxResponse; stop_sandbox(proto::StopSandboxRequest) -> proto::SandboxResponse; start_sandbox(proto::StartSandboxRequest) -> proto::SandboxResponse; + suspend_sandbox(proto::SuspendSandboxRequest) -> proto::SandboxResponse; + resume_sandbox(proto::ResumeSandboxRequest) -> proto::SandboxResponse; create_ssh_session(proto::CreateSshSessionRequest) -> proto::CreateSshSessionResponse; expose_service(proto::ExposeServiceRequest) -> proto::ServiceEndpointResponse; get_service(proto::GetServiceRequest) -> proto::ServiceEndpointResponse; diff --git a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs index 46f7c31306..497f3ce778 100644 --- a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs +++ b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs @@ -150,6 +150,20 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("unused")) } + async fn suspend_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn resume_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + async fn get_sandbox( &self, request: tonic::Request, diff --git a/crates/openshell-core/src/extension_protocol.rs b/crates/openshell-core/src/extension_protocol.rs index 9de0b05187..0776cd0f2c 100644 --- a/crates/openshell-core/src/extension_protocol.rs +++ b/crates/openshell-core/src/extension_protocol.rs @@ -22,6 +22,9 @@ pub const COMPUTE_LAUNCH_AUTHENTICATION: &str = "openshell.compute.launch-authen /// Driver stages operator-selected external isolation routes for the supervisor. pub const COMPUTE_ISOLATION_BACKEND: &str = "openshell.compute.isolation-backend"; +/// Driver implements `SuspendSandbox` and resuming through `StartSandbox`. +pub const COMPUTE_SUSPEND_RESUME: &str = "openshell.compute.suspend-resume"; + const MAX_IMPLEMENTATION_NAME_BYTES: usize = 128; const MAX_IMPLEMENTATION_VERSION_BYTES: usize = 128; const MAX_CAPABILITY_BYTES: usize = 128; diff --git a/crates/openshell-core/src/telemetry.rs b/crates/openshell-core/src/telemetry.rs index 4fefb08a64..2aca36f92b 100644 --- a/crates/openshell-core/src/telemetry.rs +++ b/crates/openshell-core/src/telemetry.rs @@ -105,6 +105,8 @@ pub enum LifecycleOperation { Delete, Stop, Start, + Suspend, + Resume, Update, } @@ -116,6 +118,8 @@ impl LifecycleOperation { Self::Delete => "delete", Self::Stop => "stop", Self::Start => "start", + Self::Suspend => "suspend", + Self::Resume => "resume", Self::Update => "update", } } diff --git a/crates/openshell-driver-docker/src/lib.rs b/crates/openshell-driver-docker/src/lib.rs index c306377141..3fc8c679b0 100644 --- a/crates/openshell-driver-docker/src/lib.rs +++ b/crates/openshell-driver-docker/src/lib.rs @@ -49,10 +49,10 @@ use openshell_core::proto::compute::v1::{ GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse, GpuResourceCapabilities, GpuResourceRequirements, ListSandboxesRequest, ListSandboxesResponse, MemoryResourceCapabilities, ResourceCapabilities, StartSandboxRequest, StartSandboxResponse, - StopSandboxRequest, StopSandboxResponse, ValidateSandboxCreateRequest, - ValidateSandboxCreateResponse, WatchSandboxesDeletedEvent, WatchSandboxesEvent, - WatchSandboxesPlatformEvent, WatchSandboxesRequest, WatchSandboxesSandboxEvent, - compute_driver_server::ComputeDriver, watch_sandboxes_event, + StopSandboxRequest, StopSandboxResponse, SuspendSandboxRequest, SuspendSandboxResponse, + ValidateSandboxCreateRequest, ValidateSandboxCreateResponse, WatchSandboxesDeletedEvent, + WatchSandboxesEvent, WatchSandboxesPlatformEvent, WatchSandboxesRequest, + WatchSandboxesSandboxEvent, compute_driver_server::ComputeDriver, watch_sandboxes_event, }; use openshell_core::proto_struct::{ deserialize_optional_non_empty_string_list, struct_to_json_value, @@ -3192,6 +3192,15 @@ impl ComputeDriver for ComputeDriverService { .await } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented( + "the Docker compute driver does not support sandbox suspend", + )) + } + async fn stop_sandbox( &self, request: Request, @@ -3373,6 +3382,15 @@ impl ComputeDriver for DockerComputeDriver { span_status.finish(Ok(Response::new(CreateSandboxResponse::default()))) } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented( + "the Docker compute driver does not support sandbox suspend", + )) + } + #[tracing::instrument( name = "docker.stop_sandbox", skip(self, request), diff --git a/crates/openshell-driver-kubernetes/src/grpc.rs b/crates/openshell-driver-kubernetes/src/grpc.rs index 86b0bf4f6b..ddfaac8b10 100644 --- a/crates/openshell-driver-kubernetes/src/grpc.rs +++ b/crates/openshell-driver-kubernetes/src/grpc.rs @@ -10,9 +10,9 @@ use openshell_core::proto::compute::v1::{ DeleteWorkspaceResponse, EnsureWorkspaceRequest, EnsureWorkspaceResponse, GetCapabilitiesRequest, GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse, ListSandboxesRequest, ListSandboxesResponse, StartSandboxRequest, StartSandboxResponse, - StopSandboxRequest, StopSandboxResponse, ValidateSandboxCreateRequest, - ValidateSandboxCreateResponse, WatchSandboxesEvent, WatchSandboxesRequest, - compute_driver_server::ComputeDriver, + StopSandboxRequest, StopSandboxResponse, SuspendSandboxRequest, SuspendSandboxResponse, + ValidateSandboxCreateRequest, ValidateSandboxCreateResponse, WatchSandboxesEvent, + WatchSandboxesRequest, compute_driver_server::ComputeDriver, }; use std::pin::Pin; use tonic::{Request, Response, Status}; @@ -167,6 +167,15 @@ impl ComputeDriver for ComputeDriverService { .await } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented( + "the Kubernetes compute driver does not support sandbox suspend", + )) + } + async fn stop_sandbox( &self, request: Request, diff --git a/crates/openshell-driver-mxc/src/grpc.rs b/crates/openshell-driver-mxc/src/grpc.rs index 4c21172c47..91c61d2088 100644 --- a/crates/openshell-driver-mxc/src/grpc.rs +++ b/crates/openshell-driver-mxc/src/grpc.rs @@ -14,9 +14,9 @@ use openshell_core::proto::compute::v1::{ DeleteWorkspaceResponse, EnsureWorkspaceRequest, EnsureWorkspaceResponse, GetCapabilitiesRequest, GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse, ListSandboxesRequest, ListSandboxesResponse, StartSandboxRequest, StartSandboxResponse, - StopSandboxRequest, StopSandboxResponse, ValidateSandboxCreateRequest, - ValidateSandboxCreateResponse, WatchSandboxesEvent, WatchSandboxesRequest, - compute_driver_server::ComputeDriver, + StopSandboxRequest, StopSandboxResponse, SuspendSandboxRequest, SuspendSandboxResponse, + ValidateSandboxCreateRequest, ValidateSandboxCreateResponse, WatchSandboxesEvent, + WatchSandboxesRequest, compute_driver_server::ComputeDriver, }; use std::pin::Pin; use tonic::{Request, Response, Status}; @@ -113,6 +113,15 @@ impl ComputeDriver for ComputeDriverService { Ok(Response::new(CreateSandboxResponse::default())) } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented( + "the MXC compute driver does not support sandbox suspend", + )) + } + async fn stop_sandbox( &self, request: Request, diff --git a/crates/openshell-driver-podman/src/grpc.rs b/crates/openshell-driver-podman/src/grpc.rs index 25cfd09d7a..6c73772a30 100644 --- a/crates/openshell-driver-podman/src/grpc.rs +++ b/crates/openshell-driver-podman/src/grpc.rs @@ -9,9 +9,9 @@ use openshell_core::proto::compute::v1::{ DeleteWorkspaceRequest, DeleteWorkspaceResponse, EnsureWorkspaceRequest, EnsureWorkspaceResponse, GetCapabilitiesRequest, GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse, ListSandboxesRequest, ListSandboxesResponse, StartSandboxRequest, - StartSandboxResponse, StopSandboxRequest, StopSandboxResponse, ValidateSandboxCreateRequest, - ValidateSandboxCreateResponse, WatchSandboxesEvent, WatchSandboxesRequest, - compute_driver_server::ComputeDriver, + StartSandboxResponse, StopSandboxRequest, StopSandboxResponse, SuspendSandboxRequest, + SuspendSandboxResponse, ValidateSandboxCreateRequest, ValidateSandboxCreateResponse, + WatchSandboxesEvent, WatchSandboxesRequest, compute_driver_server::ComputeDriver, }; use std::pin::Pin; use tonic::{Request, Response, Status}; @@ -155,6 +155,15 @@ impl ComputeDriver for ComputeDriverService { .await } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented( + "the Podman compute driver does not support sandbox suspend", + )) + } + async fn stop_sandbox( &self, request: Request, diff --git a/crates/openshell-driver-vm/src/driver.rs b/crates/openshell-driver-vm/src/driver.rs index 0a1176e7c9..d4905c3a48 100644 --- a/crates/openshell-driver-vm/src/driver.rs +++ b/crates/openshell-driver-vm/src/driver.rs @@ -63,10 +63,10 @@ use openshell_core::proto::compute::v1::{ GpuResourceCapabilities, ListSandboxesRequest, ListSandboxesResponse, MemoryResourceCapabilities, ResolvedWorkloadIdentity, ResourceCapabilities, StartSandboxRequest, StartSandboxResponse, StopSandboxRequest, StopSandboxResponse, - ValidateSandboxCreateRequest, ValidateSandboxCreateResponse, WatchSandboxesDeletedEvent, - WatchSandboxesEvent, WatchSandboxesPlatformEvent, WatchSandboxesRequest, - WatchSandboxesSandboxEvent, WorkloadIdentityRequest, compute_driver_server::ComputeDriver, - watch_sandboxes_event, + SuspendSandboxRequest, SuspendSandboxResponse, ValidateSandboxCreateRequest, + ValidateSandboxCreateResponse, WatchSandboxesDeletedEvent, WatchSandboxesEvent, + WatchSandboxesPlatformEvent, WatchSandboxesRequest, WatchSandboxesSandboxEvent, + WorkloadIdentityRequest, compute_driver_server::ComputeDriver, watch_sandboxes_event, }; use openshell_core::proto_struct::{ deserialize_optional_non_empty_string_list, struct_to_json_value, @@ -4952,6 +4952,15 @@ impl ComputeDriver for VmDriver { })) } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented( + "the VM compute driver does not support sandbox suspend", + )) + } + async fn stop_sandbox( &self, request: Request, diff --git a/crates/openshell-otel/src/grpc.rs b/crates/openshell-otel/src/grpc.rs index e22af83968..8184caae35 100644 --- a/crates/openshell-otel/src/grpc.rs +++ b/crates/openshell-otel/src/grpc.rs @@ -118,6 +118,10 @@ pub mod rpc { "StartSandbox", "openshell.compute.v1.ComputeDriver/StartSandbox", ); + pub const SUSPEND_SANDBOX: ComputeDriverRpc = ComputeDriverRpc::new( + "SuspendSandbox", + "openshell.compute.v1.ComputeDriver/SuspendSandbox", + ); pub const DELETE_SANDBOX: ComputeDriverRpc = ComputeDriverRpc::new( "DeleteSandbox", "openshell.compute.v1.ComputeDriver/DeleteSandbox", @@ -194,6 +198,7 @@ pub fn compute_driver_rpc_operation(path: &str) -> Option { Some("ListSandboxes") => Some(rpc::LIST_SANDBOXES), Some("StopSandbox") => Some(rpc::STOP_SANDBOX), Some("StartSandbox") => Some(rpc::START_SANDBOX), + Some("SuspendSandbox") => Some(rpc::SUSPEND_SANDBOX), Some("DeleteSandbox") => Some(rpc::DELETE_SANDBOX), Some("WatchSandboxes") => Some(rpc::WATCH_SANDBOXES), Some("EnsureWorkspace") => Some(rpc::ENSURE_WORKSPACE), @@ -316,6 +321,7 @@ mod tests { rpc::LIST_SANDBOXES, rpc::STOP_SANDBOX, rpc::START_SANDBOX, + rpc::SUSPEND_SANDBOX, rpc::DELETE_SANDBOX, rpc::WATCH_SANDBOXES, rpc::ENSURE_WORKSPACE, diff --git a/crates/openshell-sandbox-backend/README.md b/crates/openshell-sandbox-backend/README.md index 9045a8edf8..2d4641024d 100644 --- a/crates/openshell-sandbox-backend/README.md +++ b/crates/openshell-sandbox-backend/README.md @@ -26,6 +26,46 @@ negotiator checks major versions and each peer's required capabilities. The built-in runtime does not advertise `openshell.sandbox.suspend-resume` and returns `UNIMPLEMENTED` for those optional RPCs. +## Suspend and resume + +The supervisor's `Describe` metadata lists `openshell.sandbox.suspend-resume` +as supported but not required. The client keeps the backend's negotiated +metadata from each opening and exposes whether it advertised the capability. + +`RunningBoundary::suspend` sends one `SuspendBoundary` call with the boundary +handle, session ID, and generation, and returns the restore reference. It +fails with `Unsupported` when the backend did not advertise the capability and +rejects empty references or references larger than +`MAX_RESTORE_REFERENCE_BYTES` (64 KiB). The supervisor retries only when the +driver signals it again. + +`DelegatedLaunch` contains identity and transport metadata only. A driver can +provision a restored resource through its backend's native integration. For a +backend advertising state retention, an ordinary `OpenBoundary` can report a +restored or explicitly permitted cold-start outcome. The backend enforces the +driver's restore policy; the supervisor does not manage the retained-state handle. + +`OpenShellRuntimeBackend::with_resume` and +`discover_registered_policy_with_resume` take a `ResumeLaunch`. Every boundary +opening for that launch, including policy discovery and transport recovery, +sends `ResumeBoundary` with the same launch request instead of `OpenBoundary`. +Opening fails with `Unsupported` when the backend lacks the capability. A +resume accepts `RESTORED`, or `COLD_START_FALLBACK` only when fallback is +allowed; a fresh launch accepts only `FRESH`. A replay that reports a different +handle or outcome is denied. `BoundBoundary::launch_outcome` reports the +selected launch path. It does not prove restoration has completed. A backend +may retain only the snapshot through policy discovery, Attach, and Confirm, +then perform its restore-and-run operation when StartAgent arrives. No workload +instruction may execute before StartAgent has installed the admitted controls. +Attach may therefore report no process yet, or an already restored frozen process. +StartAgent returns the restored main process rather than launching a duplicate. + +A restore failure discovered at StartAgent fails that call. The backend must +not silently switch the selected path from restoration to a cold start; a +permitted cold-start fallback must be selected when opening the boundary. +The supervisor reports a successful resumed launch only after StartAgent succeeds. +`RunningBoundary::launch_outcome` then reports the completed launch path. + `SandboxProtocol.Exchange` and `.Mediate` begin with the handle from `OpenBoundary`. The server authenticates the stream's bearer, checks the handle against its provisioned sandbox and generation, then accepts typed protobuf diff --git a/crates/openshell-sandbox-backend/src/isolation_protocol.rs b/crates/openshell-sandbox-backend/src/isolation_protocol.rs index 9a740e4191..fccec718cd 100644 --- a/crates/openshell-sandbox-backend/src/isolation_protocol.rs +++ b/crates/openshell-sandbox-backend/src/isolation_protocol.rs @@ -11,6 +11,8 @@ use crate::boundary_protocol::{BoundaryConfig, SandboxRuntimeDescriptor}; use crate::proto::{ExchangeFrame, exchange_frame::Payload}; pub const SANDBOX_PROTOCOL_CAPABILITY: &str = "openshell.sandbox.protocol"; +/// Optional backend support for `SuspendBoundary` and `ResumeBoundary`. +pub const SUSPEND_RESUME_CAPABILITY: &str = "openshell.sandbox.suspend-resume"; const PROTOCOL_VERSION: ProtocolVersion = ProtocolVersion { major: 1, minor: 0 }; /// The built-in runtime supports fresh launches; suspend/resume is optional. @@ -26,13 +28,40 @@ pub fn metadata(implementation: &str) -> PeerMetadata { } } +/// Supervisor metadata: the base contract is required, and the supervisor can +/// drive optional suspend/resume when a backend advertises it. +#[must_use] +pub fn supervisor_metadata(implementation: &str) -> PeerMetadata { + let mut metadata = metadata(implementation); + metadata + .supported_capabilities + .push(SUSPEND_RESUME_CAPABILITY.to_string()); + metadata +} + /// Use the shared extension rules: equal majors and both peers' requirements. pub fn negotiate(local: &PeerMetadata, remote: Option) -> Result<(), tonic::Status> { + negotiate_peer(local, remote).map(drop) +} + +/// Negotiate like [`negotiate`] and return the remote peer's normalized +/// metadata so callers can check its optional capabilities. +pub fn negotiate_peer( + local: &PeerMetadata, + remote: Option, +) -> Result { negotiate_metadata("isolation", "sandbox-protocol", local, remote) - .map(drop) .map_err(|error| tonic::Status::failed_precondition(error.to_string())) } +/// Whether negotiated peer metadata advertises suspend/resume support. +#[must_use] +pub fn supports_suspend_resume(peer: &PeerMetadata) -> bool { + peer.supported_capabilities + .iter() + .any(|capability| capability == SUSPEND_RESUME_CAPABILITY) +} + /// Check native driver coordinates against the protected runtime bootstrap. /// /// The caller must first authenticate the bearer against the provisioned diff --git a/crates/openshell-sandbox-backend/src/lib.rs b/crates/openshell-sandbox-backend/src/lib.rs index a236bbd67a..527a755ee5 100644 --- a/crates/openshell-sandbox-backend/src/lib.rs +++ b/crates/openshell-sandbox-backend/src/lib.rs @@ -24,9 +24,10 @@ pub mod stream_adapter; pub use openshell_core::proto::sandbox::backend::v1 as backend_proto; pub use runtime::{ - BoundBoundary, BoundaryExec, BoundaryLoopbackConnector, BoundaryProcess, BoundaryTerminal, - ConfirmedBoundary, ExecSession, NetworkMediationSource, OpenShellRuntimeBackend, - ProcessAttachment, ReadyBoundary, RunningBoundary, + BoundBoundary, BoundaryExec, BoundaryLaunchOutcome, BoundaryLoopbackConnector, BoundaryProcess, + BoundaryTerminal, ConfirmedBoundary, ExecSession, MAX_RESTORE_REFERENCE_BYTES, + NetworkMediationSource, OpenShellRuntimeBackend, ProcessAttachment, ReadyBoundary, + ResumeLaunch, RunningBoundary, }; pub use runtime::{BoundaryTransport, BoundaryTransportConnector, validate_runtime_coordinates}; diff --git a/crates/openshell-sandbox-backend/src/runtime.rs b/crates/openshell-sandbox-backend/src/runtime.rs index 8e54aa9832..b5d2c56b8e 100644 --- a/crates/openshell-sandbox-backend/src/runtime.rs +++ b/crates/openshell-sandbox-backend/src/runtime.rs @@ -11,8 +11,9 @@ use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::time::{Duration, Instant}; use crate::backend_proto::{ - DescribeIsolationBackendRequest, OpenBoundaryRequest, - isolation_backend_client::IsolationBackendClient, open_boundary_response::LaunchOutcome, + DescribeIsolationBackendRequest, OpenBoundaryRequest, ResumeBoundaryRequest, + SuspendBoundaryRequest, isolation_backend_client::IsolationBackendClient, + open_boundary_response::LaunchOutcome, }; #[cfg(test)] use crate::isolation_protocol::{chunk_data, data_chunk}; @@ -193,7 +194,106 @@ impl BoundaryTransport { } } -/// Host-side `OpenShell` Sandbox Protocol implementation registered with the supervisor. +/// Largest restore reference the supervisor accepts from a backend or driver. +pub const MAX_RESTORE_REFERENCE_BYTES: usize = 64 * 1024; + +/// Restore a suspended boundary instead of opening a fresh one. +/// +/// Every boundary opening for this launch, including policy discovery and +/// transport recovery, replays the same `ResumeBoundary` request. +#[derive(Clone)] +pub struct ResumeLaunch { + restore_reference: Vec, + restart_if_restore_fails: bool, +} + +impl ResumeLaunch { + /// Reject empty or oversized references before any backend call. + pub fn new( + restore_reference: Vec, + restart_if_restore_fails: bool, + ) -> Result { + if restore_reference.is_empty() { + return Err(BackendError::Descriptor( + "restore reference is empty".to_string(), + )); + } + if restore_reference.len() > MAX_RESTORE_REFERENCE_BYTES { + return Err(BackendError::Descriptor(format!( + "restore reference exceeds {MAX_RESTORE_REFERENCE_BYTES} bytes" + ))); + } + Ok(Self { + restore_reference, + restart_if_restore_fails, + }) + } + + pub fn restart_if_restore_fails(&self) -> bool { + self.restart_if_restore_fails + } +} + +impl std::fmt::Debug for ResumeLaunch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ResumeLaunch") + .field("restore_reference", &"[REDACTED]") + .field("restart_if_restore_fails", &self.restart_if_restore_fails) + .finish() + } +} + +/// The selected launch path; restoration may still await `StartAgent`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum BoundaryLaunchOutcome { + Fresh, + Restored, + ColdStartFallback, +} + +impl BoundaryLaunchOutcome { + #[must_use] + pub fn as_str(self) -> &'static str { + match self { + Self::Fresh => "fresh", + Self::Restored => "restored", + Self::ColdStartFallback => "cold_start_fallback", + } + } +} + +/// Accept only the outcomes the requested launch mode permits. +fn validate_launch_outcome( + outcome: i32, + resume: Option<&ResumeLaunch>, + driver_managed_restore: bool, +) -> Result { + let outcome = LaunchOutcome::try_from(outcome).unwrap_or(LaunchOutcome::Unspecified); + match (resume, outcome) { + (None, LaunchOutcome::Fresh) => Ok(BoundaryLaunchOutcome::Fresh), + (None, LaunchOutcome::Restored) if driver_managed_restore => { + Ok(BoundaryLaunchOutcome::Restored) + } + (None, LaunchOutcome::ColdStartFallback) if driver_managed_restore => { + Ok(BoundaryLaunchOutcome::ColdStartFallback) + } + (None, _) => Err(BackendError::Descriptor( + "invalid fresh boundary opening response".to_string(), + )), + (Some(_), LaunchOutcome::Restored) => Ok(BoundaryLaunchOutcome::Restored), + (Some(resume), LaunchOutcome::ColdStartFallback) if resume.restart_if_restore_fails => { + Ok(BoundaryLaunchOutcome::ColdStartFallback) + } + (Some(_), LaunchOutcome::ColdStartFallback) => Err(BackendError::Descriptor( + "backend reported a cold-start fallback that was not permitted".to_string(), + )), + (Some(_), _) => Err(BackendError::Descriptor( + "invalid boundary resume response outcome".to_string(), + )), + } +} + +/// Concrete RPC client used for both in-tree and endpoint-registered backends. #[derive(Debug)] pub struct OpenShellRuntimeBackend { transport: BoundaryTransport, @@ -201,6 +301,7 @@ pub struct OpenShellRuntimeBackend { provider_credentials: openshell_core::provider_credentials::ProviderCredentialState, sandbox_bearer: openshell_core::jwt::SessionBearerTokenSlot, delegated: Option, + resume: Option, } #[derive(Clone)] @@ -242,9 +343,17 @@ impl OpenShellRuntimeBackend { provider_credentials, sandbox_bearer, delegated: None, + resume: None, } } + /// Restore a suspended boundary rather than opening a fresh one. + #[must_use] + pub fn with_resume(mut self, resume: Option) -> Self { + self.resume = resume; + self + } + /// Construct the same RPC client for an operator-registered backend. pub fn registered( backend_name: String, @@ -271,11 +380,30 @@ impl OpenShellRuntimeBackend { descriptor: SandboxRuntimeDescriptor, driver_descriptor: Vec, bearer: openshell_core::jwt::SessionBearerTokenSlot, + ) -> Result<(Option, bool), BackendError> { + Self::discover_registered_policy_with_resume( + backend_name, + descriptor, + driver_descriptor, + bearer, + None, + ) + .await + } + + /// Discover policy for a launch that may restore a suspended boundary. + pub async fn discover_registered_policy_with_resume( + backend_name: String, + descriptor: SandboxRuntimeDescriptor, + driver_descriptor: Vec, + bearer: openshell_core::jwt::SessionBearerTokenSlot, + resume: Option, ) -> Result<(Option, bool), BackendError> { crate::delegated::validate_backend_name(&backend_name)?; validate_runtime_coordinates(&descriptor)?; - let client = + let mut client = BoundaryClient::with_backend(descriptor, bearer, backend_name, driver_descriptor); + client.resume = resume; client.discover_policy().await } @@ -327,6 +455,7 @@ impl OpenShellRuntimeBackend { descriptor.payload.clone(), ); client.transport = self.transport.clone(); + client.resume.clone_from(&self.resume); let client = Arc::new(client); let response = client .call_idempotent(Request::Attach { @@ -476,6 +605,17 @@ impl BoundBoundary { self.host_gateway_ip } + /// The selected launch path. Restoration may still be deferred until + /// `StartAgent`; this value alone does not prove the workload was restored. + pub fn launch_outcome(&self) -> Option { + self.client.launch_outcome.get().copied() + } + + /// Whether the negotiated backend advertised suspend/resume support. + pub fn supports_suspend(&self) -> bool { + self.client.backend_supports_suspend.load(Ordering::Acquire) + } + pub async fn confirm(self: Box) -> Result { let response = self.client.call_idempotent(Request::Confirm).await?; let Response::Confirmed { confirmation } = response else { @@ -595,6 +735,11 @@ pub struct RunningBoundary { } impl RunningBoundary { + /// The launch path completed by the successful `StartAgent` call. + pub fn launch_outcome(&self) -> Option { + self.process.client.launch_outcome.get().copied() + } + pub fn agent(&self) -> Arc { self.process.clone() } @@ -615,6 +760,21 @@ impl RunningBoundary { .await?; expect_response(response, "boundary_terminated") } + + /// Whether the negotiated backend advertised suspend/resume support. + pub fn supports_suspend(&self) -> bool { + self.process + .client + .backend_supports_suspend + .load(Ordering::Acquire) + } + + /// Freeze and fence this generation, returning the backend's opaque + /// restore reference. The caller must not terminate the boundary after a + /// successful suspension. + pub async fn suspend(&self) -> Result, BackendError> { + self.process.client.suspend_boundary().await + } } pub struct BoundaryProcess { @@ -1185,6 +1345,9 @@ struct BoundaryClient { backend_name: String, driver_descriptor: Vec, boundary_handle: std::sync::OnceLock, + resume: Option, + launch_outcome: std::sync::OnceLock, + backend_supports_suspend: AtomicBool, supervisor_instance_id: crate::boundary_protocol::SupervisorInstanceId, sandbox_bearer: openshell_core::jwt::SessionBearerTokenSlot, grpc_channel: tokio::sync::Mutex>, @@ -1378,6 +1541,9 @@ impl BoundaryClient { backend_name, driver_descriptor, boundary_handle: std::sync::OnceLock::new(), + resume: None, + launch_outcome: std::sync::OnceLock::new(), + backend_supports_suspend: AtomicBool::new(false), supervisor_instance_id: crate::boundary_protocol::SupervisorInstanceId::new(), sandbox_bearer, grpc_channel: tokio::sync::Mutex::new(None), @@ -2081,9 +2247,9 @@ impl BoundaryClient { credential: &BoundaryCredential, ) -> Result<(), BackendError> { let mut client = IsolationBackendClient::new(channel) - .max_decoding_message_size(64 * 1024) - .max_encoding_message_size(64 * 1024); - let supervisor = crate::isolation_protocol::metadata("openshell/supervisor"); + .max_decoding_message_size(64 * 1024 + MAX_RESTORE_REFERENCE_BYTES) + .max_encoding_message_size(64 * 1024 + MAX_RESTORE_REFERENCE_BYTES); + let supervisor = crate::isolation_protocol::supervisor_metadata("openshell/supervisor"); let response = client .describe(DescribeIsolationBackendRequest { supervisor: Some(supervisor.clone()), @@ -2091,27 +2257,50 @@ impl BoundaryClient { .await .map_err(control_rpc_error)? .into_inner(); - crate::isolation_protocol::negotiate(&supervisor, response.backend) + let backend = crate::isolation_protocol::negotiate_peer(&supervisor, response.backend) .map_err(control_rpc_error)?; - let mut request = tonic::Request::new(OpenBoundaryRequest { + let supports_suspend = crate::isolation_protocol::supports_suspend_resume(&backend); + let launch = OpenBoundaryRequest { session_id: self.runtime_descriptor.session_id.to_string(), backend_name: self.backend_name.clone(), driver_descriptor: self.driver_descriptor.clone(), - }); - request - .metadata_mut() - .insert("authorization", credential.authorization.clone()); - let response = client - .open_boundary(request) - .await - .map_err(control_rpc_error)? - .into_inner(); - if response.outcome != LaunchOutcome::Fresh as i32 - || response.boundary_id.is_empty() - || response.boundary_id.len() > 128 - { + }; + let response = if let Some(resume) = &self.resume { + if !supports_suspend { + return Err(BackendError::Unsupported(format!( + "isolation backend does not advertise {}; cannot resume a suspended boundary", + crate::isolation_protocol::SUSPEND_RESUME_CAPABILITY + ))); + } + let mut request = tonic::Request::new(ResumeBoundaryRequest { + launch: Some(launch), + restore_reference: resume.restore_reference.clone(), + restart_if_restore_fails: resume.restart_if_restore_fails, + }); + request + .metadata_mut() + .insert("authorization", credential.authorization.clone()); + client + .resume_boundary(request) + .await + .map_err(control_rpc_error)? + .into_inner() + } else { + let mut request = tonic::Request::new(launch); + request + .metadata_mut() + .insert("authorization", credential.authorization.clone()); + client + .open_boundary(request) + .await + .map_err(control_rpc_error)? + .into_inner() + }; + let outcome = + validate_launch_outcome(response.outcome, self.resume.as_ref(), supports_suspend)?; + if response.boundary_id.is_empty() || response.boundary_id.len() > 128 { return Err(BackendError::Descriptor( - "invalid fresh boundary opening response".to_string(), + "invalid boundary opening response handle".to_string(), )); } let handle = self @@ -2122,9 +2311,56 @@ impl BoundaryClient { "boundary handle changed during launch recovery".to_string(), )); } + // Replays of the same launch must report the same outcome. + if *self.launch_outcome.get_or_init(|| outcome) != outcome { + return Err(BackendError::Denied( + "boundary launch outcome changed during launch recovery".to_string(), + )); + } + self.backend_supports_suspend + .store(supports_suspend, Ordering::Release); Ok(()) } + /// Ask the backend to freeze and fence this generation. A single attempt: + /// the compute driver retries by signalling the supervisor again. + async fn suspend_boundary(&self) -> Result, BackendError> { + if !self.backend_supports_suspend.load(Ordering::Acquire) { + return Err(BackendError::Unsupported(format!( + "isolation backend does not advertise {}", + crate::isolation_protocol::SUSPEND_RESUME_CAPABILITY + ))); + } + let boundary_id = self.boundary_handle()?.to_string(); + self.ensure_current_credential_connection().await?; + let credential = BoundaryCredential::capture(&self.sandbox_bearer)?; + let channel = self.grpc_channel().await?; + let mut client = IsolationBackendClient::new(channel) + .max_decoding_message_size(64 * 1024 + MAX_RESTORE_REFERENCE_BYTES) + .max_encoding_message_size(64 * 1024); + let mut request = tonic::Request::new(SuspendBoundaryRequest { + boundary_id, + session_id: self.runtime_descriptor.session_id.to_string(), + generation_id: self.runtime_descriptor.generation.clone(), + }); + request + .metadata_mut() + .insert("authorization", credential.authorization); + let response = tokio::time::timeout(REQUEST_TIMEOUT, client.suspend_boundary(request)) + .await + .map_err(|_| BackendError::Unavailable("boundary suspension timed out".to_string()))? + .map_err(control_rpc_error)? + .into_inner(); + if response.restore_reference.is_empty() + || response.restore_reference.len() > MAX_RESTORE_REFERENCE_BYTES + { + return Err(BackendError::Descriptor(format!( + "backend restore reference must be 1 to {MAX_RESTORE_REFERENCE_BYTES} bytes" + ))); + } + Ok(response.restore_reference) + } + #[cfg(test)] async fn connect_boundary_once(&self) -> Result { connect_boundary_once(&self.runtime_descriptor).await @@ -2539,6 +2775,9 @@ mod tests { opens: Arc, backend_name: String, driver_descriptor: Option>, + resumes: Arc>>, + suspends: Arc>>, + suspend_reference: Result, tonic::Code>, } impl Default for TestIsolationBackend { @@ -2549,6 +2788,25 @@ mod tests { opens: Arc::default(), backend_name: crate::BACKEND_NAME.to_string(), driver_descriptor: None, + resumes: Arc::default(), + suspends: Arc::default(), + suspend_reference: Err(tonic::Code::Unimplemented), + } + } + } + + impl TestIsolationBackend { + /// A backend that advertises optional suspend/resume support. + fn suspendable(outcome: LaunchOutcome) -> Self { + let mut metadata = crate::isolation_protocol::metadata("test/backend"); + metadata + .supported_capabilities + .push(crate::isolation_protocol::SUSPEND_RESUME_CAPABILITY.to_string()); + Self { + metadata: Some(metadata), + outcome: outcome as i32, + suspend_reference: Ok(b"opaque-restore-reference".to_vec()), + ..Self::default() } } } @@ -2593,16 +2851,295 @@ mod tests { async fn suspend_boundary( &self, - _request: tonic::Request, + request: tonic::Request, ) -> Result, tonic::Status> { - Err(tonic::Status::unimplemented("test backend")) + assert!(request.metadata().get("authorization").is_some()); + self.suspends.lock().unwrap().push(request.into_inner()); + match &self.suspend_reference { + Ok(reference) => Ok(tonic::Response::new(SuspendBoundaryResponse { + restore_reference: reference.clone(), + })), + Err(code) => Err(tonic::Status::new(*code, "test backend")), + } } async fn resume_boundary( &self, - _request: tonic::Request, + request: tonic::Request, ) -> Result, tonic::Status> { - Err(tonic::Status::unimplemented("test backend")) + assert!(request.metadata().get("authorization").is_some()); + let request = request.into_inner(); + let launch = request.launch.as_ref().expect("resume carries a launch"); + assert_eq!(launch.backend_name, self.backend_name); + assert!(!launch.session_id.is_empty()); + self.resumes.lock().unwrap().push(request); + Ok(tonic::Response::new(OpenBoundaryResponse { + boundary_id: TEST_BOUNDARY_HANDLE.to_string(), + outcome: self.outcome, + })) + } + } + + /// Serve one TLS connection with `service` and return a client for it. + async fn isolation_control_client( + service: TestIsolationBackend, + resume: Option, + ) -> (BoundaryClient, tokio::task::JoinHandle<()>) { + let certificate = test_certificate(); + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let address = listener.local_addr().unwrap(); + let client_tls = certificate.client_tls.clone(); + let server = tokio::spawn(async move { + let (stream, _) = listener.accept().await.unwrap(); + let stream = tokio_rustls::TlsAcceptor::from(certificate.server_config) + .accept(stream) + .await + .unwrap(); + tonic::transport::Server::builder() + .add_service(IsolationBackendServer::new(service)) + .serve_with_incoming(tokio_stream::iter([Ok::<_, std::io::Error>(TestTlsIo( + Box::new(stream), + ))])) + .await + .unwrap(); + }); + let mut client = BoundaryClient::new( + tls_runtime_descriptor(address, client_tls), + test_bearer(&"a".repeat(32)), + ); + client.resume = resume; + (client, server) + } + + fn resume_launch(restart_if_restore_fails: bool) -> ResumeLaunch { + ResumeLaunch::new( + b"opaque-restore-reference".to_vec(), + restart_if_restore_fails, + ) + .unwrap() + } + + #[test] + fn launch_outcome_validation_matches_launch_mode() { + let strict = resume_launch(false); + let fallback = resume_launch(true); + let cases = [ + ( + LaunchOutcome::Fresh, + None, + Some(BoundaryLaunchOutcome::Fresh), + ), + (LaunchOutcome::Restored, None, None), + (LaunchOutcome::ColdStartFallback, None, None), + (LaunchOutcome::Unspecified, None, None), + ( + LaunchOutcome::Restored, + Some(&strict), + Some(BoundaryLaunchOutcome::Restored), + ), + (LaunchOutcome::ColdStartFallback, Some(&strict), None), + ( + LaunchOutcome::ColdStartFallback, + Some(&fallback), + Some(BoundaryLaunchOutcome::ColdStartFallback), + ), + (LaunchOutcome::Fresh, Some(&fallback), None), + (LaunchOutcome::Unspecified, Some(&fallback), None), + ]; + for (outcome, resume, expected) in cases { + let result = validate_launch_outcome(outcome as i32, resume, false); + match expected { + Some(expected) => assert_eq!(result.unwrap(), expected, "{outcome:?}"), + None => assert!( + matches!(result, Err(BackendError::Descriptor(_))), + "{outcome:?} {resume:?}: {result:?}" + ), + } + } + assert!(validate_launch_outcome(99, Some(&fallback), true).is_err()); + assert_eq!( + validate_launch_outcome(LaunchOutcome::Restored as i32, None, true).unwrap(), + BoundaryLaunchOutcome::Restored + ); + assert_eq!( + validate_launch_outcome(LaunchOutcome::ColdStartFallback as i32, None, true).unwrap(), + BoundaryLaunchOutcome::ColdStartFallback + ); + } + + #[test] + fn resume_launch_rejects_empty_and_oversized_references() { + assert!(ResumeLaunch::new(Vec::new(), false).is_err()); + assert!(ResumeLaunch::new(vec![0; MAX_RESTORE_REFERENCE_BYTES + 1], false).is_err()); + assert!(ResumeLaunch::new(vec![0; MAX_RESTORE_REFERENCE_BYTES], false).is_ok()); + let debug = format!("{:?}", resume_launch(true)); + assert!(!debug.contains("opaque-restore-reference"), "{debug}"); + } + + #[tokio::test] + async fn driver_provisioned_restore_uses_normal_boundary_opening() { + let service = TestIsolationBackend::suspendable(LaunchOutcome::Restored); + let resumes = service.resumes.clone(); + let opens = service.opens.clone(); + let (client, server) = isolation_control_client(service, None).await; + client.grpc_channel().await.unwrap(); + assert_eq!( + client.launch_outcome.get().copied(), + Some(BoundaryLaunchOutcome::Restored) + ); + assert_eq!(opens.load(Ordering::Acquire), 1); + assert!(resumes.lock().unwrap().is_empty()); + server.abort(); + } + + #[tokio::test] + async fn resume_sends_resume_boundary_and_records_restored_outcome() { + let service = TestIsolationBackend::suspendable(LaunchOutcome::Restored); + let resumes = service.resumes.clone(); + let opens = service.opens.clone(); + let (client, server) = isolation_control_client(service, Some(resume_launch(false))).await; + client.grpc_channel().await.unwrap(); + assert_eq!( + client.launch_outcome.get().copied(), + Some(BoundaryLaunchOutcome::Restored) + ); + assert!(client.backend_supports_suspend.load(Ordering::Acquire)); + assert_eq!( + opens.load(Ordering::Acquire), + 0, + "resume must not open fresh" + ); + let resumes = resumes.lock().unwrap().clone(); + assert_eq!(resumes.len(), 1); + assert_eq!(resumes[0].restore_reference, b"opaque-restore-reference"); + assert!(!resumes[0].restart_if_restore_fails); + assert_eq!( + resumes[0].launch.as_ref().unwrap().session_id, + test_session_id().to_string() + ); + server.abort(); + } + + #[tokio::test] + async fn resume_accepts_cold_start_fallback_only_when_allowed() { + let service = TestIsolationBackend::suspendable(LaunchOutcome::ColdStartFallback); + let resumes = service.resumes.clone(); + let (client, server) = isolation_control_client(service, Some(resume_launch(true))).await; + client.grpc_channel().await.unwrap(); + assert_eq!( + client.launch_outcome.get().copied(), + Some(BoundaryLaunchOutcome::ColdStartFallback) + ); + assert!(resumes.lock().unwrap()[0].restart_if_restore_fails); + server.abort(); + + let service = TestIsolationBackend::suspendable(LaunchOutcome::ColdStartFallback); + let (client, server) = isolation_control_client(service, Some(resume_launch(false))).await; + let result = client.grpc_channel().await; + assert!( + matches!(result, Err(BackendError::Descriptor(_))), + "{result:?}" + ); + assert!(client.boundary_handle.get().is_none()); + server.abort(); + } + + #[tokio::test] + async fn resume_rejects_fresh_and_unspecified_outcomes() { + for outcome in [LaunchOutcome::Fresh, LaunchOutcome::Unspecified] { + let service = TestIsolationBackend::suspendable(outcome); + let (client, server) = + isolation_control_client(service, Some(resume_launch(true))).await; + let result = client.grpc_channel().await; + assert!( + matches!(result, Err(BackendError::Descriptor(_))), + "{outcome:?}: {result:?}" + ); + server.abort(); + } + } + + #[tokio::test] + async fn resume_requires_backend_suspend_resume_capability() { + let service = TestIsolationBackend { + outcome: LaunchOutcome::Restored as i32, + ..TestIsolationBackend::default() + }; + let resumes = service.resumes.clone(); + let opens = service.opens.clone(); + let (client, server) = isolation_control_client(service, Some(resume_launch(true))).await; + let result = client.grpc_channel().await; + assert!( + matches!(result, Err(BackendError::Unsupported(_))), + "{result:?}" + ); + assert!(resumes.lock().unwrap().is_empty()); + assert_eq!(opens.load(Ordering::Acquire), 0); + server.abort(); + } + + #[tokio::test] + async fn supervisor_advertises_suspend_resume_as_optional() { + let metadata = crate::isolation_protocol::supervisor_metadata("openshell/supervisor"); + assert!(crate::isolation_protocol::supports_suspend_resume( + &metadata + )); + assert!( + !metadata.required_capabilities.iter().any( + |capability| capability == crate::isolation_protocol::SUSPEND_RESUME_CAPABILITY + ) + ); + // Backends that do not advertise the capability still negotiate. + let (client, server) = + isolation_control_client(TestIsolationBackend::default(), None).await; + client.grpc_channel().await.unwrap(); + assert_eq!( + client.launch_outcome.get().copied(), + Some(BoundaryLaunchOutcome::Fresh) + ); + assert!(!client.backend_supports_suspend.load(Ordering::Acquire)); + let result = client.suspend_boundary().await; + assert!( + matches!(result, Err(BackendError::Unsupported(_))), + "{result:?}" + ); + server.abort(); + } + + #[tokio::test] + async fn suspend_sends_boundary_coordinates_and_returns_reference() { + let service = TestIsolationBackend::suspendable(LaunchOutcome::Fresh); + let suspends = service.suspends.clone(); + let (client, server) = isolation_control_client(service, None).await; + client.grpc_channel().await.unwrap(); + assert!(client.backend_supports_suspend.load(Ordering::Acquire)); + let reference = client.suspend_boundary().await.unwrap(); + assert_eq!(reference, b"opaque-restore-reference"); + let suspends = suspends.lock().unwrap().clone(); + assert_eq!(suspends.len(), 1); + assert_eq!(suspends[0].boundary_id, TEST_BOUNDARY_HANDLE); + assert_eq!(suspends[0].session_id, test_session_id().to_string()); + assert_eq!(suspends[0].generation_id, "test-generation"); + server.abort(); + } + + #[tokio::test] + async fn suspend_rejects_backend_failures_and_invalid_references() { + for reference in [ + Err(tonic::Code::FailedPrecondition), + Err(tonic::Code::Unavailable), + Ok(Vec::new()), + Ok(vec![0; MAX_RESTORE_REFERENCE_BYTES + 1]), + ] { + let service = TestIsolationBackend { + suspend_reference: reference.clone(), + ..TestIsolationBackend::suspendable(LaunchOutcome::Fresh) + }; + let (client, server) = isolation_control_client(service, None).await; + client.grpc_channel().await.unwrap(); + let result = client.suspend_boundary().await; + assert!(result.is_err(), "{:?}", reference.map(|bytes| bytes.len())); + server.abort(); } } diff --git a/crates/openshell-sandbox-backend/src/runtime/test_support.rs b/crates/openshell-sandbox-backend/src/runtime/test_support.rs index 6e94701548..4d7898d9a6 100644 --- a/crates/openshell-sandbox-backend/src/runtime/test_support.rs +++ b/crates/openshell-sandbox-backend/src/runtime/test_support.rs @@ -109,6 +109,19 @@ struct Peer { terminal: Option>, processes: Mutex>>, terminals: Mutex>>, + suspend: Option, + main_released: std::sync::atomic::AtomicBool, + main_release: tokio::sync::Notify, +} + +/// Optional suspend/resume behavior for an in-process test backend. +#[derive(Clone)] +pub struct Suspension { + /// Reference returned by every `SuspendBoundary` call and the only one + /// `ResumeBoundary` restores. + pub reference: Vec, + /// Counts `SuspendBoundary` calls. + pub calls: Arc, } type Stream = @@ -152,6 +165,25 @@ impl Peer { drop(handler); return std::future::pending().await; } + // A suspendable peer keeps the main process running until the + // supervisor signals or terminates it. + if self.suspend.is_some() { + use std::sync::atomic::Ordering; + match &request.request { + Request::Wait { .. } => loop { + let released = self.main_release.notified(); + if self.main_released.load(Ordering::SeqCst) { + break; + } + released.await; + }, + Request::Signal { .. } | Request::Terminate { .. } => { + self.main_released.store(true, Ordering::SeqCst); + self.main_release.notify_waiters(); + } + _ => {} + } + } let response = handler(request.request).unwrap_or_else(|e| Response::Error { kind: match e.kind() { BackendErrorKind::Unsupported => w::BoundaryErrorKind::Unsupported, @@ -686,7 +718,7 @@ fn client(peer: Peer) -> Arc { tonic::transport::Server::builder() .add_service( crate::backend_proto::isolation_backend_server::IsolationBackendServer::new( - Service(Arc::new(Peer::default())), + Service(server_peer.clone()), ), ) .add_service(SandboxProtocolServer::new(Service(server_peer))) @@ -803,9 +835,15 @@ impl crate::backend_proto::isolation_backend_server::IsolationBackend for Servic tonic::Response, tonic::Status, > { + let mut backend = crate::isolation_protocol::metadata("test-peer"); + if self.0.suspend.is_some() { + backend + .supported_capabilities + .push(crate::isolation_protocol::SUSPEND_RESUME_CAPABILITY.into()); + } Ok(tonic::Response::new( crate::backend_proto::DescribeIsolationBackendResponse { - backend: Some(crate::isolation_protocol::metadata("test-peer")), + backend: Some(backend), }, )) } @@ -824,13 +862,37 @@ impl crate::backend_proto::isolation_backend_server::IsolationBackend for Servic &self, _: tonic::Request, ) -> Result, tonic::Status> { - Err(tonic::Status::unimplemented("test peer")) + let Some(suspend) = &self.0.suspend else { + return Err(tonic::Status::unimplemented("test peer")); + }; + suspend + .calls + .fetch_add(1, std::sync::atomic::Ordering::SeqCst); + Ok(tonic::Response::new( + crate::backend_proto::SuspendBoundaryResponse { + restore_reference: suspend.reference.clone(), + }, + )) } async fn resume_boundary( &self, - _: tonic::Request, + request: tonic::Request, ) -> Result, tonic::Status> { - Err(tonic::Status::unimplemented("test peer")) + let Some(suspend) = &self.0.suspend else { + return Err(tonic::Status::unimplemented("test peer")); + }; + if request.into_inner().restore_reference != suspend.reference { + return Err(tonic::Status::failed_precondition( + "unknown restore reference", + )); + } + Ok(tonic::Response::new( + crate::backend_proto::OpenBoundaryResponse { + boundary_id: "test".into(), + outcome: crate::backend_proto::open_boundary_response::LaunchOutcome::Restored + as i32, + }, + )) } } @@ -844,9 +906,37 @@ pub fn backend( credentials: ProviderCredentialState, bearer: SessionBearerTokenSlot, handler: Handler, +) -> crate::OpenShellRuntimeBackend { + suspendable_backend( + name, + sandbox, + generation, + payload, + ca, + credentials, + bearer, + handler, + None, + ) +} + +/// Like [`backend`], optionally advertising suspend/resume. A suspendable +/// peer never answers `Wait`, so the main process runs until suspension. +#[allow(clippy::too_many_arguments)] +pub fn suspendable_backend( + name: String, + sandbox: SandboxContext, + generation: String, + payload: Vec, + ca: Arc>>, + credentials: ProviderCredentialState, + bearer: SessionBearerTokenSlot, + handler: Handler, + suspend: Option, ) -> crate::OpenShellRuntimeBackend { let peer = client(Peer { handler: Mutex::new(Some(handler)), + suspend, ..Peer::default() }); let mut descriptor = peer.runtime_descriptor.clone(); diff --git a/crates/openshell-sdk/src/client.rs b/crates/openshell-sdk/src/client.rs index 69b75ffbd2..d0904245bc 100644 --- a/crates/openshell-sdk/src/client.rs +++ b/crates/openshell-sdk/src/client.rs @@ -15,8 +15,8 @@ use crate::pagination::{Page, Pager}; use crate::raw::AuthedGrpcClient; use crate::refresh::{RefreshedToken, TokenSource}; use crate::types::{ - DeleteOptions, DeletionResult, ExecOptions, ExecResult, Health, ListOptions, SandboxPhase, - SandboxRef, SandboxSpec, SandboxTemplateCreateSpec, SandboxTemplateListOptions, + DeleteOptions, DeletionResult, ExecOptions, ExecResult, Health, ListOptions, ResumeOptions, + SandboxPhase, SandboxRef, SandboxSpec, SandboxTemplateCreateSpec, SandboxTemplateListOptions, SandboxWorkloadTemplate, WorkspaceRef, }; use crate::{WatchEvent, WatchOptions, transport}; @@ -400,6 +400,38 @@ impl OpenShellClient { sandbox_from_response(response.sandbox) } + /// Suspend a ready sandbox by name, retaining its memory state. + /// + /// Requires a compute driver and isolation backend that support suspend + /// and resume. The gateway returns `FAILED_PRECONDITION` otherwise. + pub async fn suspend_sandbox(&self, name: &str) -> Result { + let response = self + .unary(|mut grpc| { + let request = proto::SuspendSandboxRequest { + name: name.to_string(), + workspace_scope: Some(proto::workspace_selector("default")), + }; + async move { grpc.suspend_sandbox(request).await } + }) + .await?; + sandbox_from_response(response.sandbox) + } + + /// Resume a suspended sandbox by name in a new runtime generation. + pub async fn resume_sandbox(&self, name: &str, opts: ResumeOptions) -> Result { + let response = self + .unary(|mut grpc| { + let request = proto::ResumeSandboxRequest { + name: name.to_string(), + workspace_scope: Some(proto::workspace_selector("default")), + restart_if_restore_fails: opts.restart_if_restore_fails, + }; + async move { grpc.resume_sandbox(request).await } + }) + .await?; + sandbox_from_response(response.sandbox) + } + /// Poll [`OpenShellClient::get_sandbox`] until the sandbox reaches /// [`SandboxPhase::Ready`] or successful [`SandboxPhase::Completed`], or /// until the `timeout` elapses. @@ -407,7 +439,8 @@ impl OpenShellClient { /// Returns the terminal sandbox snapshot on success. Returns an /// [`SdkError::Connect`] when the timeout expires, or whatever error /// the gateway returns if the sandbox transitions into - /// [`SandboxPhase::Stopped`] or [`SandboxPhase::Error`]. + /// [`SandboxPhase::Stopped`], [`SandboxPhase::Error`], + /// [`SandboxPhase::Suspending`], or [`SandboxPhase::Suspended`]. pub async fn wait_ready(&self, name: &str, timeout: Duration) -> Result { self.wait_for(name, timeout, |phase| match phase { SandboxPhase::Ready | SandboxPhase::Completed => Some(Ok(())), @@ -417,6 +450,9 @@ impl OpenShellClient { SandboxPhase::Error => Some(Err(SdkError::connect(format!( "sandbox '{name}' entered error phase" )))), + SandboxPhase::Suspending | SandboxPhase::Suspended => Some(Err(SdkError::connect( + format!("sandbox '{name}' is suspended; resume it before waiting for ready"), + ))), _ => None, }) .await @@ -1118,6 +1154,40 @@ impl WorkspaceScopedClient { sandbox_from_response(response.sandbox) } + /// Suspend a ready sandbox by name in this workspace, retaining its memory state. + /// + /// Requires a compute driver and isolation backend that support suspend + /// and resume. The gateway returns `FAILED_PRECONDITION` otherwise. + pub async fn suspend_sandbox(&self, name: &str) -> Result { + let response = self + .client + .unary(|mut grpc| { + let request = proto::SuspendSandboxRequest { + name: name.to_string(), + workspace_scope: Some(proto::workspace_selector(&self.workspace)), + }; + async move { grpc.suspend_sandbox(request).await } + }) + .await?; + sandbox_from_response(response.sandbox) + } + + /// Resume a suspended sandbox by name in this workspace in a new runtime generation. + pub async fn resume_sandbox(&self, name: &str, opts: ResumeOptions) -> Result { + let response = self + .client + .unary(|mut grpc| { + let request = proto::ResumeSandboxRequest { + name: name.to_string(), + workspace_scope: Some(proto::workspace_selector(&self.workspace)), + restart_if_restore_fails: opts.restart_if_restore_fails, + }; + async move { grpc.resume_sandbox(request).await } + }) + .await?; + sandbox_from_response(response.sandbox) + } + /// Poll until the sandbox reaches [`SandboxPhase::Ready`] or successful /// [`SandboxPhase::Completed`], or the timeout elapses. pub async fn wait_ready(&self, name: &str, timeout: Duration) -> Result { @@ -1139,6 +1209,11 @@ impl WorkspaceScopedClient { "sandbox '{name}' entered error phase" ))); } + SandboxPhase::Suspending | SandboxPhase::Suspended => { + return Err(SdkError::connect(format!( + "sandbox '{name}' is suspended; resume it before waiting for ready" + ))); + } _ => {} } if Instant::now() >= deadline { diff --git a/crates/openshell-sdk/src/lib.rs b/crates/openshell-sdk/src/lib.rs index 950d1285ff..83793bc543 100644 --- a/crates/openshell-sdk/src/lib.rs +++ b/crates/openshell-sdk/src/lib.rs @@ -51,9 +51,10 @@ pub use pagination::{Page, Pager}; pub use refresh::{Refresh, RefreshError, RefreshedToken, TokenSource}; pub use types::{ DeleteOptions, DeletionOutcome, DeletionResult, ExecOptions, ExecResult, Health, ListOptions, - LogLine, PlatformEvent, SandboxPhase, SandboxRef, SandboxResources, SandboxRestartPolicy, - SandboxServiceLevel, SandboxSpec, SandboxStartup, SandboxTemplateCreateSpec, - SandboxTemplateListOptions, SandboxWorkloadConfig, SandboxWorkloadTemplate, - SandboxWorkloadTemplateProvenance, SandboxWorkloadTemplateSpec, ServiceAuthorizationMode, - ServiceExposure, ServiceStatus, WatchEvent, WatchOptions, WorkspaceRef, + LogLine, PlatformEvent, ResumeOptions, SandboxPhase, SandboxRef, SandboxResources, + SandboxRestartPolicy, SandboxServiceLevel, SandboxSpec, SandboxStartup, + SandboxTemplateCreateSpec, SandboxTemplateListOptions, SandboxWorkloadConfig, + SandboxWorkloadTemplate, SandboxWorkloadTemplateProvenance, SandboxWorkloadTemplateSpec, + ServiceAuthorizationMode, ServiceExposure, ServiceStatus, WatchEvent, WatchOptions, + WorkspaceRef, }; diff --git a/crates/openshell-sdk/src/raw.rs b/crates/openshell-sdk/src/raw.rs index dd3b7b165b..faca71fb59 100644 --- a/crates/openshell-sdk/src/raw.rs +++ b/crates/openshell-sdk/src/raw.rs @@ -28,11 +28,12 @@ pub use openshell_core::proto::{ ListSandboxTemplatesRequest, ListSandboxesRequest, ListWorkspacesRequest, ProviderDesiredIdentity, ProviderMutationKind, ProviderMutationReceipt, ProviderReadinessObservation, ProviderReadinessReason, ProviderReadinessState, - ProviderReadinessStatus, Sandbox, SandboxPhase as ProtoSandboxPhase, SandboxResources, - SandboxServiceLevel, SandboxSpec as ProtoSandboxSpec, SandboxStartup, SandboxTemplate, - SandboxTemplateResponse, SandboxWorkloadConfig, SandboxWorkloadTemplate, + ProviderReadinessStatus, ResumeSandboxRequest, Sandbox, SandboxPhase as ProtoSandboxPhase, + SandboxResources, SandboxServiceLevel, SandboxSpec as ProtoSandboxSpec, SandboxStartup, + SandboxTemplate, SandboxTemplateResponse, SandboxWorkloadConfig, SandboxWorkloadTemplate, SandboxWorkloadTemplateProvenance, SandboxWorkloadTemplateSpec, - ServiceStatus as ProtoServiceStatus, StartSandboxRequest, StopSandboxRequest, Workspace, + ServiceStatus as ProtoServiceStatus, StartSandboxRequest, StopSandboxRequest, + SuspendSandboxRequest, Workspace, }; /// Type alias for the gRPC client wrapped in the SDK's auth interceptor. diff --git a/crates/openshell-sdk/src/types.rs b/crates/openshell-sdk/src/types.rs index e4b66942dd..571ee42b68 100644 --- a/crates/openshell-sdk/src/types.rs +++ b/crates/openshell-sdk/src/types.rs @@ -23,6 +23,14 @@ pub struct DeleteOptions { pub allow_missing: bool, } +/// Options for resuming a suspended sandbox. +#[derive(Clone, Copy, Debug, Default)] +pub struct ResumeOptions { + /// Boot the workload cleanly when the retained memory state cannot be + /// restored. When false, resume fails instead. + pub restart_if_restore_fails: bool, +} + /// A deletion acknowledgement is not necessarily completion. #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[non_exhaustive] @@ -215,6 +223,8 @@ pub enum SandboxPhase { Stopped, Starting, Completed, + Suspending, + Suspended, } impl From for SandboxPhase { @@ -230,6 +240,8 @@ impl From for SandboxPhase { proto::SandboxPhase::Stopped => Self::Stopped, proto::SandboxPhase::Starting => Self::Starting, proto::SandboxPhase::Completed => Self::Completed, + proto::SandboxPhase::Suspending => Self::Suspending, + proto::SandboxPhase::Suspended => Self::Suspended, } } } diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index 56ea582109..ce7ac3b364 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -57,6 +57,8 @@ struct MockState { last_delete_workspace: Mutex>, last_stop: Mutex>, last_start: Mutex>, + last_suspend: Mutex>, + last_resume: Mutex>, last_list_request: Mutex>, list_requests: Mutex>, last_exec_request: Mutex>, @@ -452,6 +454,40 @@ impl OpenShell for TestOpenShell { })) } + async fn suspend_sandbox( + &self, + request: tonic::Request, + ) -> Result, Status> { + let request = request.into_inner(); + let sandbox = sandbox_with_phase_ws( + request.name.as_str(), + proto::SandboxPhase::Suspending, + selected_workspace(&request.workspace_scope).unwrap_or_default(), + ); + *self.state.last_suspend.lock().await = Some(request); + Ok(Response::new(proto::SandboxResponse { + sandbox: Some(sandbox), + service_urls: HashMap::new(), + })) + } + + async fn resume_sandbox( + &self, + request: tonic::Request, + ) -> Result, Status> { + let request = request.into_inner(); + let sandbox = sandbox_with_phase_ws( + request.name.as_str(), + proto::SandboxPhase::Starting, + selected_workspace(&request.workspace_scope).unwrap_or_default(), + ); + *self.state.last_resume.lock().await = Some(request); + Ok(Response::new(proto::SandboxResponse { + sandbox: Some(sandbox), + service_urls: HashMap::new(), + })) + } + async fn get_sandbox( &self, request: tonic::Request, @@ -1461,6 +1497,63 @@ async fn stop_and_start_map_requests_and_phases() { assert_eq!(selected_workspace(&start.workspace_scope), Some("team-a")); } +#[tokio::test] +async fn suspend_and_resume_map_requests_and_phases() { + let state = Arc::new(MockState::default()); + let endpoint = start_mock(state.clone()).await; + let client = connect(&endpoint).await; + + let suspended = client.suspend_sandbox("frozen").await.unwrap(); + assert_eq!(suspended.phase, SandboxPhase::Suspending); + let suspend = state.last_suspend.lock().await.clone().unwrap(); + assert_eq!(suspend.name, "frozen"); + assert_eq!( + selected_workspace(&suspend.workspace_scope), + Some("default") + ); + + let resumed = client + .workspace("team-a") + .resume_sandbox( + "frozen", + openshell_sdk::ResumeOptions { + restart_if_restore_fails: true, + }, + ) + .await + .unwrap(); + assert_eq!(resumed.phase, SandboxPhase::Starting); + let resume = state.last_resume.lock().await.clone().unwrap(); + assert_eq!(resume.name, "frozen"); + assert!(resume.restart_if_restore_fails); + assert_eq!(selected_workspace(&resume.workspace_scope), Some("team-a")); + + client + .resume_sandbox("frozen", openshell_sdk::ResumeOptions::default()) + .await + .unwrap(); + let resume = state.last_resume.lock().await.clone().unwrap(); + assert!(!resume.restart_if_restore_fails); + assert_eq!(selected_workspace(&resume.workspace_scope), Some("default")); +} + +#[tokio::test] +async fn wait_ready_fails_fast_on_suspended_phase() { + let state = Arc::new(MockState { + phase_sequence: vec![proto::SandboxPhase::Suspended], + ..Default::default() + }); + let endpoint = start_mock(state).await; + let client = connect(&endpoint).await; + + let err = client + .wait_ready("frozen", Duration::from_secs(5)) + .await + .unwrap_err(); + assert_eq!(err.code(), "connect"); + assert!(err.to_string().contains("suspended"), "{err}"); +} + #[tokio::test] async fn wait_ready_transitions_through_phases() { let state = Arc::new(MockState { diff --git a/crates/openshell-server/src/auth/method_authz.rs b/crates/openshell-server/src/auth/method_authz.rs index e00357b8ac..fcdc1e25df 100644 --- a/crates/openshell-server/src/auth/method_authz.rs +++ b/crates/openshell-server/src/auth/method_authz.rs @@ -213,6 +213,8 @@ mod tests { for path in [ "/openshell.v1.OpenShell/StopSandbox", "/openshell.v1.OpenShell/StartSandbox", + "/openshell.v1.OpenShell/SuspendSandbox", + "/openshell.v1.OpenShell/ResumeSandbox", ] { let entry = lookup(path).expect("lifecycle RPC must have auth metadata"); assert_eq!(entry.auth_mode, AuthMode::Bearer); diff --git a/crates/openshell-server/src/auth/sandbox_methods.rs b/crates/openshell-server/src/auth/sandbox_methods.rs index 29e56563cc..498e2a0dd9 100644 --- a/crates/openshell-server/src/auth/sandbox_methods.rs +++ b/crates/openshell-server/src/auth/sandbox_methods.rs @@ -45,6 +45,12 @@ mod tests { )); assert!(!is_sandbox_callable("/openshell.v1.OpenShell/StopSandbox")); assert!(!is_sandbox_callable("/openshell.v1.OpenShell/StartSandbox")); + assert!(!is_sandbox_callable( + "/openshell.v1.OpenShell/SuspendSandbox" + )); + assert!(!is_sandbox_callable( + "/openshell.v1.OpenShell/ResumeSandbox" + )); assert!(!is_sandbox_callable( "/openshell.v1.OpenShell/CreateProvider" )); diff --git a/crates/openshell-server/src/auth/sandbox_session.rs b/crates/openshell-server/src/auth/sandbox_session.rs index dc9e424240..6e6eb57d7b 100644 --- a/crates/openshell-server/src/auth/sandbox_session.rs +++ b/crates/openshell-server/src/auth/sandbox_session.rs @@ -279,11 +279,14 @@ async fn load_identity( })?; let phase = SandboxPhase::try_from(sandbox.phase()).unwrap_or(SandboxPhase::Unknown); + // A suspending runtime stays live until its supervisor captures the + // workload and exits; a suspended runtime's identity is never reused. if !matches!( phase, SandboxPhase::Provisioning | SandboxPhase::Ready | SandboxPhase::Starting + | SandboxPhase::Suspending | SandboxPhase::Completed | SandboxPhase::Error ) { @@ -533,6 +536,26 @@ mod tests { assert_eq!(error.reason, AuthFailureReason::StaleIdentity); } + #[tokio::test] + async fn suspension_revokes_runtime_identity_only_once_settled() { + let store = Store::connect("sqlite::memory:").await.expect("store"); + persist_sandbox(&store, SandboxPhase::Suspending).await; + authorize_persisted(&store, &principal(1, Uuid::from_u128(1))) + .await + .expect("suspending runtime is still live"); + + store + .update_message_cas::("sandbox-a", 0, |sandbox| { + sandbox.set_phase(SandboxPhase::Suspended as i32); + }) + .await + .expect("suspend sandbox"); + let error = authorize_persisted(&store, &principal(1, Uuid::from_u128(1))) + .await + .expect_err("suspended runtime must reject its token"); + assert_eq!(error.reason, AuthFailureReason::StaleIdentity); + } + #[tokio::test] async fn terminal_runtime_remains_authorized_for_exit_delivery() { for phase in [SandboxPhase::Completed, SandboxPhase::Error] { diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index 1ec4cfd522..ea48d3b9e9 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -40,8 +40,8 @@ use openshell_core::proto::compute::v1::{ GpuResourceRequirements as DriverGpuResourceRequirements, ListSandboxesRequest, ResourceCapabilities as DriverResourceCapabilities, ResourceRequirements as DriverSandboxResourceRequirements, StartSandboxRequest, - StopSandboxRequest, ValidateSandboxCreateRequest, WatchSandboxesEvent, WatchSandboxesRequest, - WorkloadIdentityRequest, compute_driver_client::ComputeDriverClient, + StopSandboxRequest, SuspendSandboxRequest, ValidateSandboxCreateRequest, WatchSandboxesEvent, + WatchSandboxesRequest, WorkloadIdentityRequest, compute_driver_client::ComputeDriverClient, compute_driver_server::ComputeDriver, watch_sandboxes_event, }; use openshell_core::proto::{ @@ -71,6 +71,12 @@ pub const COMPUTE_DRIVER_ANNOTATION: &str = "internal.openshell.ai/compute-drive const ISOLATION_BACKEND_ANNOTATION: &str = "internal.openshell.ai/isolation-backend"; pub const COMPUTE_RUNTIME_IDENTITY_ANNOTATION: &str = "internal.openshell.ai/compute-runtime-identity"; +/// Durable intent of an in-flight `Starting` transition that resumes retained +/// state. Bound to the runtime generation it was written for so retries and +/// gateway-restart recovery send the same driver request, and so a stale value +/// can never turn a later start into a resume. +const RESUME_INTENT_ANNOTATION: &str = "internal.openshell.ai/resume-intent"; + #[cfg(unix)] use tower::service_fn; use tracing::{Instrument as _, debug, info, warn}; @@ -86,6 +92,12 @@ fn supports_isolation_registration(capabilities: &[String]) -> bool { }) } +fn supports_suspend_resume(capabilities: &[String]) -> bool { + capabilities + .iter() + .any(|capability| capability == openshell_core::extension_protocol::COMPUTE_SUSPEND_RESUME) +} + use provisioning_operation::ProvisioningOperationError; /// Driver-specific values that must be delivered atomically with sandbox /// creation without expanding the public compute-driver protobuf contract. @@ -353,6 +365,121 @@ enum BeginDelete { AlreadyDeleting, } +/// Explicit lifecycle operations that quiesce a running sandbox: an ordinary +/// stop, or a suspend whose driver retains the workload's memory state. +/// +/// Both share one durable shape: an in-flight phase committed before the +/// owned driver call, and a gateway-owned settled phase committed after it. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum QuiesceOperation { + Stop, + Suspend, +} + +/// What an explicit quiesce request does with the current durable phase. +enum QuiesceAdmission { + /// The requested state is already durable. + Settled, + /// Retry the idempotent driver call for the persisted transition. + Retry, + /// Persist a new transition. + Begin, +} + +impl QuiesceOperation { + const fn verb(self) -> &'static str { + match self { + Self::Stop => "stop", + Self::Suspend => "suspend", + } + } + + const fn in_flight_phase(self) -> SandboxPhase { + match self { + Self::Stop => SandboxPhase::Stopping, + Self::Suspend => SandboxPhase::Suspending, + } + } + + const fn settled_phase(self) -> SandboxPhase { + match self { + Self::Stop => SandboxPhase::Stopped, + Self::Suspend => SandboxPhase::Suspended, + } + } + + const fn requested_condition(self) -> (&'static str, &'static str) { + match self { + Self::Stop => ("Stopping", "Sandbox stop requested"), + Self::Suspend => ("Suspending", "Sandbox suspend requested"), + } + } + + const fn settled_condition(self) -> (&'static str, &'static str) { + match self { + Self::Stop => ("Stopped", "Sandbox compute is stopped"), + Self::Suspend => ( + "Suspended", + "Sandbox is suspended; its memory state is retained for resume", + ), + } + } + + fn admit(self, sandbox: &Sandbox) -> Result { + let phase = SandboxPhase::try_from(sandbox.phase()).unwrap_or(SandboxPhase::Unknown); + match self { + Self::Stop => { + if matches!(phase, SandboxPhase::Stopped | SandboxPhase::Completed) + || is_failed_main_process_result(sandbox) + { + return Ok(QuiesceAdmission::Settled); + } + // Timeout cleanup owns reclamation while the record remains + // Error. Its later start may recreate missing compute; an + // ordinary stop must not replace that recovery state with + // Stopping or Stopped. + if phase == SandboxPhase::Error && provisioning_deadline::timed_out(sandbox) { + return Err(Status::failed_precondition( + "sandbox provisioning timed out; retry start after timeout cleanup completes", + )); + } + // Error does not prove compute has stopped. Use the normal + // driver stop and session cleanup before a subsequent start + // renews authentication and repeats configuration admission + // for the retained sandbox. Stopping a suspended sandbox + // discards its retained state; an unresolved suspend may be + // abandoned the same way. + if !matches!( + phase, + SandboxPhase::Ready + | SandboxPhase::Stopping + | SandboxPhase::Error + | SandboxPhase::Suspending + | SandboxPhase::Suspended + ) && !is_automatic_restart_transition(sandbox) + { + return Err(Status::failed_precondition(format!( + "sandbox must be Ready, Suspended, Error, or in an automatic restart to stop (current phase: {phase:?})" + ))); + } + Ok(if phase == SandboxPhase::Stopping { + QuiesceAdmission::Retry + } else { + QuiesceAdmission::Begin + }) + } + Self::Suspend => match phase { + SandboxPhase::Suspended => Ok(QuiesceAdmission::Settled), + SandboxPhase::Suspending => Ok(QuiesceAdmission::Retry), + SandboxPhase::Ready => Ok(QuiesceAdmission::Begin), + _ => Err(Status::failed_precondition(format!( + "sandbox must be Ready to suspend (current phase: {phase:?})" + ))), + }, + } + } +} + #[derive(Debug, Clone)] #[allow(clippy::struct_excessive_bools)] pub struct ComputeDriverInfoSnapshot { @@ -699,6 +826,15 @@ impl ComputeDriver for RemoteComputeDriver { client.start_sandbox(request).await } + async fn suspend_sandbox( + &self, + request: Request, + ) -> Result, Status> + { + let mut client = self.client(); + client.suspend_sandbox(request).await + } + async fn delete_sandbox( &self, request: Request, @@ -1068,6 +1204,9 @@ impl ComputeRuntime { if self.isolation_backend.is_some() { self.validate_launch_signer_configured(!launch_authentication.is_empty())?; } + // Every start path derives resume from the durable transition, so a + // retried or recovered start repeats the request that was committed. + let resume = in_flight_resume_intent(sandbox); Ok(StartSandboxRequest { sandbox_id: sandbox.object_id().to_string(), name: sandbox.object_name().to_string(), @@ -1077,6 +1216,8 @@ impl ComputeRuntime { launch_authentication, expected_runtime_identity, isolation_backend: self.isolation_backend.clone(), + resume: resume.is_some(), + restart_if_restore_fails: resume.unwrap_or(false), }) } @@ -1809,6 +1950,44 @@ impl ComputeRuntime { workspace: &str, name: &str, ) -> Result { + self.quiesce_sandbox(QuiesceOperation::Stop, workspace, name) + .await + } + + /// Whether the configured compute driver retains sandbox memory state + /// across `SuspendSandbox` and a resuming `StartSandbox`. + #[must_use] + pub fn supports_suspend_resume(&self) -> bool { + supports_suspend_resume(&self.driver_info.negotiated_extension.supported_capabilities) + } + + fn require_suspend_resume(&self) -> Result<(), Status> { + if self.supports_suspend_resume() { + Ok(()) + } else { + Err(Status::failed_precondition( + "compute driver does not support sandbox suspend", + )) + } + } + + pub(crate) async fn suspend_sandbox( + &self, + workspace: &str, + name: &str, + ) -> Result { + self.require_suspend_resume()?; + self.quiesce_sandbox(QuiesceOperation::Suspend, workspace, name) + .await + } + + async fn quiesce_sandbox( + &self, + operation: QuiesceOperation, + workspace: &str, + name: &str, + ) -> Result { + let verb = operation.verb(); let candidate = self .store .get_message_by_name::(workspace, name) @@ -1826,64 +2005,37 @@ impl ComputeRuntime { .map_err(|e| Status::internal(format!("fetch sandbox failed: {e}")))? .ok_or_else(|| Status::not_found("sandbox not found"))?; if current.object_name() != sandbox_name { - return Err(Status::aborted( - "sandbox name changed while the stop request was waiting; retry explicitly", - )); + return Err(Status::aborted(format!( + "sandbox name changed while the {verb} request was waiting; retry explicitly" + ))); } let mut attempt = 1; - let (previous, stopping) = loop { + let (previous, transition) = loop { provisioning_operation::ensure_operation_settled(¤t)?; - let phase = SandboxPhase::try_from(current.phase()).unwrap_or(SandboxPhase::Unknown); - if matches!(phase, SandboxPhase::Stopped | SandboxPhase::Completed) - || is_failed_main_process_result(¤t) - { - self.cleanup_stopped_sandbox_sessions(¤t) - .await - .map_err(Status::internal)?; - return Ok(current); - } - let automatic_restart = is_automatic_restart_transition(¤t); - // Timeout cleanup owns reclamation while the record remains Error. - // Its later start may recreate missing compute; an ordinary stop must - // not replace that recovery state with Stopping or Stopped. - if phase == SandboxPhase::Error && provisioning_deadline::timed_out(¤t) { - return Err(Status::failed_precondition( - "sandbox provisioning timed out; retry start after timeout cleanup completes", - )); - } - // Error does not prove compute has stopped. Use the normal driver stop - // and session cleanup before a subsequent start renews authentication - // and repeats configuration admission for the retained sandbox. - if !matches!( - phase, - SandboxPhase::Ready | SandboxPhase::Stopping | SandboxPhase::Error - ) && !automatic_restart - { - return Err(Status::failed_precondition(format!( - "sandbox must be Ready, Error, or in an automatic restart to stop (current phase: {phase:?})" - ))); - } - - if phase == SandboxPhase::Stopping { - // Acquiring the lifecycle gate proves that no local worker still - // owns this transition. Retry the idempotent driver operation. - break (current.clone(), current); + match operation.admit(¤t)? { + QuiesceAdmission::Settled => { + self.cleanup_stopped_sandbox_sessions(¤t) + .await + .map_err(Status::internal)?; + return Ok(current); + } + // Acquiring the lifecycle gate proves that no local worker + // still owns this transition. Retry the idempotent driver + // operation. + QuiesceAdmission::Retry => break (current.clone(), current), + QuiesceAdmission::Begin => {} } + let (reason, message) = operation.requested_condition(); match self - .write_lifecycle_phase( - ¤t, - SandboxPhase::Stopping, - "Stopping", - "Sandbox stop requested", - ) + .write_lifecycle_phase(¤t, operation.in_flight_phase(), reason, message) .await { - Ok(stopping) => { - self.sandbox_index.update_from_sandbox(&stopping); + Ok(transition) => { + self.sandbox_index.update_from_sandbox(&transition); self.sandbox_watch_bus.notify(&sandbox_id); - break (current, stopping); + break (current, transition); } Err(crate::persistence::PersistenceError::Conflict { .. }) if attempt < STOP_PHASE_CAS_RETRY_LIMIT => @@ -1894,13 +2046,15 @@ impl ComputeRuntime { .get_message::(&sandbox_id) .await .map_err(|error| { - Status::internal(format!("fetch sandbox after stop conflict: {error}")) + Status::internal(format!( + "fetch sandbox after {verb} conflict: {error}" + )) })? .ok_or_else(|| Status::not_found("sandbox not found"))?; if current.object_name() != sandbox_name { - return Err(Status::aborted( - "sandbox name changed during stop; retry explicitly", - )); + return Err(Status::aborted(format!( + "sandbox name changed during {verb}; retry explicitly" + ))); } } Err(error) => { @@ -1914,18 +2068,19 @@ impl ComputeRuntime { drop(sandbox_guard); // Once the durable transition is committed, request cancellation must - // not cancel the driver operation and strand the sandbox in - // `Stopping`. Keep the lifecycle gate in an owned worker, matching - // the delete path's cancellation semantics. + // not cancel the driver operation and strand the sandbox in its + // in-flight phase. Keep the lifecycle gate in an owned worker, + // matching the delete path's cancellation semantics. let runtime = self.clone(); let request_span = tracing::Span::current(); tokio::spawn( async move { - Box::pin(runtime.complete_sandbox_stop( + Box::pin(runtime.complete_sandbox_quiesce( + operation, sandbox_id, sandbox_name, previous, - stopping, + transition, lifecycle_guard, )) .await @@ -1935,61 +2090,90 @@ impl ComputeRuntime { .await .map_err(|err| { Status::internal(format!( - "sandbox stop worker terminated unexpectedly: {err}" + "sandbox {verb} worker terminated unexpectedly: {err}" )) })? } - async fn complete_sandbox_stop( + async fn complete_sandbox_quiesce( &self, + operation: QuiesceOperation, sandbox_id: String, sandbox_name: String, previous: Sandbox, - stopping: Sandbox, + transition: Sandbox, lifecycle_guard: SandboxLifecycleGuard, ) -> Result { - let result = self - .driver - .call( - openshell_otel::rpc::STOP_SANDBOX, - Some(&sandbox_id), - |driver| { - let sandbox_id = sandbox_id.clone(); - let sandbox_name = sandbox_name.clone(); - async move { - driver - .stop_sandbox(Request::new(StopSandboxRequest { - sandbox_id, - name: sandbox_name, - })) - .await - } - }, - ) - .await; - - match result { - Ok(_) => { + match self + .call_quiesce_driver(operation, &sandbox_id, &sandbox_name) + .await + { + Ok(()) => { let _sandbox_guard = self.lock_sandbox_for_lifecycle(&lifecycle_guard).await; - let stopped = self.commit_sandbox_stopped(&sandbox_id).await?; - self.cleanup_stopped_sandbox_sessions(&stopped) + let settled = self.commit_sandbox_quiesced(operation, &sandbox_id).await?; + self.cleanup_stopped_sandbox_sessions(&settled) .await .map_err(Status::internal)?; - self.sandbox_index.update_from_sandbox(&stopped); + self.sandbox_index.update_from_sandbox(&settled); self.sandbox_watch_bus.notify(&sandbox_id); - Ok(stopped) + Ok(settled) } Err(err) => { - self.recover_failed_lifecycle(&lifecycle_guard, &stopping, &previous, true) + self.recover_failed_lifecycle(&lifecycle_guard, &transition, &previous, true) .await; Err(Status::new( err.code(), - format!("stop sandbox failed: {}", err.message()), + format!("{} sandbox failed: {}", operation.verb(), err.message()), )) } } } + /// Issue the idempotent driver operation that settles a quiesce + /// transition. + async fn call_quiesce_driver( + &self, + operation: QuiesceOperation, + sandbox_id: &str, + sandbox_name: &str, + ) -> Result<(), Status> { + let request_id = sandbox_id.to_string(); + let name = sandbox_name.to_string(); + match operation { + QuiesceOperation::Stop => self + .driver + .call( + openshell_otel::rpc::STOP_SANDBOX, + Some(sandbox_id), + move |driver| async move { + driver + .stop_sandbox(Request::new(StopSandboxRequest { + sandbox_id: request_id, + name, + })) + .await + }, + ) + .await + .map(drop), + QuiesceOperation::Suspend => self + .driver + .call( + openshell_otel::rpc::SUSPEND_SANDBOX, + Some(sandbox_id), + move |driver| async move { + driver + .suspend_sandbox(Request::new(SuspendSandboxRequest { + sandbox: request_id, + })) + .await + }, + ) + .await + .map(drop), + } + } + #[cfg(test)] pub(crate) async fn start_sandbox( &self, @@ -2006,6 +2190,54 @@ impl ComputeRuntime { name: &str, authority: Option<&crate::auth::sandbox_jwt::SandboxSessionJwtAuthority>, ) -> Result { + self.start_sandbox_with_intent(workspace, name, authority, StartIntent::Start) + .await + } + + #[cfg(test)] + pub(crate) async fn resume_sandbox( + &self, + workspace: &str, + name: &str, + restart_if_restore_fails: bool, + ) -> Result { + self.resume_sandbox_authenticated(workspace, name, restart_if_restore_fails, None) + .await + } + + /// Restore a suspended sandbox in a new runtime generation. + pub(crate) async fn resume_sandbox_authenticated( + &self, + workspace: &str, + name: &str, + restart_if_restore_fails: bool, + authority: Option<&crate::auth::sandbox_jwt::SandboxSessionJwtAuthority>, + ) -> Result { + self.require_suspend_resume().map_err(|_| { + Status::failed_precondition("compute driver does not support sandbox resume") + })?; + self.start_sandbox_with_intent( + workspace, + name, + authority, + StartIntent::Resume { + restart_if_restore_fails, + }, + ) + .await + } + + async fn start_sandbox_with_intent( + &self, + workspace: &str, + name: &str, + authority: Option<&crate::auth::sandbox_jwt::SandboxSessionJwtAuthority>, + intent: StartIntent, + ) -> Result { + let verb = match intent { + StartIntent::Start => "start", + StartIntent::Resume { .. } => "resume", + }; let candidate = self .store .get_message_by_name::(workspace, name) @@ -2039,9 +2271,9 @@ impl ComputeRuntime { .map_err(|e| Status::internal(format!("fetch sandbox failed: {e}")))? .ok_or_else(|| Status::not_found("sandbox not found"))?; if current.object_name() != sandbox_name { - return Err(Status::aborted( - "sandbox name changed while the start request was waiting; retry explicitly", - )); + return Err(Status::aborted(format!( + "sandbox name changed while the {verb} request was waiting; retry explicitly" + ))); } self.validate_caller_driver_config( @@ -2055,6 +2287,17 @@ impl ComputeRuntime { let (previous, starting, launch_authentication) = loop { provisioning_operation::ensure_operation_settled(¤t)?; let phase = SandboxPhase::try_from(current.phase()).unwrap_or(SandboxPhase::Unknown); + if let StartIntent::Resume { .. } = intent { + // Resume restores only retained state. A Starting record may + // be retried only when it is the same in-flight resume. + let resuming = + phase == SandboxPhase::Starting && in_flight_resume_intent(¤t).is_some(); + if phase != SandboxPhase::Suspended && !resuming { + return Err(Status::failed_precondition(format!( + "sandbox must be Suspended to resume (current phase: {phase:?})" + ))); + } + } if phase == SandboxPhase::Ready { return Ok(current); } @@ -2071,9 +2314,14 @@ impl ComputeRuntime { "provisioning timeout cleanup is still pending; retry start after compute is reclaimed", )); } + // Starting a suspended sandbox discards its retained state: the + // driver receives `resume=false` and boots the workload fresh. if !matches!( phase, - SandboxPhase::Stopped | SandboxPhase::Completed | SandboxPhase::Starting + SandboxPhase::Stopped + | SandboxPhase::Completed + | SandboxPhase::Starting + | SandboxPhase::Suspended ) && !is_failed_main_process_result(¤t) && !provisioning_timeout { @@ -2083,7 +2331,7 @@ impl ComputeRuntime { "" }; return Err(Status::failed_precondition(format!( - "sandbox must be Stopped, Completed, or a failed main-process Error to start (current phase: {phase:?}){recovery_hint}" + "sandbox must be Stopped, Suspended, Completed, or a failed main-process Error to start (current phase: {phase:?}){recovery_hint}" ))); } if phase == SandboxPhase::Completed || is_failed_main_process_result(¤t) { @@ -2095,7 +2343,8 @@ impl ComputeRuntime { if phase == SandboxPhase::Starting { // Acquiring the lifecycle gate proves that no local worker still // owns this transition. Retry the idempotent driver operation - // with the identity committed by the original transition. + // with the identity and resume intent committed by the original + // transition. let authentication = self .encode_persisted_launch_authentication(authority, ¤t) .await?; @@ -2127,16 +2376,25 @@ impl ComputeRuntime { &sandbox_id, expected_resource_version, move |sandbox| { - if let Some(metadata) = sandbox.metadata.as_mut() { - next_identity_for_update.write(&mut metadata.annotations); - } + let (reason, message) = match intent { + StartIntent::Start => ("Starting", "Sandbox start requested"), + StartIntent::Resume { .. } => ("Resuming", "Sandbox resume requested"), + }; apply_lifecycle_phase( sandbox, SandboxPhase::Starting, - "Starting", - "Sandbox start requested", + reason, + message, self.image_preparation_timeout_seconds, ); + if let Some(metadata) = sandbox.metadata.as_mut() { + next_identity_for_update.write(&mut metadata.annotations); + write_start_intent( + &mut metadata.annotations, + next_identity_for_update.runtime_generation.as_str(), + intent, + ); + } }, ) .await @@ -2155,13 +2413,15 @@ impl ComputeRuntime { .get_message::(&sandbox_id) .await .map_err(|error| { - Status::internal(format!("fetch sandbox after start conflict: {error}")) + Status::internal(format!( + "fetch sandbox after {verb} conflict: {error}" + )) })? .ok_or_else(|| Status::not_found("sandbox not found"))?; if current.object_name() != sandbox_name { - return Err(Status::aborted( - "sandbox name changed during start; retry explicitly", - )); + return Err(Status::aborted(format!( + "sandbox name changed during {verb}; retry explicitly" + ))); } } Err(error) => { @@ -2194,7 +2454,7 @@ impl ComputeRuntime { .await .map_err(|err| { Status::internal(format!( - "sandbox start worker terminated unexpectedly: {err}" + "sandbox {verb} worker terminated unexpectedly: {err}" )) })? } @@ -2317,6 +2577,7 @@ impl ComputeRuntime { provisioning_operation::ensure_current_result(&latest, &starting)?; latest }; + let latest = self.clear_resume_intent(latest).await; self.sandbox_index.update_from_sandbox(&latest); self.sandbox_watch_bus.notify(&sandbox_id); Ok(latest) @@ -2414,6 +2675,39 @@ impl ComputeRuntime { unreachable!("runtime identity persistence retry loop always returns") } + /// Clear a resume intent once the driver accepted the resume. + /// + /// The driver consumed the retained state, so a later idempotent start of + /// the same generation must not ask it to restore that state again. + async fn clear_resume_intent(&self, sandbox: Sandbox) -> Sandbox { + let Some(intent) = sandbox + .metadata + .as_ref() + .and_then(|metadata| metadata.annotations.get(RESUME_INTENT_ANNOTATION)) + .cloned() + else { + return sandbox; + }; + let sandbox_id = sandbox.object_id().to_string(); + match self + .store + .update_message_cas::(&sandbox_id, 0, |current| { + if let Some(metadata) = current.metadata.as_mut() + && metadata.annotations.get(RESUME_INTENT_ANNOTATION) == Some(&intent) + { + metadata.annotations.remove(RESUME_INTENT_ANNOTATION); + } + }) + .await + { + Ok(updated) => updated, + Err(error) => { + warn!(sandbox_id, %error, "Failed to clear completed sandbox resume intent"); + sandbox + } + } + } + async fn compensate_successful_start( &self, lifecycle_guard: &SandboxLifecycleGuard, @@ -2421,6 +2715,47 @@ impl ComputeRuntime { previous: &Sandbox, original: Status, ) -> Status { + // A supervisor can reach Ready before the driver returns. The intent + // still identifies a successful resume until its binding is committed. + let resuming = persisted_resume_intent(starting).is_some_and(|intent| { + sandbox_runtime_generation(starting) + .is_ok_and(|generation| intent.generation == generation.as_str()) + }); + // Once restoration succeeded, a subsequent STOP may consume the only + // remaining state even if its response is lost. Persist that the + // reference was consumed before attempting cleanup, so recovery never + // retries restoration or rolls back to Suspended after an ambiguous STOP. + let starting = if resuming { + let consumed = match self + .store + .update_message_cas::( + starting.object_id(), + sandbox_resource_version(starting), + |current| { + if let Some(metadata) = current.metadata.as_mut() { + metadata.annotations.remove(RESUME_INTENT_ANNOTATION); + } + }, + ) + .await + { + Ok(consumed) => consumed, + Err(error) => { + return Status::new( + original.code(), + format!( + "{}; could not record successful resume; cleanup deferred: {error}", + original.message() + ), + ); + } + }; + self.sandbox_index.update_from_sandbox(&consumed); + self.sandbox_watch_bus.notify(consumed.object_id()); + consumed + } else { + starting.clone() + }; let sandbox_id = starting.object_id().to_string(); let sandbox_name = starting.object_name().to_string(); let request_id = sandbox_id.clone(); @@ -2428,7 +2763,7 @@ impl ComputeRuntime { // A newer operation or timeout must reject it without touching compute. let stop_result = self .await_provisioning_operation( - starting, + &starting, self.driver.call_owned( openshell_otel::rpc::STOP_SANDBOX, Some(&sandbox_id), @@ -2465,7 +2800,25 @@ impl ComputeRuntime { }; let _sandbox_guard = self.lock_sandbox_for_lifecycle(lifecycle_guard).await; - if self.restore_lifecycle_snapshot(&settled, previous).await { + // A successful resume consumed the retained state. STOP discards + // the restored workload, so rolling back to Suspended would advertise + // a snapshot that no longer exists. Keep this attempt's generation + // and credentials and record the confirmed stopped runtime instead. + let mut rollback = previous.clone(); + if resuming { + rollback = (*settled).clone(); + apply_lifecycle_phase( + &mut rollback, + SandboxPhase::Stopped, + "ResumeRolledBack", + "Resumed workload stopped after its runtime binding could not be committed", + self.image_preparation_timeout_seconds, + ); + } + if self.restore_lifecycle_snapshot(&settled, &rollback).await { + if resuming && let Err(error) = self.cleanup_stopped_sandbox_sessions(&rollback).await { + warn!(sandbox_id, %error, "Failed to clean up stopped sandbox after start compensation"); + } original } else { Status::new( @@ -2511,7 +2864,30 @@ impl ComputeRuntime { expected_stopped && driver_snapshot_confirms_stopping(&snapshot); let runtime_restart_during_stop = expected_stopped && driver_snapshot_reports_runtime_restart(&snapshot); - if suspension_progressing || runtime_restart_during_stop { + // A suspended runtime looks exited or failed to the driver. + // Only a confirmed stopped runtime permits retrying retained + // state. An unknown or still-starting runtime remains ambiguous. + let resume_not_running = !expected_stopped + && in_flight_resume_intent(transition).is_some() + && backend_phase != SandboxPhase::Ready; + if resume_not_running { + if observed_stopped { + // Recovery and explicit retries may have Starting as + // their previous snapshot. Keep the current generation + // and credentials, but restore the retained-state phase. + let mut suspended = transition.clone(); + apply_lifecycle_phase( + &mut suspended, + SandboxPhase::Suspended, + "Suspended", + "Sandbox remains suspended after failed resume", + self.image_preparation_timeout_seconds, + ); + let _ = self + .restore_lifecycle_snapshot(transition, &suspended) + .await; + } + } else if suspension_progressing || runtime_restart_during_stop { // The backend has accepted the stop but has not finished // terminating the sandbox. A runtime restart can likewise // be the expected exit from an in-flight stop. Preserve the @@ -2620,12 +2996,17 @@ impl ComputeRuntime { .await } - /// Commit `Stopped` after the driver confirmed the stop. + /// Commit the settled phase after the driver confirmed a stop or + /// suspend. /// - /// Other replicas apply watch events for the terminating runtime without + /// Other replicas apply watch events for the quiescing runtime without /// this replica's lifecycle gate, so the CAS can lose to an unrelated - /// status write. Re-read and retry while the record is still `Stopping`. - async fn commit_sandbox_stopped(&self, sandbox_id: &str) -> Result { + /// status write. Re-read and retry while the record is still in flight. + async fn commit_sandbox_quiesced( + &self, + operation: QuiesceOperation, + sandbox_id: &str, + ) -> Result { let mut attempt = 1; loop { let latest = self @@ -2634,25 +3015,22 @@ impl ComputeRuntime { .await .map_err(|e| Status::internal(format!("fetch sandbox failed: {e}")))? .ok_or_else(|| Status::not_found("sandbox not found"))?; - match SandboxPhase::try_from(latest.phase()).unwrap_or(SandboxPhase::Unknown) { - SandboxPhase::Stopped => return Ok(latest), - SandboxPhase::Stopping => {} - _ => { - return Err(Status::aborted( - "sandbox lifecycle changed while stop completed", - )); - } + let phase = SandboxPhase::try_from(latest.phase()).unwrap_or(SandboxPhase::Unknown); + if phase == operation.settled_phase() { + return Ok(latest); + } + if phase != operation.in_flight_phase() { + return Err(Status::aborted(format!( + "sandbox lifecycle changed while {} completed", + operation.verb() + ))); } + let (reason, message) = operation.settled_condition(); match self - .write_lifecycle_phase( - &latest, - SandboxPhase::Stopped, - "Stopped", - "Sandbox compute is stopped", - ) + .write_lifecycle_phase(&latest, operation.settled_phase(), reason, message) .await { - Ok(stopped) => return Ok(stopped), + Ok(settled) => return Ok(settled), Err(crate::persistence::PersistenceError::Conflict { current_resource_version, }) if attempt < STOP_PHASE_CAS_RETRY_LIMIT => { @@ -2660,7 +3038,8 @@ impl ComputeRuntime { sandbox_id, attempt, current_resource_version, - "Retrying sandbox stop completion after a concurrent sandbox update" + operation = operation.verb(), + "Retrying sandbox lifecycle completion after a concurrent sandbox update" ); attempt += 1; } @@ -3560,7 +3939,12 @@ impl ComputeRuntime { let phase = SandboxPhase::try_from(sandbox.phase()).unwrap_or(SandboxPhase::Unknown); - if !sandbox_phase_should_be_running(phase) { + // A driver stop discards retained suspend state. An unresolved + // resume still needs that state when startup recovery repeats + // it, and an idempotent restart reconciles any runtime it left. + if !sandbox_phase_should_be_running(phase) + || in_flight_resume_intent(&sandbox).is_some() + { return (0, 0); } let sandbox_name = sandbox.object_name().to_string(); @@ -3698,7 +4082,9 @@ impl ComputeRuntime { } }; - if provisioning_deadline::driver_operation_pending(&sandbox) { + if provisioning_deadline::driver_operation_pending(&sandbox) + || in_flight_resume_intent(&sandbox).is_some() + { warn!( sandbox_id, "Retaining pending driver operation during gateway recovery" @@ -3831,6 +4217,8 @@ impl ComputeRuntime { } } } + *recovered_sandbox = + self.clear_resume_intent((*recovered_sandbox).clone()).await; if let Err(err) = authentication_committed(sandbox.object_id()).await { warn!( sandbox_id = %sandbox.object_id(), @@ -3933,7 +4321,7 @@ impl ComputeRuntime { .list_persisted_sandbox_ids("lifecycle recovery") .await?; for sandbox_id in sandbox_ids { - let _lifecycle_guard = self.lifecycle_gates.lock_for(&sandbox_id).await; + let lifecycle_guard = self.lifecycle_gates.lock_for(&sandbox_id).await; let sandbox = match self.store.get_message::(&sandbox_id).await { Ok(Some(sandbox)) => sandbox, Ok(None) => continue, @@ -3955,7 +4343,7 @@ impl ComputeRuntime { } let phase = SandboxPhase::try_from(sandbox.phase()).unwrap_or(SandboxPhase::Unknown); match phase { - SandboxPhase::Stopped | SandboxPhase::Completed => { + SandboxPhase::Stopped | SandboxPhase::Suspended | SandboxPhase::Completed => { if let Err(err) = self.cleanup_stopped_sandbox_sessions(&sandbox).await { warn!(sandbox_id = %sandbox.object_id(), error = %err, "Failed to complete recovered sandbox session cleanup"); } @@ -3966,43 +4354,12 @@ impl ComputeRuntime { } } SandboxPhase::Stopping => { - let sandbox_id = sandbox.object_id().to_string(); - let sandbox_name = sandbox.object_name().to_string(); - let driver_sandbox_id = sandbox_id.clone(); - match self - .driver - .call( - openshell_otel::rpc::STOP_SANDBOX, - Some(&sandbox_id), - |driver| async move { - driver - .stop_sandbox(Request::new(StopSandboxRequest { - sandbox_id: driver_sandbox_id, - name: sandbox_name, - })) - .await - }, - ) - .await - { - Ok(_) => match self.commit_sandbox_stopped(&sandbox_id).await { - Ok(updated) => { - self.sandbox_index.update_from_sandbox(&updated); - self.sandbox_watch_bus.notify(updated.object_id()); - if let Err(err) = - self.cleanup_stopped_sandbox_sessions(&updated).await - { - warn!(sandbox_id = %updated.object_id(), error = %err, "Failed to complete recovered sandbox session cleanup"); - } - } - Err(err) => { - warn!(sandbox_id = %sandbox.object_id(), error = %err, "Failed to persist recovered stop"); - } - }, - Err(err) => { - warn!(sandbox_id = %sandbox.object_id(), error = %err, "Failed to recover sandbox stop"); - } - } + self.recover_quiesce_transition(QuiesceOperation::Stop, &sandbox) + .await; + } + SandboxPhase::Suspending => { + self.recover_quiesce_transition(QuiesceOperation::Suspend, &sandbox) + .await; } SandboxPhase::Starting => { if let Err(error) = self.validate_isolation_backend_binding(&sandbox) { @@ -4054,7 +4411,7 @@ impl ComputeRuntime { // Recovery retains the original attempt and deadline. A // stalled driver must release this lifecycle gate after // expiry so the deadline worker can reclaim its compute. - if let Err(err) = self + match self .await_provisioning_operation( &sandbox, self.driver.call_owned( @@ -4067,7 +4424,24 @@ impl ComputeRuntime { ) .await { - warn!(sandbox_id = %sandbox.object_id(), error = %err, "Failed to recover sandbox start"); + Ok((_, settled)) => { + let updated = self.clear_resume_intent(*settled).await; + self.sandbox_index.update_from_sandbox(&updated); + } + Err(err) => { + warn!(sandbox_id = %sandbox.object_id(), error = %err, "Failed to recover sandbox start"); + if let ProvisioningOperationError::Driver { settled, .. } = err + && in_flight_resume_intent(&settled).is_some() + { + Box::pin(self.recover_failed_lifecycle( + &lifecycle_guard, + &settled, + &sandbox, + false, + )) + .await; + } + } } } _ => {} @@ -4076,6 +4450,31 @@ impl ComputeRuntime { Ok(()) } + /// Re-issue the idempotent driver call of a stop or suspend interrupted + /// by a gateway restart, then commit its settled phase. + async fn recover_quiesce_transition(&self, operation: QuiesceOperation, sandbox: &Sandbox) { + let sandbox_id = sandbox.object_id(); + if let Err(err) = self + .call_quiesce_driver(operation, sandbox_id, sandbox.object_name()) + .await + { + warn!(sandbox_id, operation = operation.verb(), error = %err, "Failed to recover sandbox lifecycle transition"); + return; + } + match self.commit_sandbox_quiesced(operation, sandbox_id).await { + Ok(updated) => { + self.sandbox_index.update_from_sandbox(&updated); + self.sandbox_watch_bus.notify(updated.object_id()); + if let Err(err) = self.cleanup_stopped_sandbox_sessions(&updated).await { + warn!(sandbox_id, error = %err, "Failed to complete recovered sandbox session cleanup"); + } + } + Err(err) => { + warn!(sandbox_id, operation = operation.verb(), error = %err, "Failed to persist recovered sandbox lifecycle transition"); + } + } + } + async fn list_persisted_sandbox_ids(&self, operation: &str) -> Result, String> { self.store .collect_records(Sandbox::object_type(), ObjectListQuery::AllWorkspaces) @@ -5278,7 +5677,11 @@ impl ComputeRuntime { && (provisioning_deadline::timed_out(¤t) || matches!( current_phase, - SandboxPhase::Deleting | SandboxPhase::Stopping | SandboxPhase::Stopped + SandboxPhase::Deleting + | SandboxPhase::Stopping + | SandboxPhase::Stopped + | SandboxPhase::Suspending + | SandboxPhase::Suspended )) { return Err(format!( @@ -5298,6 +5701,8 @@ impl ComputeRuntime { | SandboxPhase::Error | SandboxPhase::Stopping | SandboxPhase::Stopped + | SandboxPhase::Suspending + | SandboxPhase::Suspended | SandboxPhase::Completed ) { return Ok(()); @@ -5435,7 +5840,10 @@ impl ComputeRuntime { let phase = SandboxPhase::try_from(existing.phase()).unwrap_or(SandboxPhase::Unknown); if matches!( phase, - SandboxPhase::Deleting | SandboxPhase::Stopping | SandboxPhase::Stopped + SandboxPhase::Deleting + | SandboxPhase::Stopping + | SandboxPhase::Stopped + | SandboxPhase::Suspended ) { return Ok(()); } @@ -5526,7 +5934,10 @@ impl ComputeRuntime { let phase = SandboxPhase::try_from(sandbox.phase()).unwrap_or(SandboxPhase::Unknown); if matches!( phase, - SandboxPhase::Deleting | SandboxPhase::Stopping | SandboxPhase::Stopped + SandboxPhase::Deleting + | SandboxPhase::Stopping + | SandboxPhase::Stopped + | SandboxPhase::Suspended ) { // Lifecycle shutdown intentionally discards the canonical process // result. Finalization must still acknowledge that discarded @@ -6054,7 +6465,11 @@ impl ComputeRuntime { } if matches!( phase, - SandboxPhase::Stopping | SandboxPhase::Stopped | SandboxPhase::Starting + SandboxPhase::Stopping + | SandboxPhase::Stopped + | SandboxPhase::Starting + | SandboxPhase::Suspending + | SandboxPhase::Suspended ) { let updated = self .store @@ -6925,8 +7340,19 @@ fn apply_driver_snapshot( // sticky until an explicit lifecycle operation changes desired state. A // late signal-exit snapshot must also not overwrite the terminal reason // recorded by a completed explicit stop. - if matches!(old_phase, SandboxPhase::Error | SandboxPhase::Completed) - || (old_phase == SandboxPhase::Stopped && driver_snapshot_reports_runtime_restart(incoming)) + // Suspension is gateway-owned like an explicit stop, but a suspended + // runtime has no driver state that can describe it: the frozen workload + // looks exited, stopped, or even still running while the driver captures + // it. Only the explicit suspend result and later lifecycle requests may + // move these phases. + if matches!( + old_phase, + SandboxPhase::Error + | SandboxPhase::Completed + | SandboxPhase::Suspending + | SandboxPhase::Suspended + ) || (old_phase == SandboxPhase::Stopped + && driver_snapshot_reports_runtime_restart(incoming)) { if let Some(metadata) = sandbox.metadata.as_mut() { metadata.name.clone_from(sandbox_name); @@ -7492,7 +7918,17 @@ fn apply_lifecycle_phase( image_preparation_timeout_seconds: u32, ) { sandbox.set_phase(phase as i32); - if matches!(phase, SandboxPhase::Stopping | SandboxPhase::Starting) { + // Every explicit lifecycle write ends the previous transition's resume + // intent. A resuming start records a new one after this write. + if let Some(metadata) = sandbox.metadata.as_mut() { + metadata.annotations.remove(RESUME_INTENT_ANNOTATION); + } + // Explicit quiesce and start requests cancel any gateway-managed + // automatic restart. + if matches!( + phase, + SandboxPhase::Stopping | SandboxPhase::Starting | SandboxPhase::Suspending + ) { let status = sandbox.status.get_or_insert_with(Default::default); // Retain the previous instance id as a tombstone until the restarted // supervisor registers its new id. @@ -7526,6 +7962,70 @@ fn apply_lifecycle_phase( ); } +/// Whether a `Starting` transition boots fresh or restores retained state. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum StartIntent { + Start, + Resume { restart_if_restore_fails: bool }, +} + +#[derive(serde::Serialize, serde::Deserialize)] +struct PersistedResumeIntent { + generation: String, + restart_if_restore_fails: bool, +} + +/// Record the intent of a new `Starting` transition for `generation`. +/// +/// Plain starts remove any prior intent so the driver discards retained +/// state instead of restoring it. +fn write_start_intent( + annotations: &mut HashMap, + generation: &str, + intent: StartIntent, +) { + match intent { + StartIntent::Start => { + annotations.remove(RESUME_INTENT_ANNOTATION); + } + StartIntent::Resume { + restart_if_restore_fails, + } => { + let value = serde_json::to_string(&PersistedResumeIntent { + generation: generation.to_string(), + restart_if_restore_fails, + }) + .expect("resume intent serialization is infallible"); + annotations.insert(RESUME_INTENT_ANNOTATION.to_string(), value); + } + } +} + +/// The persisted resume intent of the sandbox's current `Starting` +/// transition, returning its cold-start fallback choice. +/// +/// Only an explicit, not yet completed transition for the current runtime +/// generation counts. Automatic restarts always boot fresh. +fn in_flight_resume_intent(sandbox: &Sandbox) -> Option { + if SandboxPhase::try_from(sandbox.phase()) != Ok(SandboxPhase::Starting) + || is_automatic_restart_transition(sandbox) + { + return None; + } + let intent = persisted_resume_intent(sandbox)?; + let generation = sandbox_runtime_generation(sandbox).ok()?; + (intent.generation == generation.as_str()).then_some(intent.restart_if_restore_fails) +} + +fn persisted_resume_intent(sandbox: &Sandbox) -> Option { + let value = sandbox + .metadata + .as_ref()? + .annotations + .get(RESUME_INTENT_ANNOTATION)?; + serde_json::from_str(value).ok() +} + fn next_runtime_identity( sandbox: &Sandbox, ) -> Result { @@ -7758,6 +8258,16 @@ impl ComputeDriver for NoopTestDriver { )) } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> + { + Err(Status::unimplemented( + "test driver does not support sandbox suspend", + )) + } + async fn delete_sandbox( &self, _request: Request, @@ -7879,6 +8389,7 @@ pub fn new_test_runtime_with_driver( #[cfg(test)] mod tests { mod error_recovery; + mod suspend_resume; use super::*; use crate::policy_store::PolicyStoreExt; @@ -7887,7 +8398,8 @@ mod tests { use openshell_core::proto::compute::v1::{ CreateSandboxResponse, DeleteSandboxResponse, GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse, StartSandboxResponse, StopSandboxRequest, StopSandboxResponse, - ValidateSandboxCreateResponse, WatchSandboxesDeletedEvent, WatchSandboxesSandboxEvent, + SuspendSandboxResponse, ValidateSandboxCreateResponse, WatchSandboxesDeletedEvent, + WatchSandboxesSandboxEvent, }; use std::collections::HashMap; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; @@ -8387,6 +8899,13 @@ mod tests { Ok(tonic::Response::new(StartSandboxResponse::default())) } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Ok(tonic::Response::new(SuspendSandboxResponse {})) + } + async fn delete_sandbox( &self, _request: Request, @@ -8491,6 +9010,12 @@ mod tests { start_generations: TestMutex>, start_expected_runtime_identities: TestMutex>, start_outcome: TestMutex, + start_resume_requests: TestMutex>, + suspend_started: Notify, + suspend_release: Semaphore, + suspend_blocked: AtomicBool, + suspend_calls: AtomicUsize, + suspend_outcome: TestMutex, runtime_identity: TestMutex, get_started: Notify, get_release: Semaphore, @@ -8536,6 +9061,12 @@ mod tests { start_generations: TestMutex::new(Vec::new()), start_expected_runtime_identities: TestMutex::new(Vec::new()), start_outcome: TestMutex::new(ControlledLifecycleOutcome::Ok), + start_resume_requests: TestMutex::new(Vec::new()), + suspend_started: Notify::new(), + suspend_release: Semaphore::new(0), + suspend_blocked: AtomicBool::new(false), + suspend_calls: AtomicUsize::new(0), + suspend_outcome: TestMutex::new(ControlledLifecycleOutcome::Ok), runtime_identity: TestMutex::new(String::new()), get_started: Notify::new(), get_release: Semaphore::new(0), @@ -8605,6 +9136,32 @@ mod tests { .expect("start outcome lock poisoned") = outcome; } + fn set_suspend_outcome(&self, outcome: ControlledLifecycleOutcome) { + *self + .suspend_outcome + .lock() + .expect("suspend outcome lock poisoned") = outcome; + } + + fn suspend_calls(&self) -> usize { + self.suspend_calls.load(Ordering::SeqCst) + } + + /// `(resume, restart_if_restore_fails)` for every start request. + fn start_resume_requests(&self) -> Vec<(bool, bool)> { + self.start_resume_requests + .lock() + .expect("start resume requests lock poisoned") + .clone() + } + + fn start_generations(&self) -> Vec { + self.start_generations + .lock() + .expect("start generations lock poisoned") + .clone() + } + fn set_runtime_identity(&self, runtime_identity: impl Into) { *self .runtime_identity @@ -8841,6 +9398,10 @@ mod tests { request: Request, ) -> Result, Status> { let request = request.into_inner(); + self.start_resume_requests + .lock() + .expect("start resume requests lock poisoned") + .push((request.resume, request.restart_if_restore_fails)); self.start_requests .lock() .expect("start requests lock poisoned") @@ -8885,6 +9446,29 @@ mod tests { } } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + self.suspend_calls.fetch_add(1, Ordering::SeqCst); + self.suspend_started.notify_one(); + if self.suspend_blocked.load(Ordering::SeqCst) { + self.suspend_release.acquire().await.unwrap().forget(); + } + let outcome = self + .suspend_outcome + .lock() + .expect("suspend outcome lock poisoned") + .clone(); + match outcome { + ControlledLifecycleOutcome::Ok => { + Ok(tonic::Response::new(SuspendSandboxResponse {})) + } + ControlledLifecycleOutcome::NotFound => Err(Status::not_found("sandbox not found")), + ControlledLifecycleOutcome::Error(message) => Err(Status::internal(message)), + } + } + async fn delete_sandbox( &self, request: Request, @@ -12003,6 +12587,13 @@ mod tests { self.0.start_sandbox(request).await } + async fn suspend_sandbox( + &self, + request: Request, + ) -> Result, Status> { + self.0.suspend_sandbox(request).await + } + async fn delete_sandbox( &self, request: Request, diff --git a/crates/openshell-server/src/compute/tests/suspend_resume.rs b/crates/openshell-server/src/compute/tests/suspend_resume.rs new file mode 100644 index 0000000000..0e59e4ec90 --- /dev/null +++ b/crates/openshell-server/src/compute/tests/suspend_resume.rs @@ -0,0 +1,726 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Suspend retains memory state behind gateway-owned phases; resume restores +//! it in a new runtime generation. + +use super::*; + +async fn stored(runtime: &ComputeRuntime, id: &str) -> Sandbox { + runtime + .store + .get_message::(id) + .await + .unwrap() + .unwrap() +} + +fn enable_suspend_resume(runtime: &mut ComputeRuntime) { + runtime + .driver_info + .negotiated_extension + .supported_capabilities + .push(openshell_core::extension_protocol::COMPUTE_SUSPEND_RESUME.to_string()); +} + +async fn suspend_capable_runtime(driver: Arc) -> ComputeRuntime { + let mut runtime = test_runtime(driver).await; + enable_suspend_resume(&mut runtime); + runtime +} + +fn has_resume_intent(sandbox: &Sandbox) -> bool { + sandbox + .metadata + .as_ref() + .is_some_and(|metadata| metadata.annotations.contains_key(RESUME_INTENT_ANNOTATION)) +} + +fn exited_driver_sandbox(sandbox: &Sandbox) -> DriverSandbox { + let mut exited = ready_driver_sandbox(sandbox.object_id(), sandbox.object_name()); + exited.status = Some(make_driver_status(make_driver_condition( + "ContainerExited", + "Container exited with status 0", + ))); + exited +} + +#[tokio::test] +async fn suspend_commits_suspended_and_revokes_sessions() { + let driver = ControlledDriver::new(); + let runtime = suspend_capable_runtime(driver.clone()).await; + let sandbox = sandbox_record("sb-suspend", "suspend", SandboxPhase::Ready); + runtime.store.put_message(&sandbox).await.unwrap(); + let session = ssh_session_record("suspend-session", sandbox.object_id()); + runtime.store.put_message(&session).await.unwrap(); + register_test_supervisor_session(&runtime, sandbox.object_id()); + + let suspended = runtime.suspend_sandbox("default", "suspend").await.unwrap(); + + assert_eq!(suspended.phase(), SandboxPhase::Suspended as i32); + assert_eq!(ready_condition(&suspended).unwrap().reason, "Suspended"); + assert_eq!(driver.suspend_calls(), 1); + assert_eq!(driver.stop_calls(), 0, "suspend never stops compute"); + assert!(!runtime.supervisor_sessions.has_session(sandbox.object_id())); + assert!( + runtime + .store + .get_message::(session.object_id()) + .await + .unwrap() + .is_none(), + "suspend revokes ephemeral SSH sessions" + ); + + let again = runtime.suspend_sandbox("default", "suspend").await.unwrap(); + assert_eq!(again.phase(), SandboxPhase::Suspended as i32); + assert_eq!(driver.suspend_calls(), 1, "stable suspend is idempotent"); +} + +#[tokio::test] +async fn suspend_requires_driver_capability() { + let driver = ControlledDriver::new(); + let runtime = test_runtime(driver.clone()).await; + let sandbox = sandbox_record("sb-unsupported", "unsupported", SandboxPhase::Ready); + runtime.store.put_message(&sandbox).await.unwrap(); + + let error = runtime + .suspend_sandbox("default", "unsupported") + .await + .unwrap_err(); + assert_eq!(error.code(), Code::FailedPrecondition); + assert!(error.message().contains("does not support sandbox suspend")); + + let suspended = sandbox_record("sb-unsupported-2", "unsupported-2", SandboxPhase::Suspended); + runtime.store.put_message(&suspended).await.unwrap(); + let error = runtime + .resume_sandbox("default", "unsupported-2", false) + .await + .unwrap_err(); + assert_eq!(error.code(), Code::FailedPrecondition); + assert!(error.message().contains("does not support sandbox resume")); + + assert_eq!(driver.suspend_calls(), 0); + assert_eq!(driver.start_calls(), 0); + assert_eq!( + stored(&runtime, sandbox.object_id()).await.phase(), + SandboxPhase::Ready as i32 + ); +} + +#[tokio::test] +async fn suspend_rejects_sandboxes_that_are_not_ready() { + let driver = ControlledDriver::new(); + let runtime = suspend_capable_runtime(driver.clone()).await; + for (id, phase) in [ + ("sb-provisioning", SandboxPhase::Provisioning), + ("sb-starting", SandboxPhase::Starting), + ("sb-stopping", SandboxPhase::Stopping), + ("sb-stopped", SandboxPhase::Stopped), + ("sb-error", SandboxPhase::Error), + ("sb-completed", SandboxPhase::Completed), + ] { + runtime + .store + .put_message(&sandbox_record(id, id, phase)) + .await + .unwrap(); + let error = runtime.suspend_sandbox("default", id).await.unwrap_err(); + assert_eq!(error.code(), Code::FailedPrecondition, "{phase:?}"); + assert!( + error.message().contains("must be Ready to suspend"), + "{phase:?}" + ); + assert_eq!(stored(&runtime, id).await.phase(), phase as i32); + } + assert_eq!(driver.suspend_calls(), 0); +} + +#[tokio::test] +async fn suspend_retries_an_unresolved_suspending_transition() { + let driver = ControlledDriver::new(); + let runtime = suspend_capable_runtime(driver.clone()).await; + let sandbox = sandbox_record("sb-suspending", "suspending", SandboxPhase::Suspending); + runtime.store.put_message(&sandbox).await.unwrap(); + + let suspended = runtime + .suspend_sandbox("default", "suspending") + .await + .unwrap(); + + assert_eq!(suspended.phase(), SandboxPhase::Suspended as i32); + assert_eq!(driver.suspend_calls(), 1); +} + +#[tokio::test] +async fn failed_suspend_restores_a_still_running_sandbox() { + let driver = ControlledDriver::new(); + driver.set_suspend_outcome(ControlledLifecycleOutcome::Error("boundary busy")); + let runtime = suspend_capable_runtime(driver.clone()).await; + let sandbox = sandbox_record("sb-suspend-fail", "suspend-fail", SandboxPhase::Ready); + runtime.store.put_message(&sandbox).await.unwrap(); + driver.set_get_outcome(ControlledGetOutcome::Sandbox(Box::new( + ready_driver_sandbox(sandbox.object_id(), sandbox.object_name()), + ))); + + let error = runtime + .suspend_sandbox("default", "suspend-fail") + .await + .unwrap_err(); + + assert!(error.message().starts_with("suspend sandbox failed")); + assert_eq!( + stored(&runtime, sandbox.object_id()).await.phase(), + SandboxPhase::Ready as i32 + ); +} + +#[tokio::test] +async fn resume_starts_a_new_generation_that_restores_retained_state() { + let driver = ControlledDriver::new(); + let runtime = suspend_capable_runtime(driver.clone()).await; + let sandbox = sandbox_record("sb-resume", "resume", SandboxPhase::Suspended); + let suspended_generation = sandbox_runtime_generation(&sandbox).unwrap(); + runtime.store.put_message(&sandbox).await.unwrap(); + + let resumed = runtime + .resume_sandbox("default", "resume", true) + .await + .unwrap(); + + assert_eq!(resumed.phase(), SandboxPhase::Starting as i32); + assert_eq!(ready_condition(&resumed).unwrap().reason, "Resuming"); + assert_eq!(driver.start_resume_requests(), vec![(true, true)]); + let generation = sandbox_runtime_generation(&resumed).unwrap(); + assert_ne!(generation, suspended_generation); + assert_eq!(driver.start_generations(), vec![generation.into_string()]); + assert!( + !has_resume_intent(&resumed), + "an accepted resume consumes the retained state" + ); + + // An explicit retry of the accepted start must not restore again. + runtime.start_sandbox("default", "resume").await.unwrap(); + assert_eq!( + driver.start_resume_requests(), + vec![(true, true), (false, false)] + ); + let error = runtime + .resume_sandbox("default", "resume", true) + .await + .unwrap_err(); + assert_eq!(error.code(), Code::FailedPrecondition); + assert!(error.message().contains("must be Suspended to resume")); +} + +#[tokio::test] +async fn unresolved_resume_retries_with_the_same_request() { + let driver = ControlledDriver::new(); + driver.set_start_outcome(ControlledLifecycleOutcome::Error("transport reset")); + driver.set_get_outcome(ControlledGetOutcome::Error("driver unavailable")); + let runtime = suspend_capable_runtime(driver.clone()).await; + let sandbox = sandbox_record("sb-resume-retry", "resume-retry", SandboxPhase::Suspended); + runtime.store.put_message(&sandbox).await.unwrap(); + + runtime + .resume_sandbox("default", "resume-retry", false) + .await + .unwrap_err(); + let pending = stored(&runtime, sandbox.object_id()).await; + assert_eq!(pending.phase(), SandboxPhase::Starting as i32); + assert!(has_resume_intent(&pending)); + + driver.set_start_outcome(ControlledLifecycleOutcome::Ok); + // Both an explicit resume and a plain start retry the committed resume. + runtime + .resume_sandbox("default", "resume-retry", true) + .await + .unwrap(); + assert_eq!( + driver.start_resume_requests(), + vec![(true, false), (true, false)], + "a retry repeats the committed fallback choice" + ); + let generations = driver.start_generations(); + assert_eq!(generations[0], generations[1]); + assert!(!has_resume_intent( + &stored(&runtime, sandbox.object_id()).await + )); +} + +#[tokio::test] +async fn failed_resume_of_a_frozen_runtime_restores_suspended() { + let driver = ControlledDriver::new(); + driver.set_start_outcome(ControlledLifecycleOutcome::Error("restore failed")); + let runtime = suspend_capable_runtime(driver.clone()).await; + let sandbox = sandbox_record("sb-resume-fail", "resume-fail", SandboxPhase::Suspended); + runtime.store.put_message(&sandbox).await.unwrap(); + driver.set_get_outcome(ControlledGetOutcome::Sandbox(Box::new( + exited_driver_sandbox(&sandbox), + ))); + + runtime + .resume_sandbox("default", "resume-fail", false) + .await + .unwrap_err(); + + let restored = stored(&runtime, sandbox.object_id()).await; + assert_eq!(restored.phase(), SandboxPhase::Suspended as i32); + assert!(!has_resume_intent(&restored)); +} + +#[tokio::test] +async fn start_from_suspended_discards_retained_state() { + let driver = ControlledDriver::new(); + let runtime = suspend_capable_runtime(driver.clone()).await; + let sandbox = sandbox_record("sb-cold", "cold", SandboxPhase::Suspended); + runtime.store.put_message(&sandbox).await.unwrap(); + + let starting = runtime.start_sandbox("default", "cold").await.unwrap(); + + assert_eq!(starting.phase(), SandboxPhase::Starting as i32); + assert_eq!(driver.start_resume_requests(), vec![(false, false)]); + assert_ne!( + sandbox_runtime_generation(&starting).unwrap(), + sandbox_runtime_generation(&sandbox).unwrap() + ); +} + +#[tokio::test] +async fn stop_from_suspended_commits_stopped() { + let driver = ControlledDriver::new(); + let runtime = suspend_capable_runtime(driver.clone()).await; + let sandbox = sandbox_record( + "sb-stop-suspended", + "stop-suspended", + SandboxPhase::Suspended, + ); + runtime.store.put_message(&sandbox).await.unwrap(); + + let stopped = runtime + .stop_sandbox("default", "stop-suspended") + .await + .unwrap(); + + assert_eq!(stopped.phase(), SandboxPhase::Stopped as i32); + assert_eq!(driver.stop_calls(), 1); +} + +#[tokio::test] +async fn driver_snapshots_and_sessions_cannot_move_suspension() { + let driver = ControlledDriver::new(); + let runtime = suspend_capable_runtime(driver.clone()).await; + for (id, phase) in [ + ("sb-snapshot-suspending", SandboxPhase::Suspending), + ("sb-snapshot-suspended", SandboxPhase::Suspended), + ] { + let sandbox = sandbox_record(id, id, phase); + runtime.store.put_message(&sandbox).await.unwrap(); + register_test_supervisor_session(&runtime, sandbox.object_id()); + + for snapshot in [ + exited_driver_sandbox(&sandbox), + ready_driver_sandbox(sandbox.object_id(), sandbox.object_name()), + ] { + runtime.apply_sandbox_update(snapshot).await.unwrap(); + assert_eq!(stored(&runtime, id).await.phase(), phase as i32); + } + runtime + .supervisor_session_connected(id, "stale-instance") + .await + .expect_err("a stale supervisor cannot reconnect a suspension"); + assert_eq!(stored(&runtime, id).await.phase(), phase as i32); + } +} + +#[tokio::test] +async fn gateway_restart_retries_suspending_and_leaves_suspended_alone() { + let driver = ControlledDriver::new(); + let mut runtime = + test_runtime_with_gateway_managed_lifecycle(driver.clone(), "test-driver").await; + enable_suspend_resume(&mut runtime); + let suspended = sandbox_record( + "sb-restart-suspended", + "restart-suspended", + SandboxPhase::Suspended, + ); + let suspending = sandbox_record( + "sb-restart-suspending", + "restart-suspending", + SandboxPhase::Suspending, + ); + for sandbox in [&suspended, &suspending] { + runtime.store.put_message(sandbox).await.unwrap(); + } + + runtime.start_persisted_sandboxes().await.unwrap(); + + assert_eq!(driver.suspend_calls(), 1); + assert_eq!(driver.start_calls(), 0, "suspension is never auto-started"); + for sandbox in [&suspended, &suspending] { + assert_eq!( + stored(&runtime, sandbox.object_id()).await.phase(), + SandboxPhase::Suspended as i32 + ); + } + + runtime.cleanup_on_shutdown().await.unwrap(); + assert_eq!( + driver.stop_calls(), + 0, + "shutdown leaves suspended compute alone" + ); +} + +#[tokio::test] +async fn gateway_restart_repeats_an_unresolved_resume() { + let driver = ControlledDriver::new(); + driver.set_start_outcome(ControlledLifecycleOutcome::Error("transport reset")); + driver.set_get_outcome(ControlledGetOutcome::Error("driver unavailable")); + let mut runtime = + test_runtime_with_gateway_managed_lifecycle(driver.clone(), "test-driver").await; + enable_suspend_resume(&mut runtime); + let sandbox = sandbox_record( + "sb-restart-resume", + "restart-resume", + SandboxPhase::Suspended, + ); + runtime.store.put_message(&sandbox).await.unwrap(); + runtime + .resume_sandbox("default", "restart-resume", true) + .await + .unwrap_err(); + assert!(has_resume_intent( + &stored(&runtime, sandbox.object_id()).await + )); + runtime.cleanup_on_shutdown().await.unwrap(); + assert_eq!( + driver.stop_calls(), + 0, + "shutdown keeps the state an unresolved resume still needs" + ); + + driver.set_start_outcome(ControlledLifecycleOutcome::Ok); + runtime.start_persisted_sandboxes().await.unwrap(); + + let requests = driver.start_resume_requests(); + assert_eq!(requests[0], (true, true)); + assert_eq!( + requests[1], + (true, true), + "recovery repeats the committed resume" + ); + assert!( + requests[2..] + .iter() + .all(|request| *request == (false, false)), + "after the driver accepts the resume, later starts boot fresh: {requests:?}" + ); + let generations = driver.start_generations(); + assert!( + generations + .iter() + .all(|generation| *generation == generations[0]) + ); + assert!(!has_resume_intent( + &stored(&runtime, sandbox.object_id()).await + )); +} + +#[tokio::test] +async fn main_process_exit_wins_over_pending_suspend() { + for outcome in [ + ControlledLifecycleOutcome::Ok, + ControlledLifecycleOutcome::Error("process already exited"), + ] { + for exit_code in [0, 9] { + let driver = ControlledDriver::new(); + driver.suspend_blocked.store(true, Ordering::SeqCst); + driver.set_suspend_outcome(outcome.clone()); + let runtime = suspend_capable_runtime(driver.clone()).await; + let mut sandbox = sandbox_record("sb-exit-race", "exit-race", SandboxPhase::Ready); + sandbox.status.as_mut().unwrap().main_process_instance_id = "instance-1".into(); + runtime.store.put_message(&sandbox).await.unwrap(); + driver.set_get_outcome(ControlledGetOutcome::Sandbox(Box::new( + ready_driver_sandbox(sandbox.object_id(), sandbox.object_name()), + ))); + let pending = { + let runtime = runtime.clone(); + tokio::spawn(async move { runtime.suspend_sandbox("default", "exit-race").await }) + }; + driver.suspend_started.notified().await; + assert_eq!( + stored(&runtime, sandbox.object_id()).await.phase(), + SandboxPhase::Suspending as i32 + ); + runtime + .report_main_process_exit(sandbox.object_id(), "instance-1", exit_code) + .await + .unwrap(); + runtime + .finalize_main_process_exit(sandbox.object_id(), "instance-1") + .await + .unwrap(); + driver.suspend_release.add_permits(1); + pending.await.unwrap().unwrap_err(); + let completed = stored(&runtime, sandbox.object_id()).await; + assert_eq!( + completed.phase(), + if exit_code == 0 { + SandboxPhase::Completed + } else { + SandboxPhase::Error + } as i32 + ); + assert_eq!(completed.status.unwrap().exit_code, Some(exit_code)); + } + } +} + +#[tokio::test] +async fn failed_recovered_resume_preserves_retryable_state() { + for recover_on_startup in [false, true] { + for confirmed_stopped in [false, true] { + let driver = ControlledDriver::new(); + driver.set_start_outcome(ControlledLifecycleOutcome::Error("restore failed")); + driver.set_get_outcome(ControlledGetOutcome::Error("driver unavailable")); + let mut runtime = + test_runtime_with_gateway_managed_lifecycle(driver.clone(), "test-driver").await; + enable_suspend_resume(&mut runtime); + let sandbox = sandbox_record( + "sb-recover-resume", + "recover-resume", + SandboxPhase::Suspended, + ); + runtime.store.put_message(&sandbox).await.unwrap(); + runtime + .resume_sandbox("default", "recover-resume", false) + .await + .unwrap_err(); + let pending = stored(&runtime, sandbox.object_id()).await; + if confirmed_stopped { + driver.set_get_outcome(ControlledGetOutcome::Sandbox(Box::new( + exited_driver_sandbox(&sandbox), + ))); + } + if recover_on_startup { + runtime.start_persisted_sandboxes().await.unwrap(); + } else { + runtime + .resume_sandbox("default", "recover-resume", false) + .await + .unwrap_err(); + } + let recovered = stored(&runtime, sandbox.object_id()).await; + assert_eq!( + driver.start_calls(), + 2, + "startup must not retry an unresolved resume twice" + ); + assert_eq!( + sandbox_runtime_generation(&recovered), + sandbox_runtime_generation(&pending) + ); + assert_eq!( + recovered.phase(), + if confirmed_stopped { + SandboxPhase::Suspended + } else { + SandboxPhase::Starting + } as i32 + ); + assert_eq!(has_resume_intent(&recovered), !confirmed_stopped); + driver.set_start_outcome(ControlledLifecycleOutcome::Ok); + runtime + .resume_sandbox("default", "recover-resume", false) + .await + .unwrap(); + } + } +} + +#[tokio::test] +async fn successful_resume_compensation_records_stopped_without_retained_state() { + for (missing_identity, ready_before_response) in [(false, false), (true, false), (false, true)] + { + let driver = ControlledDriver::new(); + driver.set_runtime_identity(if missing_identity { + "" + } else { + "new-runtime-identity" + }); + if ready_before_response { + driver.block_start(); + } + let (_directory, mut runtime) = runtime_with_binding_store_failure(driver.clone()).await; + enable_suspend_resume(&mut runtime); + let mut sandbox = sandbox_record( + "sb-resume-store-failure", + "resume-store-failure", + SandboxPhase::Suspended, + ); + set_compute_runtime_binding(&mut sandbox, "previous-runtime-identity"); + let old_generation = sandbox_runtime_generation(&sandbox).unwrap(); + runtime.store.put_message(&sandbox).await.unwrap(); + + let error = if ready_before_response { + let pending = { + let runtime = runtime.clone(); + let name = sandbox.object_name().to_string(); + tokio::spawn(async move { runtime.resume_sandbox("default", &name, false).await }) + }; + driver.start_started.notified().await; + let starting = stored(&runtime, sandbox.object_id()).await; + runtime + .store + .update_message_cas::( + sandbox.object_id(), + sandbox_resource_version(&starting), + |current| current.set_phase(SandboxPhase::Ready as i32), + ) + .await + .unwrap(); + register_test_supervisor_session(&runtime, sandbox.object_id()); + driver.release_start(); + pending.await.unwrap().unwrap_err() + } else { + runtime + .resume_sandbox("default", sandbox.object_name(), false) + .await + .unwrap_err() + }; + assert!( + error.message().contains(if missing_identity { + "did not return a runtime identity" + } else { + "persist compute runtime identity failed" + }), + "{error}" + ); + assert_eq!(driver.start_calls(), 1); + assert_eq!(driver.stop_calls(), 1); + let stopped = stored(&runtime, sandbox.object_id()).await; + assert_eq!(stopped.phase(), SandboxPhase::Stopped as i32); + assert_eq!( + ready_condition(&stopped).unwrap().reason, + "ResumeRolledBack" + ); + assert!(!has_resume_intent(&stopped)); + assert!(!runtime.supervisor_sessions.has_session(sandbox.object_id())); + assert_ne!( + sandbox_runtime_generation(&stopped).unwrap(), + old_generation + ); + assert_eq!( + runtime + .resume_sandbox("default", sandbox.object_name(), false) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + // A clean start is still available, without reusing the consumed reference. + driver.set_runtime_identity("previous-runtime-identity"); + if ready_before_response { + driver.release_start(); + } + runtime + .start_sandbox("default", sandbox.object_name()) + .await + .unwrap(); + assert_eq!( + driver.start_resume_requests(), + vec![(true, false), (false, false)] + ); + } +} + +#[tokio::test] +async fn failed_resume_compensation_does_not_retry_a_consumed_reference() { + let driver = ControlledDriver::new(); + driver.set_runtime_identity("new-runtime-identity"); + driver.set_stop_outcome(ControlledLifecycleOutcome::Error("stop response lost")); + let (_directory, mut runtime) = runtime_with_binding_store_failure(driver.clone()).await; + enable_suspend_resume(&mut runtime); + let mut sandbox = sandbox_record( + "sb-resume-stop-fail", + "resume-stop-fail", + SandboxPhase::Suspended, + ); + set_compute_runtime_binding(&mut sandbox, "previous-runtime-identity"); + runtime.store.put_message(&sandbox).await.unwrap(); + + let error = runtime + .resume_sandbox("default", sandbox.object_name(), false) + .await + .unwrap_err(); + assert!(error.message().contains("stop response lost")); + let unresolved = stored(&runtime, sandbox.object_id()).await; + assert_eq!(unresolved.phase(), SandboxPhase::Starting as i32); + assert!( + !has_resume_intent(&unresolved), + "the successful restore consumed its reference before cleanup" + ); + assert_eq!( + runtime + .resume_sandbox("default", sandbox.object_name(), false) + .await + .unwrap_err() + .code(), + Code::FailedPrecondition + ); + driver.set_runtime_identity("previous-runtime-identity"); + runtime + .start_sandbox("default", sandbox.object_name()) + .await + .unwrap(); + assert_eq!( + driver.start_resume_requests(), + vec![(true, false), (false, false)] + ); +} + +#[tokio::test] +async fn stale_resume_compensation_cannot_clear_a_newer_operation_intent() { + let driver = ControlledDriver::new(); + let runtime = suspend_capable_runtime(driver.clone()).await; + let mut sandbox = sandbox_record("sb-resume-owner", "resume-owner", SandboxPhase::Starting); + sandbox.status.as_mut().unwrap().provisioning = Some( + provisioning_deadline::new_preparation_record(openshell_core::time::now_ms(), 1800), + ); + let generation = sandbox_runtime_generation(&sandbox).unwrap(); + write_start_intent( + &mut sandbox.metadata.as_mut().unwrap().annotations, + generation.as_str(), + StartIntent::Resume { + restart_if_restore_fails: false, + }, + ); + runtime.store.put_message(&sandbox).await.unwrap(); + let current = stored(&runtime, sandbox.object_id()).await; + let ((), old_settled) = runtime + .await_provisioning_operation(¤t, async { Ok(()) }) + .await + .unwrap(); + let ((), newer) = runtime + .await_provisioning_operation(&old_settled, async { Ok(()) }) + .await + .unwrap(); + let gate = runtime.lifecycle_gates.lock_for(sandbox.object_id()).await; + let error = runtime + .compensate_successful_start( + &gate, + &old_settled, + &sandbox, + Status::internal("missing binding"), + ) + .await; + assert!(error.message().contains("cleanup deferred")); + assert_eq!(driver.stop_calls(), 0); + let retained = stored(&runtime, sandbox.object_id()).await; + assert!(has_resume_intent(&retained)); + assert_eq!( + sandbox_resource_version(&retained), + sandbox_resource_version(&newer) + ); +} diff --git a/crates/openshell-server/src/grpc/mod.rs b/crates/openshell-server/src/grpc/mod.rs index 0368025348..7a917d8c85 100644 --- a/crates/openshell-server/src/grpc/mod.rs +++ b/crates/openshell-server/src/grpc/mod.rs @@ -60,14 +60,14 @@ use openshell_core::proto::{ RemoveWorkspaceMemberResponse, ReportEndpointStatusRequest, ReportEndpointStatusResponse, ReportMainProcessExitRequest, ReportMainProcessExitResponse, ReportPolicyStatusRequest, ReportPolicyStatusResponse, ReportProviderReadinessRequest, ReportProviderReadinessResponse, - ResourceCapabilities, RevokeSshSessionRequest, RevokeSshSessionResponse, + ResourceCapabilities, ResumeSandboxRequest, RevokeSshSessionRequest, RevokeSshSessionResponse, RotateProviderCredentialRequest, RotateProviderCredentialResponse, SandboxResponse, SandboxTemplateResponse, ServiceEndpointResponse, ServiceStatus, StartSandboxRequest, StopSandboxRequest, SubmitPolicyAnalysisRequest, SubmitPolicyAnalysisResponse, - SupervisorMessage, TcpForwardFrame, UndoDraftChunkRequest, UndoDraftChunkResponse, - UpdateConfigRequest, UpdateConfigResponse, UpdateProviderProfilesRequest, - UpdateProviderProfilesResponse, UpdateProviderRequest, WatchSandboxRequest, - open_shell_server::OpenShell, + SupervisorMessage, SuspendSandboxRequest, TcpForwardFrame, UndoDraftChunkRequest, + UndoDraftChunkResponse, UpdateConfigRequest, UpdateConfigResponse, + UpdateProviderProfilesRequest, UpdateProviderProfilesResponse, UpdateProviderRequest, + WatchSandboxRequest, open_shell_server::OpenShell, }; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -436,6 +436,20 @@ impl OpenShell for OpenShellService { mutation_replay::run(&self.state, request).await } + async fn suspend_sandbox( + &self, + request: Request, + ) -> Result, Status> { + sandbox::handle_suspend_sandbox(&self.state, request).await + } + + async fn resume_sandbox( + &self, + request: Request, + ) -> Result, Status> { + sandbox::handle_resume_sandbox(&self.state, request).await + } + // --- Exec --- type ExecSandboxStream = ReceiverStream>; diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index 75baeea81b..77a54a2bc8 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -34,11 +34,11 @@ use openshell_core::proto::{ ExecSandboxStdout, GetSandboxRequest, GetSandboxTemplateRequest, ListSandboxProvidersRequest, ListSandboxProvidersResponse, ListSandboxTemplatesRequest, ListSandboxTemplatesResponse, ListSandboxesRequest, ListSandboxesResponse, Provider, ProviderMutationKind, - ResourceRequirements, RevokeSshSessionRequest, RevokeSshSessionResponse, SandboxResources, - SandboxResponse, SandboxSpec, SandboxStreamEvent, SandboxTemplateResponse, + ResourceRequirements, ResumeSandboxRequest, RevokeSshSessionRequest, RevokeSshSessionResponse, + SandboxResources, SandboxResponse, SandboxSpec, SandboxStreamEvent, SandboxTemplateResponse, SandboxWorkloadTemplate, SandboxWorkloadTemplateProvenance, SshRelayTarget, - StartSandboxRequest, StopSandboxRequest, TcpForwardFrame, TcpForwardInit, TcpRelayTarget, - WatchSandboxRequest, relay_open, tcp_forward_init, + StartSandboxRequest, StopSandboxRequest, SuspendSandboxRequest, TcpForwardFrame, + TcpForwardInit, TcpRelayTarget, WatchSandboxRequest, relay_open, tcp_forward_init, }; use openshell_core::proto::{ BeginRootfsTarStagingRequest, BeginRootfsTarStagingResponse, Sandbox, SandboxPhase, @@ -1840,6 +1840,103 @@ async fn handle_start_sandbox_inner( })) } +pub(super) async fn handle_suspend_sandbox( + state: &Arc, + request: Request, +) -> Result, Status> { + let result = handle_suspend_sandbox_inner(state, request).await; + openshell_core::telemetry::emit_lifecycle( + LifecycleResource::Sandbox, + LifecycleOperation::Suspend, + if result.is_ok() { + TelemetryOutcome::Success + } else { + TelemetryOutcome::Failure + }, + ); + result +} + +async fn handle_suspend_sandbox_inner( + state: &Arc, + request: Request, +) -> Result, Status> { + let principal = super::extract_principal(&request)?; + let req = request.into_inner(); + let resolved = resolve_and_authorize_sandbox_name( + state, + &principal, + &req.name, + crate::auth::workspace_authz::selected_workspace_name(req.workspace_scope.as_ref())?, + MinWorkspaceRole::User, + ) + .await?; + let workspace = resolved.object_workspace(); + let name = resolved.object_name(); + let sandbox = state.compute.suspend_sandbox(workspace, name).await?; + info!(sandbox_name = %name, "SuspendSandbox request completed successfully"); + Ok(Response::new(SandboxResponse { + sandbox: Some(sandbox), + service_urls: HashMap::new(), + })) +} + +pub(super) async fn handle_resume_sandbox( + state: &Arc, + request: Request, +) -> Result, Status> { + let result = handle_resume_sandbox_inner(state, request).await; + openshell_core::telemetry::emit_lifecycle( + LifecycleResource::Sandbox, + LifecycleOperation::Resume, + if result.is_ok() { + TelemetryOutcome::Success + } else { + TelemetryOutcome::Failure + }, + ); + result +} + +async fn handle_resume_sandbox_inner( + state: &Arc, + request: Request, +) -> Result, Status> { + let principal = super::extract_principal(&request)?; + let req = request.into_inner(); + let resolved = resolve_and_authorize_sandbox_name( + state, + &principal, + &req.name, + crate::auth::workspace_authz::selected_workspace_name(req.workspace_scope.as_ref())?, + MinWorkspaceRole::User, + ) + .await?; + let workspace = resolved.object_workspace().to_string(); + let name = resolved.object_name().to_string(); + let mut sandbox = state + .compute + .resume_sandbox_authenticated( + &workspace, + &name, + req.restart_if_restore_fails, + state.sandbox_session_jwt_authority.as_deref(), + ) + .await?; + let remote_authority = + crate::supervisor_session::remote_supervisor_owner(state, sandbox.object_id()) + .await? + .is_some(); + state + .supervisor_sessions + .project_endpoint_status(&mut sandbox, remote_authority); + info!(sandbox_name = %name, "ResumeSandbox request completed successfully"); + Ok(Response::new(SandboxResponse { + sandbox: Some(sandbox), + service_urls: HashMap::new(), + })) +} + pub async fn mint_persisted_authentication( state: &ServerState, sandbox: &Sandbox, @@ -2499,7 +2596,11 @@ pub(super) async fn handle_watch_sandbox( fn is_watch_terminal(phase: SandboxPhase) -> bool { matches!( phase, - SandboxPhase::Ready | SandboxPhase::Completed | SandboxPhase::Stopped | SandboxPhase::Error + SandboxPhase::Ready + | SandboxPhase::Completed + | SandboxPhase::Stopped + | SandboxPhase::Suspended + | SandboxPhase::Error ) } @@ -4231,6 +4332,7 @@ mod tests { SandboxPhase::Ready, SandboxPhase::Completed, SandboxPhase::Stopped, + SandboxPhase::Suspended, SandboxPhase::Error, ] { assert!(is_watch_terminal(phase), "{phase:?} should stop the watch"); @@ -4239,6 +4341,7 @@ mod tests { SandboxPhase::Provisioning, SandboxPhase::Starting, SandboxPhase::Stopping, + SandboxPhase::Suspending, SandboxPhase::Deleting, SandboxPhase::Unknown, ] { diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index 774e6226c6..49d158637a 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -158,10 +158,15 @@ mod tests { // record; absent report extensions retain compatibility without a rewrite. // Supervisor middleware binding policy and selectors are public-only. An // absent policy preserves dynamic discovery; older supervisors ignore both fields. + // Suspend/resume adds two public request messages without durable request + // admission, the restart_if_restore_fails resume option, and the SUSPENDING + // and SUSPENDED values to the shared + // SandboxPhase enum. Stored rows never carried those values, so prior + // payloads decode unchanged. const PUBLIC_RPC_SCHEMA_SHA256: &str = - "5ae09053b7d6a114971edc32770918d63ae5848bb9670135b67d7891dec1ccd5"; + "f24c9b77a85f59ae9ab60f783d45654d78bf566fcf260f9131f1aba39fa4b59b"; const DURABLE_SCHEMA_SHA256: &str = - "d4dc7abdb91b919db1f7be0d4652e30cbfda86f3b2ed9b59d5de1f76a2bf691d"; + "ffb20595e36032a9476d1c6956e2dcdc814f85286fc4735751e5ec6f499ea9ed"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = "ac1ffc4b5b81467de27270a4e33f6db1e31eeb2c52f79750dbaaf19515eadbb2"; // Encoded with the schema that omitted stable_placeholder. Keep these @@ -626,7 +631,7 @@ mod tests { } assert_eq!( compiled_method_count, - 103 + PROVIDER_READINESS_RPC_SIGNATURES.len() + 106 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len() + PEER_CONFIG_RPC_SIGNATURES.len() + isolation_methods.len() @@ -636,7 +641,7 @@ mod tests { ); assert_eq!( methods.len(), - 78 + PROVIDER_READINESS_RPC_SIGNATURES.len() + 80 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len() + PEER_CONFIG_RPC_SIGNATURES.len(), "inventory every public gateway RPC" @@ -646,7 +651,7 @@ mod tests { .iter() .filter(|method| method.starts_with("openshell.v1.OpenShell/")) .count(), - 78 + PROVIDER_READINESS_RPC_SIGNATURES.len() + 80 + PROVIDER_READINESS_RPC_SIGNATURES.len() + PEER_OWNER_RPC_SIGNATURES.len() + PEER_CONFIG_RPC_SIGNATURES.len() ); @@ -697,7 +702,7 @@ mod tests { overlap_hash.as_str(), ), ( - (328, 31), + (330, 31), (95, 22), (83, 22), PUBLIC_RPC_SCHEMA_SHA256, diff --git a/crates/openshell-server/src/test_support.rs b/crates/openshell-server/src/test_support.rs index 5aa4a70f5c..112b47cf40 100644 --- a/crates/openshell-server/src/test_support.rs +++ b/crates/openshell-server/src/test_support.rs @@ -21,9 +21,9 @@ use openshell_core::proto::compute::v1::{ DeleteWorkspaceRequest, DeleteWorkspaceResponse, DriverSandbox, EnsureWorkspaceRequest, EnsureWorkspaceResponse, GetCapabilitiesRequest, GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse, ListSandboxesRequest, ListSandboxesResponse, StartSandboxRequest, - StartSandboxResponse, StopSandboxRequest, StopSandboxResponse, ValidateSandboxCreateRequest, - ValidateSandboxCreateResponse, WatchSandboxesEvent, WatchSandboxesRequest, - compute_driver_server::ComputeDriver, + StartSandboxResponse, StopSandboxRequest, StopSandboxResponse, SuspendSandboxRequest, + SuspendSandboxResponse, ValidateSandboxCreateRequest, ValidateSandboxCreateResponse, + WatchSandboxesEvent, WatchSandboxesRequest, compute_driver_server::ComputeDriver, }; use std::collections::HashMap; #[cfg(unix)] @@ -401,6 +401,15 @@ impl ComputeDriver for FakeComputeDriver { Ok(Response::new(CreateSandboxResponse::default())) } + async fn suspend_sandbox( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented( + "the test compute driver does not support sandbox suspend", + )) + } + async fn stop_sandbox( &self, request: Request, diff --git a/crates/openshell-server/tests/common/mod.rs b/crates/openshell-server/tests/common/mod.rs index 4d41124c01..a4072b57b4 100644 --- a/crates/openshell-server/tests/common/mod.rs +++ b/crates/openshell-server/tests/common/mod.rs @@ -184,6 +184,20 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("unused")) } + async fn suspend_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn resume_sandbox( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + async fn get_sandbox( &self, _request: tonic::Request, diff --git a/crates/openshell-server/tests/supervisor_relay_integration.rs b/crates/openshell-server/tests/supervisor_relay_integration.rs index 910a54daf8..ceb2fa6bf8 100644 --- a/crates/openshell-server/tests/supervisor_relay_integration.rs +++ b/crates/openshell-server/tests/supervisor_relay_integration.rs @@ -240,6 +240,18 @@ impl OpenShell for RelayGateway { ) -> Result, Status> { Err(Status::unimplemented("unused")) } + async fn suspend_sandbox( + &self, + _: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + async fn resume_sandbox( + &self, + _: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } async fn get_sandbox( &self, _: tonic::Request, diff --git a/crates/openshell-supervisor/README.md b/crates/openshell-supervisor/README.md index 10964b8542..249076d458 100644 --- a/crates/openshell-supervisor/README.md +++ b/crates/openshell-supervisor/README.md @@ -35,7 +35,8 @@ policy inputs, auth bundle, backend descriptor, and file locations. `SandboxInstanceBindings` is the live state its owner prepares once: the `GatewayCredentials` issued from the auth bundle, the OCSF context and JSON settings, the log sink, and the denial history served by `policy.local`. -`SandboxInstanceControls` carries the owner's stop signal and readiness. +`SandboxInstanceControls` carries the owner's stop signal, suspension requests, +and readiness. Everything else, including credential renewal, policy, provider credentials and token grants, middleware credentials, the backend connection, and the access plane, is created by the instance. Gateway clients receive a `GatewayEndpoint`, @@ -82,6 +83,32 @@ trust directory uses its private directory. Hosted processes must install `LogPushLayer::thread_bound` and an `OcsfShorthandLayer` writing to `SandboxInstanceDenialWriter`. +## Suspend and resume + +The dedicated process wrapper installs a `SIGUSR1` handler at startup and +maps it to that instance's suspension request stream. Hosted instances never +subscribe to process-wide suspension signals; `SandboxInstanceHost::request_suspend` +queues a request for one instance by key. Pending requests coalesce, and a +failed suspension can be retried with another request. After the workload +starts, requests suspend it when the backend advertises +`openshell.sandbox.suspend-resume`; otherwise the instance ignores them. + +While suspending, the supervisor stops waiting on the workload so a fenced +generation's stream failure cannot race the request. The backend retains the +state and hands its handle to the compute driver through their native +integration. On success the instance ends with status 0 without writing a +reference file, calling `TerminateBoundary`, or reporting a main-process exit. +The dedicated wrapper exits; a shared host keeps its other instances running. +On failure it resumes waiting on the workload. Both outcomes emit OCSF events +without reference bytes. + +Resume is provisioned by the driver and backend. The supervisor's ordinary +`OpenBoundary` call can prepare a restored boundary. The opening response selects +its launch path; actual restoration may wait until `StartAgent`, after policy +admission. A late restore failure fails startup. A successful resumed launch is +reported only after `StartAgent` succeeds. No retention state or policy is carried +in the shared supervisor bootstrap metadata. + ## Console logging Diagnostics and OCSF shorthand share a bounded, nonblocking stderr writer. With `ocsf_json_enabled=true`, the same writer also receives timestamped `OCSF-JSON` records. Each formatter submits a complete line in one write so concurrent producers cannot interleave records in the queue. The 1,024-line queue drops new lines when full rather than waiting for stderr. diff --git a/crates/openshell-supervisor/src/backend_setup/tests.rs b/crates/openshell-supervisor/src/backend_setup/tests.rs index b4704bf623..8ab63a1188 100644 --- a/crates/openshell-supervisor/src/backend_setup/tests.rs +++ b/crates/openshell-supervisor/src/backend_setup/tests.rs @@ -16,6 +16,7 @@ use openshell_supervisor_network::upstream_proxy::UpstreamProxyArgs; const TEST_BACKEND: &str = "in-process-test"; // Deliberately not JSON or a SandboxRuntimeDescriptor. Only TestSetup accepts it. const TEST_PAYLOAD: &[u8] = b"in-process-v1\0owned-launch"; +const TEST_RESTORE_REFERENCE: &[u8] = b"opaque\0restore-reference"; #[test] fn endpoint_registrations_reject_duplicates_builtin_replacement_and_bad_routes() { @@ -118,6 +119,13 @@ struct Observed { active: AtomicBool, starts: AtomicUsize, releases: AtomicUsize, + suspendable: AtomicBool, + restore: AtomicBool, + defer_restore: AtomicBool, + restore_fails: AtomicBool, + restores: AtomicUsize, + suspends: Arc, + boundary_terminations: AtomicUsize, } impl Observed { @@ -284,7 +292,8 @@ impl PreparedBackend for TestLaunch { let handler = Arc::new( move |request: openshell_sandbox_backend::boundary_protocol::Request| { use openshell_sandbox_backend::boundary_protocol::{ - ExitStatusWire, Request, Response, SessionSnapshotWire, + ExitStatusWire, OutputWindowWire, ProcessKindWire, ProcessSnapshotWire, + Request, Response, SessionSnapshotWire, }; let _lease = &lease; Ok(match request { @@ -293,10 +302,28 @@ impl PreparedBackend for TestLaunch { if observed.active.swap(true, Ordering::SeqCst) { return Err(BackendError::Denied("already attached".into())); } + // A deferred restore has no live process to expose yet. + let processes = if observed.restore.load(Ordering::SeqCst) + && !observed.defer_restore.load(Ordering::SeqCst) + { + vec![ProcessSnapshotWire { + process_id: "main".into(), + kind: ProcessKindWire::Main, + terminal: false, + status: None, + retained_output: OutputWindowWire { + first_sequence: 0, + next_sequence: 0, + truncated: false, + }, + }] + } else { + vec![] + }; Response::Attached { snapshot: SessionSnapshotWire { generation: generation.clone(), - processes: vec![], + processes, }, } } @@ -336,6 +363,15 @@ impl PreparedBackend for TestLaunch { } observed.record("start"); observed.starts.fetch_add(1, Ordering::SeqCst); + if observed.defer_restore.load(Ordering::SeqCst) { + assert!(observed.events().contains(&"confirm")); + observed.restores.fetch_add(1, Ordering::SeqCst); + if observed.restore_fails.load(Ordering::SeqCst) { + return Err(BackendError::Process( + "deferred restore failed".into(), + )); + } + } Response::Started { process_id: "main".into(), provider_env_revision, @@ -346,12 +382,23 @@ impl PreparedBackend for TestLaunch { status: ExitStatusWire::Exited(0), }, Request::AttachProcess { .. } => Response::ProcessAttached { terminal: false }, - Request::TerminateBoundary => Response::BoundaryTerminated, + Request::TerminateBoundary => { + observed + .boundary_terminations + .fetch_add(1, Ordering::SeqCst); + Response::BoundaryTerminated + } _ => return Err(BackendError::Unsupported("test peer".into())), }) }, ); - let backend = openshell_sandbox_backend::test_support::backend( + let suspension = self.observed.suspendable.load(Ordering::SeqCst).then(|| { + openshell_sandbox_backend::test_support::Suspension { + reference: TEST_RESTORE_REFERENCE.to_vec(), + calls: self.observed.suspends.clone(), + } + }); + let backend = openshell_sandbox_backend::test_support::suspendable_backend( self.name.into(), SandboxContext { sandbox_id: "sandbox-1".into(), @@ -366,11 +413,16 @@ impl PreparedBackend for TestLaunch { services.provider_credentials.clone(), services.sandbox_bearer.clone(), handler, + suspension, ); + let resume = self.observed.restore.load(Ordering::SeqCst).then(|| { + openshell_sandbox_backend::ResumeLaunch::new(TEST_RESTORE_REFERENCE.to_vec(), false) + .unwrap() + }); Ok(BuiltBackend { payload: TEST_PAYLOAD.to_vec(), proxy_listener: None, - backend: Arc::new(backend), + backend: Arc::new(backend.with_resume(resume)), }) } } @@ -521,6 +573,94 @@ async fn attachment_receives_live_supervisor_services() { assert!(setup.observed.services.lock().unwrap().upgrade().is_none()); } +#[tokio::test] +async fn restored_boundary_attaches_with_retained_processes_and_starts_agent() { + let setup = TestSetup::new(); + setup.observed.suspendable.store(true, Ordering::SeqCst); + setup.observed.restore.store(true, Ordering::SeqCst); + let (bound, _) = setup + .select() + .attach(setup.services(), policy(), agent()) + .await + .unwrap(); + assert_eq!( + bound.launch_outcome(), + Some(openshell_sandbox_backend::BoundaryLaunchOutcome::Restored) + ); + assert!(bound.supports_suspend()); + let running = bound + .confirm() + .await + .unwrap() + .into_boundary() + .start_agent() + .await + .unwrap(); + assert!(running.supports_suspend()); + assert_eq!( + setup.observed.events(), + ["decode", "build", "attach", "confirm", "start"] + ); + assert_eq!(setup.observed.starts.load(Ordering::SeqCst), 1); +} + +#[tokio::test] +async fn deferred_restore_runs_only_at_start_agent_and_propagates_failure() { + for failure in ["none", "confirmation", "restore"] { + let setup = TestSetup::new(); + setup.observed.suspendable.store(true, Ordering::SeqCst); + setup.observed.restore.store(true, Ordering::SeqCst); + setup.observed.defer_restore.store(true, Ordering::SeqCst); + setup + .observed + .deny_confirmation + .store(failure == "confirmation", Ordering::SeqCst); + setup + .observed + .restore_fails + .store(failure == "restore", Ordering::SeqCst); + let (bound, _) = setup + .select() + .attach(setup.services(), policy(), agent()) + .await + .unwrap(); + // RESTORED selects the launch path even though no restore has run yet. + assert_eq!( + bound.launch_outcome(), + Some(openshell_sandbox_backend::BoundaryLaunchOutcome::Restored) + ); + assert_eq!(setup.observed.restores.load(Ordering::SeqCst), 0); + let confirmed = bound.confirm().await; + assert_eq!(setup.observed.restores.load(Ordering::SeqCst), 0); + if failure == "confirmation" { + assert!(confirmed.is_err()); + assert_eq!(setup.observed.starts.load(Ordering::SeqCst), 0); + continue; + } + let started = confirmed.unwrap().into_boundary().start_agent().await; + assert_eq!(setup.observed.restores.load(Ordering::SeqCst), 1); + if failure == "restore" { + let Err(error) = started else { + panic!("a failed restore must fail StartAgent") + }; + assert!( + error.to_string().contains("deferred restore failed"), + "{error}" + ); + } else { + let running = started.unwrap(); + assert_eq!( + running.launch_outcome(), + Some(openshell_sandbox_backend::BoundaryLaunchOutcome::Restored) + ); + } + assert_eq!( + setup.observed.events(), + ["decode", "build", "attach", "confirm", "start"] + ); + } +} + #[tokio::test] async fn constructed_backend_must_keep_selected_name() { let mut setup = TestSetup::new(); @@ -824,3 +964,142 @@ async fn shared_startup_uses_selected_backend_through_readiness_and_shutdown() { .is_err() ); } + +/// Runs in an isolated child for the same reasons as the shared startup test: +/// signals and auth slots are process-wide. +#[cfg(unix)] +#[tokio::test] +async fn suspend_signal_exits_without_terminating_boundary() { + use std::time::Duration; + + const CHILD_ROOT: &str = "OPENSHELL_TEST_SUSPEND_ROOT"; + const TEST: &str = "backend_setup::tests::suspend_signal_exits_without_terminating_boundary"; + let Ok(root) = std::env::var(CHILD_ROOT) else { + let root = tempfile::Builder::new() + .prefix("suspend-backend-") + .tempdir_in("/tmp") + .unwrap(); + let mut child = tokio::process::Command::new(std::env::current_exe().unwrap()); + child.args(["--exact", TEST, "--nocapture", "--test-threads=1"]); + for (name, _) in std::env::vars_os() { + if name.to_string_lossy().starts_with("OPENSHELL_") { + child.env_remove(name); + } + } + child + .env(CHILD_ROOT, root.path()) + .env( + openshell_core::sandbox_env::PROXY_TLS_DIR, + root.path().join("tls"), + ) + .kill_on_drop(true); + let output = tokio::time::timeout(Duration::from_secs(30), child.output()) + .await + .expect("suspend child exceeded its deadline") + .expect("run isolated suspend test"); + assert!( + output.status.success(), + "suspend child failed: {}\n{}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr), + ); + return; + }; + + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + let root = PathBuf::from(root); + let rules = root.join("policy.rego"); + let data = root.join("policy.yaml"); + let readiness = root.join("ready.sock"); + let marker = root.join("main-exit"); + std::fs::write( + &rules, + include_str!("../../../openshell-supervisor-network/data/sandbox-policy.rego"), + ) + .unwrap(); + std::fs::write(&data, "network_policies: {}\n").unwrap(); + + let setup = TestSetup::new(); + let startup = || { + let config = crate::SandboxInstanceConfig { + command: vec!["test-agent".into(), "test-argument".into()], + workdir: Some("/test-workspace".into()), + timeout_secs: 15, + interactive: false, + await_main_process_attachment: false, + sandbox_id: Some(setup.sandbox_id.clone()), + sandbox: None, + container_image: String::new(), + openshell_endpoint: None, + policy_rules: Some(rules.to_string_lossy().into_owned()), + policy_data: Some(data.to_string_lossy().into_owned()), + ssh_socket_path: None, + shared_ssh_socket: false, + upstream_proxy_args: UpstreamProxyArgs::default(), + additional_ca_bundle: None, + backend_descriptor: TestSetup::descriptor(), + auth_bundle: setup.auth.clone(), + admitted_isolation_backend: Some(TEST_BACKEND.into()), + main_exit_marker: Some(marker.clone()), + trace_context: None, + provider_workload_api_socket: None, + // The binary loads the proxy trust directory from its environment. + proxy_tls: openshell_supervisor_network::run::ProxyTlsFiles::from_environment(), + }; + let bindings = crate::SandboxInstanceBindings::dedicated( + &config, + openshell_core::grpc_client::GatewayCredentials::from_auth_bundle(&setup.auth).unwrap(), + openshell_ocsf::OcsfJsonSettings::default(), + ); + Box::pin(crate::run_sandbox_with_backend( + &setup, + config, + bindings, + Some(readiness.clone()), + None, + )) + }; + let wait_ready = || async { + tokio::time::timeout(Duration::from_secs(10), async { + while tokio::net::UnixStream::connect(&readiness).await.is_err() { + tokio::time::sleep(Duration::from_millis(10)).await; + } + }) + .await + .expect("supervisor did not become ready"); + }; + let signal = |signal| nix::sys::signal::kill(nix::unistd::Pid::this(), signal).unwrap(); + + // Without backend support, SIGUSR1 is ignored; SIGTERM still + // stops the sandbox normally. + let ignore_then_stop = async { + wait_ready().await; + signal(nix::sys::signal::Signal::SIGUSR1); + tokio::time::sleep(Duration::from_millis(200)).await; + assert_eq!(setup.observed.suspends.load(Ordering::SeqCst), 0); + signal(nix::sys::signal::Signal::SIGTERM); + }; + let (result, ()) = tokio::join!(startup(), ignore_then_stop); + result.unwrap(); + assert_eq!(setup.observed.suspends.load(Ordering::SeqCst), 0); + let terminal_count = setup.observed.boundary_terminations.load(Ordering::SeqCst); + // This non-suspendable fixture completes its main process immediately. + // Clear that completed generation's marker before the suspension case. + let _ = std::fs::remove_file(&marker); + setup.observed.suspendable.store(true, Ordering::SeqCst); + + let suspend = async { + wait_ready().await; + signal(nix::sys::signal::Signal::SIGUSR1); + }; + let (result, ()) = tokio::join!(startup(), suspend); + assert_eq!(result.unwrap(), 0); + assert_eq!(setup.observed.suspends.load(Ordering::SeqCst), 1); + assert_eq!( + setup.observed.boundary_terminations.load(Ordering::SeqCst), + terminal_count, + "suspension must not terminate the boundary" + ); + assert!(!marker.exists(), "suspension must not publish a main exit"); + assert!(!readiness.exists()); +} diff --git a/crates/openshell-supervisor/src/lib.rs b/crates/openshell-supervisor/src/lib.rs index a84c70a4a3..86f47b49f0 100644 --- a/crates/openshell-supervisor/src/lib.rs +++ b/crates/openshell-supervisor/src/lib.rs @@ -378,6 +378,115 @@ async fn wait_for_control_shutdown_signal() { let _ = tokio::signal::ctrl_c().await; } +/// SIGUSR1 asks the supervisor to suspend its boundary. The handler is +/// installed at startup so an early signal never takes the default +/// terminating disposition. +#[cfg(unix)] +struct SuspendSignal(tokio::signal::unix::Signal); + +#[cfg(unix)] +impl SuspendSignal { + fn install() -> Result { + use tokio::signal::unix::{SignalKind, signal}; + signal(SignalKind::user_defined1()) + .into_diagnostic() + .wrap_err("install SIGUSR1 suspension handler") + .map(Self) + } + + async fn recv(&mut self) { + if self.0.recv().await.is_none() { + std::future::pending::<()>().await; + } + } +} + +/// Suspension requests are signal-driven and unavailable on non-Unix hosts. +#[cfg(not(unix))] +struct SuspendSignal; + +#[cfg(not(unix))] +impl SuspendSignal { + #[allow(clippy::unnecessary_wraps)] + fn install() -> Result { + Ok(Self) + } + + async fn recv(&mut self) { + std::future::pending::<()>().await; + } +} + +/// Handle one suspension request. Returns true only after the backend fenced +/// the generation and retained its state; the caller +/// must then exit without terminating the boundary or publishing an exit. +async fn suspend_on_request( + running: &openshell_sandbox_backend::RunningBoundary, + backend_name: &str, +) -> bool { + if !running.supports_suspend() { + warn!( + backend = %backend_name, + "Ignoring SIGUSR1: isolation backend does not advertise suspend/resume" + ); + return false; + } + let failure = |reason: String| { + ocsf_emit!( + AppLifecycleBuilder::new(ocsf_ctx()) + .activity(ActivityId::Fail) + .severity(SeverityId::Medium) + .status(StatusId::Failure) + .message(format!( + "Sandbox suspend failed [backend:{backend_name}]: {reason}" + )) + .build() + ); + }; + match running.suspend().await { + Ok(_) => {} + Err(error) => { + failure(error.to_string()); + return false; + } + } + ocsf_emit!( + AppLifecycleBuilder::new(ocsf_ctx()) + .activity(ActivityId::Fail) + .severity(SeverityId::Informational) + .status(StatusId::Success) + .message(format!( + "Sandbox suspended; state retained by backend [backend:{backend_name}]" + )) + .build() + ); + true +} + +/// Report the completed launch path after `StartAgent` succeeds. +fn report_boundary_resumed( + outcome: openshell_sandbox_backend::BoundaryLaunchOutcome, + backend_name: &str, +) { + use openshell_sandbox_backend::BoundaryLaunchOutcome; + let severity = match outcome { + BoundaryLaunchOutcome::Restored => SeverityId::Informational, + // The backend booted cleanly instead; in-memory state was lost. + BoundaryLaunchOutcome::ColdStartFallback | BoundaryLaunchOutcome::Fresh => SeverityId::Low, + }; + ocsf_emit!( + AppLifecycleBuilder::new(ocsf_ctx()) + .activity(ActivityId::Reset) + .severity(severity) + .status(StatusId::Success) + .message(format!( + "Sandbox boundary resumed [backend:{backend_name} outcome:{}]", + outcome.as_str() + )) + .build() + ); +} + use openshell_core::denial::DenialEvent; use openshell_core::policy::{NetworkMode, NetworkPolicy, ProxyPolicy, SandboxPolicy}; use openshell_core::proposals::AgentProposals; @@ -705,12 +814,22 @@ pub async fn run_sandbox_with_backend( .chain(health_port.map(ReadinessEndpoint::Tcp)) .map(|endpoint| ControlReadiness::start(endpoint, Some(instance_readiness.clone()))) .collect::>>()?; + // Only a dedicated process maps process-wide signals to one instance. + let suspend_signal = SuspendSignal::install()?; + let suspend = Box::pin(futures::stream::unfold( + suspend_signal, + |mut signal| async move { + signal.recv().await; + Some(((), signal)) + }, + )); let result = Box::pin(run_sandbox_instance( backend_setup, config, bindings, SandboxInstanceControls { shutdown: Box::pin(wait_for_control_shutdown_signal()), + suspend, readiness, }, )) @@ -849,6 +968,9 @@ pub struct SandboxInstanceControls { /// Completes when the owner asks the instance to stop its workload. It is /// first polled once the workload has started. pub shutdown: Pin + Send>>, + /// Requests to suspend only this instance. A failed suspension can be + /// retried by sending another request. Closing the stream disables it. + pub suspend: Pin + Send>>, /// True while the gateway has accepted this instance's supervision and its /// access plane is retained; false otherwise. pub readiness: tokio::sync::watch::Sender, @@ -950,6 +1072,7 @@ pub async fn run_sandbox_instance( } = bindings; let SandboxInstanceControls { shutdown: shutdown_requested, + mut suspend, readiness, } = controls; // The current client attachment adapter is SSH; retaining a process's I/O @@ -1489,6 +1612,13 @@ pub async fn run_sandbox_instance( .instrument(tracing::info_span!(parent: &startup, "supervisor.boundary.start_agent")) .await .map_err(|error| start_agent_error(error.to_string()))?; + // Opening can only prepare a restore. Report success after StartAgent + // has completed restoration, so a late failure is never logged as resumed. + if let Some(outcome) = running.launch_outcome() + && outcome != openshell_sandbox_backend::BoundaryLaunchOutcome::Fresh + { + report_boundary_resumed(outcome, &backend_name); + } workload_started_tx.send_replace(true); info!(backend = %backend_name, "Isolation boundary agent started"); let agent = running.agent(); @@ -1528,56 +1658,70 @@ pub async fn run_sandbox_instance( let mut instance_readiness = SandboxInstanceReadiness::start(readiness, boundary_access.session_readiness()); let instance_id = boundary_access.instance_id().to_string(); - let wait_agent = agent.clone(); let mut shutdown_requested = shutdown_requested; - let wait = async move { - wait_agent - .wait() - .await - .map(|status| match status { - openshell_isolation_interface::contract::BoundaryExitStatus::Exited(code) => { - code - } - openshell_isolation_interface::contract::BoundaryExitStatus::Signaled( - signal, - ) => 128_i32.saturating_add(signal), - }) - .map_err(|error| miette::miette!(error.to_string())) - }; - let (exit_code, mut retain_access) = tokio::select! { - result = wait => (result?, true), - () = &mut proxy_exited => { - let _ = running.terminate().await; - return Err(miette::miette!( - "control-mode proxy accept loop exited unexpectedly" - )); - } - () = &mut shutdown_requested => { - let _ = agent - .signal(openshell_isolation_interface::contract::BoundarySignal::Term) - .await; - let status = if let Ok(result) = timeout(Duration::from_secs(5), agent.wait()).await { - result - } else { - let _ = agent.terminate().await; - agent.wait().await + // `None` means the boundary was suspended and its reference persisted. + let lifecycle = loop { + let wait_agent = agent.clone(); + let wait = async move { + wait_agent + .wait() + .await + .map(boundary_exit_code) + .map_err(|error| miette::miette!(error.to_string())) + }; + tokio::select! { + result = wait => break Some((result?, true)), + () = &mut proxy_exited => { + let _ = running.terminate().await; + return Err(miette::miette!( + "control-mode proxy accept loop exited unexpectedly" + )); } - .map_err(|error| miette::miette!(error.to_string()))?; - let exit_code = match status { - openshell_isolation_interface::contract::BoundaryExitStatus::Exited(code) => code, - openshell_isolation_interface::contract::BoundaryExitStatus::Signaled(signal) => { - 128_i32.saturating_add(signal) + () = &mut shutdown_requested => { + let _ = agent + .signal(openshell_isolation_interface::contract::BoundarySignal::Term) + .await; + let status = if let Ok(result) = timeout(Duration::from_secs(5), agent.wait()).await { + result + } else { + let _ = agent.terminate().await; + agent.wait().await } - }; - running - .terminate() + .map_err(|error| miette::miette!(error.to_string()))?; + running + .terminate() + .await + .map_err(|error| miette::miette!( + "sandbox did not acknowledge terminal state: {error}" + ))?; + break Some((boundary_exit_code(status), false)); + } + // The agent wait is cancelled while suspending so a fenced + // generation's stream failure cannot race the suspension. + Some(()) = futures::StreamExt::next(&mut suspend) => { + // Boxed to keep the startup future's stack frame small. + if Box::pin(suspend_on_request( + &running, + &backend_name, + )) .await - .map_err(|error| miette::miette!( - "sandbox did not acknowledge terminal state: {error}" - ))?; - (exit_code, false) + { + break None; + } + } } }; + let Some((exit_code, mut retain_access)) = lifecycle else { + // A suspended boundary is retained by the backend: never send + // TerminateBoundary or publish a main-process exit. Dropping the + // access plane closes this supervisor's gateway session. + instance_readiness.release(); + drop(running); + drop(boundary_access); + drop(networking); + info!(backend = %backend_name, "Isolation boundary suspended; supervisor instance exiting"); + return Ok(0); + }; if !retain_access { instance_readiness.release(); } @@ -1640,20 +1784,35 @@ pub async fn run_sandbox_instance( Ok(exit_code) } +fn boundary_exit_code(status: openshell_isolation_interface::contract::BoundaryExitStatus) -> i32 { + match status { + openshell_isolation_interface::contract::BoundaryExitStatus::Exited(code) => code, + openshell_isolation_interface::contract::BoundaryExitStatus::Signaled(signal) => { + 128_i32.saturating_add(signal) + } + } +} + fn persist_main_exit_marker(path: &std::path::Path, exit_code: i32) -> std::io::Result<()> { + write_private_file_atomically(path, format!("exit_code={exit_code}\n").as_bytes()) +} + +/// Replace `path` with `contents` via an owner-only (0600) temporary file in +/// the same directory, fsync, rename, and directory fsync. +fn write_private_file_atomically(path: &std::path::Path, contents: &[u8]) -> std::io::Result<()> { let parent = path .parent() .filter(|parent| !parent.as_os_str().is_empty()) .ok_or_else(|| { std::io::Error::new( std::io::ErrorKind::InvalidInput, - format!("completion marker has no parent: {}", path.display()), + format!("{} has no parent directory", path.display()), ) })?; let name = path.file_name().ok_or_else(|| { std::io::Error::new( std::io::ErrorKind::InvalidInput, - format!("completion marker has no file name: {}", path.display()), + format!("{} has no file name", path.display()), ) })?; let temporary = parent.join(format!( @@ -1661,17 +1820,24 @@ fn persist_main_exit_marker(path: &std::path::Path, exit_code: i32) -> std::io:: name.to_string_lossy(), std::process::id() )); + // A stale temporary could keep broader permissions; always create anew. + let _ = std::fs::remove_file(&temporary); let mut options = std::fs::OpenOptions::new(); - options.write(true).create(true).truncate(true); + options.write(true).create_new(true); #[cfg(unix)] { use std::os::unix::fs::OpenOptionsExt as _; options.mode(0o600); } let mut file = options.open(&temporary)?; - writeln!(file, "exit_code={exit_code}")?; - file.sync_all()?; - std::fs::rename(&temporary, path)?; + let written = file + .write_all(contents) + .and_then(|()| file.sync_all()) + .and_then(|()| std::fs::rename(&temporary, path)); + if let Err(error) = written { + let _ = std::fs::remove_file(&temporary); + return Err(error); + } // Windows cannot open directories through File::open. The marker data is // flushed above and rename still atomically replaces the previous value. #[cfg(unix)] @@ -4624,6 +4790,29 @@ mod tests { ); } + #[cfg(unix)] + #[test] + fn restore_reference_write_is_owner_only_and_replaces_stale_temporary() { + use std::os::unix::fs::PermissionsExt as _; + let directory = tempfile::tempdir().unwrap(); + let reference = directory.path().join("restore-reference"); + let temporary = directory + .path() + .join(format!(".restore-reference.tmp-{}", std::process::id())); + std::fs::write(&temporary, b"stale").unwrap(); + std::fs::set_permissions(&temporary, std::fs::Permissions::from_mode(0o644)).unwrap(); + + write_private_file_atomically(&reference, b"\0opaque\xff").unwrap(); + + assert_eq!(std::fs::read(&reference).unwrap(), b"\0opaque\xff"); + assert_eq!( + std::fs::metadata(&reference).unwrap().permissions().mode() & 0o777, + 0o600 + ); + assert!(!temporary.exists()); + assert!(write_private_file_atomically(std::path::Path::new("/"), b"x").is_err()); + } + #[tokio::test] async fn remote_access_plane_outlives_main_completion_until_teardown() { let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel(); diff --git a/crates/openshell-supervisor/src/main.rs b/crates/openshell-supervisor/src/main.rs index de29e9509a..692041fb13 100644 --- a/crates/openshell-supervisor/src/main.rs +++ b/crates/openshell-supervisor/src/main.rs @@ -248,6 +248,26 @@ fn backend_descriptor(args: &Args, admitted_backend: &str) -> Result Result { + use std::io::Read as _; + let file = std::fs::File::open(path) + .map_err(|error| miette::miette!("read boundary launch metadata: {error}"))?; + let mut bytes = Vec::new(); + file.take(MAX_BOUNDARY_LAUNCH_BYTES as u64 + 1) + .read_to_end(&mut bytes) + .map_err(|error| miette::miette!("read boundary launch metadata: {error}"))?; + if bytes.len() > MAX_BOUNDARY_LAUNCH_BYTES { + return Err(miette::miette!("boundary launch metadata exceeds 1 MiB")); + } + serde_json::from_slice(&bytes) + .map_err(|error| miette::miette!("decode boundary launch metadata: {error}")) +} + fn backend_setup( args: &Args, admitted_backend: &str, @@ -287,10 +307,7 @@ fn backend_setup( let path = args.boundary_launch_file.as_ref().ok_or_else(|| { miette::miette!("--boundary-launch-file is required for a registered external backend") })?; - let bytes = std::fs::read(path) - .map_err(|error| miette::miette!("read boundary launch metadata: {error}"))?; - let launch = serde_json::from_slice(&bytes) - .map_err(|error| miette::miette!("decode boundary launch metadata: {error}"))?; + let launch = read_boundary_launch(path)?; Ok(Box::new(registrations.resolve(admitted_backend, launch)?)) } @@ -1048,6 +1065,18 @@ mod tests { assert!(validate_role_arguments(&args).is_err()); } + #[test] + fn boundary_launch_input_is_bounded_before_decoding() { + let directory = tempfile::tempdir().unwrap(); + let path = directory.path().join("boundary.json"); + assert!(read_boundary_launch(&path).is_err()); + std::fs::write(&path, vec![b' '; MAX_BOUNDARY_LAUNCH_BYTES + 1]).unwrap(); + let error = read_boundary_launch(&path).unwrap_err(); + assert!(error.to_string().contains("exceeds 1 MiB")); + std::fs::write(&path, b"{}").unwrap(); + assert!(read_boundary_launch(&path).is_err()); + } + #[test] fn completion_marker_must_be_absolute() { assert!(validate_main_exit_marker(Some(Path::new("relative"))).is_err()); diff --git a/crates/openshell-supervisor/src/sandbox_instance_host.rs b/crates/openshell-supervisor/src/sandbox_instance_host.rs index 7465701460..30403ba79c 100644 --- a/crates/openshell-supervisor/src/sandbox_instance_host.rs +++ b/crates/openshell-supervisor/src/sandbox_instance_host.rs @@ -142,6 +142,7 @@ struct HostedSandboxInstance { fingerprint: [u8; 32], sandbox_id: String, stop: watch::Sender, + suspend: tokio::sync::mpsc::Sender<()>, abort: watch::Sender, phase: watch::Receiver, ready: watch::Receiver, @@ -302,6 +303,7 @@ impl SandboxInstanceHost { fingerprint, sandbox_id, stop: running.stop, + suspend: running.suspend, abort: running.abort, phase: running.phase, ready: running.ready, @@ -313,6 +315,24 @@ impl SandboxInstanceHost { Ok(SandboxInstanceAdmitted::Created) } + /// Request suspension of one hosted instance. This only queues the request; + /// the backend still decides whether suspension succeeds. Repeated pending + /// requests coalesce. Returns false for missing, removing, or exited instances. + #[must_use] + pub fn request_suspend(&self, key: &str) -> bool { + let instances = lock(&self.instances); + let Some(instance) = instances + .get(key) + .filter(|instance| instance.removal.is_none()) + else { + return false; + }; + matches!( + instance.suspend.try_send(()), + Ok(()) | Err(tokio::sync::mpsc::error::TrySendError::Full(())) + ) + } + /// Status of a hosted sandbox instance, including one that ended but has /// not been removed. The report's route is the instance's key. #[must_use] @@ -469,6 +489,7 @@ impl Removal { /// Signals and thread of one started instance runtime. struct RunningInstance { stop: watch::Sender, + suspend: tokio::sync::mpsc::Sender<()>, abort: watch::Sender, phase: watch::Receiver, ready: watch::Receiver, @@ -481,6 +502,7 @@ fn spawn_instance( changes: ChangeNotifier, ) -> std::result::Result { let (stop, stop_requested) = watch::channel(false); + let (suspend, suspend_requested) = tokio::sync::mpsc::channel(1); let (abort, abort_requested) = watch::channel(false); let (phase_tx, phase) = watch::channel(SandboxInstancePhaseReport::Starting); let (ready_tx, ready) = watch::channel(false); @@ -493,6 +515,7 @@ fn spawn_instance( body, SandboxInstanceSignals { stop_requested, + suspend_requested, abort_requested, phase: phase_tx, ready: ready_tx, @@ -506,6 +529,7 @@ fn spawn_instance( })?; Ok(RunningInstance { stop, + suspend, abort, phase, ready, @@ -515,6 +539,7 @@ fn spawn_instance( struct SandboxInstanceSignals { stop_requested: watch::Receiver, + suspend_requested: tokio::sync::mpsc::Receiver<()>, abort_requested: watch::Receiver, phase: watch::Sender, ready: watch::Sender, @@ -554,6 +579,7 @@ fn run_hosted_sandbox_instance( ) { let SandboxInstanceSignals { stop_requested, + suspend_requested, mut abort_requested, phase, ready, @@ -617,6 +643,7 @@ fn run_hosted_sandbox_instance( }); let instance = body(SandboxInstanceControls { shutdown, + suspend: Box::pin(tokio_stream::wrappers::ReceiverStream::new(suspend_requested)), readiness, }); let outcome = tokio::select! { @@ -852,6 +879,7 @@ mod tests { let SandboxInstanceControls { shutdown, readiness, + .. } = controls; // Nested tasks and the blocking pool inherit the instance identity. let observed = tokio::spawn(async { @@ -963,6 +991,51 @@ mod tests { (root, Arc::new(host)) } + #[tokio::test(flavor = "multi_thread")] + async fn suspend_requests_are_isolated_and_retryable_between_hosted_instances() { + let (_root, host) = private_host(); + let (observed, mut requests) = mpsc::channel(8); + for key in ["alpha", "beta"] { + let observed = observed.clone(); + let body: SandboxInstanceBody = Box::new(move |mut controls| { + Box::pin(async move { + controls.readiness.send_replace(true); + loop { + tokio::select! { + Some(()) = futures::StreamExt::next(&mut controls.suspend) => { + // Leave this instance running, as after a failed + // suspension, so a later request can retry it. + observed.send(key).await.unwrap(); + } + () = &mut controls.shutdown => return Ok(0), + } + } + }) + }); + admit(&host, key, key, 1, unbound(), body).unwrap(); + wait_supervising(&host, key).await; + } + assert!(!host.request_suspend("missing")); + for key in ["alpha", "alpha", "beta"] { + assert!(host.request_suspend(key)); + assert_eq!( + tokio::time::timeout(Duration::from_secs(1), requests.recv()) + .await + .unwrap(), + Some(key) + ); + } + assert!( + requests.try_recv().is_err(), + "requests must never reach another instance" + ); + for key in ["alpha", "beta"] { + assert!(host.status(key).unwrap().ready); + } + host.remove_all(Duration::from_secs(1)).await; + assert!(!host.request_suspend("alpha")); + } + #[tokio::test(flavor = "multi_thread")] async fn one_removal_holds_an_idempotent_admission_until_its_files_are_gone() { let (root, host) = private_host(); diff --git a/crates/openshell-tui/src/lib.rs b/crates/openshell-tui/src/lib.rs index 86529c2e74..133d7d5c0a 100644 --- a/crates/openshell-tui/src/lib.rs +++ b/crates/openshell-tui/src/lib.rs @@ -3094,6 +3094,8 @@ fn phase_label(phase: i32) -> String { x if x == SandboxPhase::Stopped as i32 => "Stopped", x if x == SandboxPhase::Starting as i32 => "Starting", x if x == SandboxPhase::Completed as i32 => "Completed", + x if x == SandboxPhase::Suspending as i32 => "Suspending", + x if x == SandboxPhase::Suspended as i32 => "Suspended", _ => "Unknown", } .to_string() @@ -3197,6 +3199,12 @@ mod phase_label_tests { assert_eq!(phase_label(SandboxPhase::Starting as i32), "Starting"); assert_eq!(phase_label(SandboxPhase::Completed as i32), "Completed"); } + + #[test] + fn phase_label_covers_suspend_and_resume_lifecycle() { + assert_eq!(phase_label(SandboxPhase::Suspending as i32), "Suspending"); + assert_eq!(phase_label(SandboxPhase::Suspended as i32), "Suspended"); + } } /// Format epoch milliseconds as a human-readable UTC timestamp: `YYYY-MM-DD HH:MM`. diff --git a/crates/openshell-tui/src/ui/sandbox_detail.rs b/crates/openshell-tui/src/ui/sandbox_detail.rs index 552bda6a59..726e6d8124 100644 --- a/crates/openshell-tui/src/ui/sandbox_detail.rs +++ b/crates/openshell-tui/src/ui/sandbox_detail.rs @@ -70,7 +70,7 @@ pub fn draw(frame: &mut Frame<'_>, app: &App, area: Rect) { let phase_style = match phase { "Ready" | "Completed" => t.status_ok, - "Provisioning" | "Stopping" | "Starting" => t.status_warn, + "Provisioning" | "Stopping" | "Starting" | "Suspending" => t.status_warn, "Error" => t.status_err, _ => t.muted, }; @@ -78,8 +78,8 @@ pub fn draw(frame: &mut Frame<'_>, app: &App, area: Rect) { let status_indicator = match phase { "Ready" => "●", "Completed" => "✓", - "Provisioning" | "Stopping" | "Starting" => "◐", - "Error" | "Stopped" => "○", + "Provisioning" | "Stopping" | "Starting" | "Suspending" => "◐", + "Error" | "Stopped" | "Suspended" => "○", _ => "…", }; diff --git a/crates/openshell-tui/src/ui/sandboxes.rs b/crates/openshell-tui/src/ui/sandboxes.rs index 3f8a20991e..0acf16e525 100644 --- a/crates/openshell-tui/src/ui/sandboxes.rs +++ b/crates/openshell-tui/src/ui/sandboxes.rs @@ -41,7 +41,7 @@ pub fn draw(frame: &mut Frame<'_>, app: &App, area: Rect, focused: bool) { let phase_style = match phase { "Ready" | "Completed" => t.status_ok, - "Provisioning" | "Stopping" | "Starting" => t.status_warn, + "Provisioning" | "Stopping" | "Starting" | "Suspending" => t.status_warn, "Error" => t.status_err, _ => t.muted, }; diff --git a/examples/isolation-backend-v8/src/driver.rs b/examples/isolation-backend-v8/src/driver.rs index 9d432d36bd..adce131a8f 100644 --- a/examples/isolation-backend-v8/src/driver.rs +++ b/examples/isolation-backend-v8/src/driver.rs @@ -450,6 +450,14 @@ impl compute_driver_server::ComputeDriver for DriverService { } Ok(Response::new(StopSandboxResponse {})) } + async fn suspend_sandbox( + &self, + _: Request, + ) -> Result, Status> { + Err(Status::unimplemented( + "the V8 example compute driver does not support sandbox suspend", + )) + } async fn delete_sandbox( &self, q: Request, @@ -471,6 +479,11 @@ impl compute_driver_server::ComputeDriver for DriverService { q: Request, ) -> Result, Status> { let q = q.into_inner(); + if q.resume { + return Err(Status::unimplemented( + "the V8 example compute driver does not support sandbox resume", + )); + } let mut entry = self.entry.lock().await; let current = entry .as_mut() diff --git a/proto/compute_driver.proto b/proto/compute_driver.proto index 2d3f67b5d7..65da876898 100644 --- a/proto/compute_driver.proto +++ b/proto/compute_driver.proto @@ -51,6 +51,15 @@ service ComputeDriver { // Idempotently start platform resources for a stopped sandbox. rpc StartSandbox(StartSandboxRequest) returns (StartSandboxResponse); + // Idempotently suspend a running sandbox, retaining its memory state. + // Drivers advertise openshell.compute.suspend-resume when implemented; + // otherwise this returns UNIMPLEMENTED. Before returning, the driver has the + // supervisor call IsolationBackend.SuspendBoundary, obtains the retained + // state handle through its native backend integration, and ensures the old + // generation is fenced. The gateway + // never receives the restore reference. + rpc SuspendSandbox(SuspendSandboxRequest) returns (SuspendSandboxResponse); + // Tear down platform resources for a sandbox. rpc DeleteSandbox(DeleteSandboxRequest) returns (DeleteSandboxResponse); @@ -462,8 +471,25 @@ message StartSandboxRequest { // under a different selection. Operator endpoints may change without // changing that identity; the driver still validates the retained resource. IsolationBackendRegistration isolation_backend = 6; + // Restore the state retained by the last SuspendSandbox through + // IsolationBackend.ResumeBoundary. When false, the driver discards any + // retained state and starts fresh. A resume without retained state fails + // with FAILED_PRECONDITION. When the driver can observe a failed restore + // before returning, it should keep the retained state and return an error, + // so the gateway returns the sandbox to SUSPENDED for another attempt. + bool resume = 7; + // Forwarded to ResumeBoundaryRequest.restart_if_restore_fails. + bool restart_if_restore_fails = 8; +} + +message SuspendSandboxRequest { + // Immutable sandbox ID stored by the gateway. The driver resolves its own + // compute-runtime name from this identity. + string sandbox = 1; } +message SuspendSandboxResponse {} + message StartSandboxResponse { // Updated opaque runtime identity after a successful start. Required when // the driver advertises sandbox authentication support. diff --git a/proto/isolation_backend.proto b/proto/isolation_backend.proto index fc9a2023c1..46e2d8481a 100644 --- a/proto/isolation_backend.proto +++ b/proto/isolation_backend.proto @@ -44,6 +44,11 @@ service IsolationBackend { // Reopening the same session and generation returns the same result. The // descriptor must bind to the same provisioned resource; a different resource // binding fails. + // A trusted driver may prepare retained state through its native backend + // integration. In that case OpenBoundary selects RESTORED, or + // COLD_START_FALLBACK only when the driver explicitly permitted it. The + // backend enforces this choice; reference handoff is private to the driver + // and backend and does not require supervisor bootstrap fields. // Driver deletion invalidates all handles and retained-state references, // including abandoned launches and suspended boundaries. rpc OpenBoundary(OpenBoundaryRequest) returns (OpenBoundaryResponse); @@ -55,10 +60,14 @@ service IsolationBackend { // calls and streams are rejected and the old workload cannot make progress. rpc SuspendBoundary(SuspendBoundaryRequest) returns (SuspendBoundaryResponse); - // Restore a suspended boundary using the fresh launch in ResumeBoundaryRequest. - // Follow SandboxProtocol admission while keeping the restored workload frozen - // until StartAgent. A permitted cold start is reported. Unsupported optional - // suspend/resume RPCs return UNIMPLEMENTED without advancing lifecycle state. + // Prepare a suspended boundary using the fresh launch in ResumeBoundaryRequest. + // Validate the reference and reserve its binding without executing workload + // instructions. The backend may defer actual restoration until StartAgent, + // after Attach and Confirm have admitted the new generation's policy. + // Restore failures discovered then fail StartAgent; preparing a boundary does + // not guarantee that restoration will succeed. An eagerly restored workload + // must remain frozen until StartAgent. Unsupported optional suspend/resume + // RPCs return UNIMPLEMENTED without advancing lifecycle state. rpc ResumeBoundary(ResumeBoundaryRequest) returns (OpenBoundaryResponse); } @@ -95,8 +104,12 @@ message OpenBoundaryResponse { LAUNCH_OUTCOME_COLD_START_FALLBACK = 3; } - // Required. Distinguishes restoration from cold-start fallback; admission - // follows SandboxProtocol for either outcome. + // Required. Selects the launch path; it is not proof of completed restoration. + // RESTORED may select a restore deferred until StartAgent. That call must + // either complete this path or fail. The selected path is immutable on replay; + // it must not silently change to a cold start if deferred restoration fails. + // COLD_START_FALLBACK may be selected only when explicitly permitted. + // Admission follows SandboxProtocol for every path. LaunchOutcome outcome = 2; } @@ -127,5 +140,5 @@ message ResumeBoundaryRequest { // boot from the image and persistent volumes is permitted and reported as // LAUNCH_OUTCOME_COLD_START_FALLBACK. This never permits unauthorized or // superseded references to select a new launch. - bool allow_cold_start_fallback = 3; + bool restart_if_restore_fails = 3; } diff --git a/proto/openshell.proto b/proto/openshell.proto index 44d5ed81ee..1be9dc7da8 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -195,6 +195,26 @@ service OpenShell { }; } + // Freeze a ready sandbox and retain its memory state for a later resume. + // Requires a compute driver and isolation backend that support state + // retention. + rpc SuspendSandbox(SuspendSandboxRequest) returns (SandboxResponse) { + option (openshell.options.v1.authorization) = { + auth_mode: "bearer" + scope: "sandbox:write" + workspace_role: "user" + }; + } + + // Restore a suspended sandbox in a new runtime generation. + rpc ResumeSandbox(ResumeSandboxRequest) returns (SandboxResponse) { + option (openshell.options.v1.authorization) = { + auth_mode: "bearer" + scope: "sandbox:write" + workspace_role: "user" + }; + } + // Create a short-lived SSH session for a sandbox. rpc CreateSshSession(CreateSshSessionRequest) returns (CreateSshSessionResponse) { option (openshell.options.v1.authorization) = { @@ -1258,6 +1278,11 @@ enum SandboxPhase { SANDBOX_PHASE_COMPLETED = 9; reserved 10; reserved "SANDBOX_PHASE_RESTARTING"; + // The gateway requested suspension and the driver has not confirmed it. + SANDBOX_PHASE_SUSPENDING = 11; + // The workload is frozen and its memory state is retained by the isolation + // backend. ResumeSandbox restores it; StartSandbox discards it. + SANDBOX_PHASE_SUSPENDED = 12; } // Public platform event exposed on the sandbox watch stream. @@ -1490,6 +1515,23 @@ message StartSandboxRequest { string request_id = 3; } +// Suspend sandbox request. +message SuspendSandboxRequest { + // Workspace scope. Only a named workspace selection is accepted. + openshell.datamodel.v1.WorkspaceSelector workspace_scope = 2; + string name = 1; +} + +// Resume sandbox request. +message ResumeSandboxRequest { + // Workspace scope. Only a named workspace selection is accepted. + openshell.datamodel.v1.WorkspaceSelector workspace_scope = 2; + string name = 1; + // If true, the isolation backend may boot the workload cleanly when it + // cannot restore the retained memory state. If false, resume fails instead. + bool restart_if_restore_fails = 3; +} + // Sandbox response. message SandboxResponse { Sandbox sandbox = 1; diff --git a/proto/sandbox_protocol.proto b/proto/sandbox_protocol.proto index 40a35cf096..41a0da625f 100644 --- a/proto/sandbox_protocol.proto +++ b/proto/sandbox_protocol.proto @@ -121,8 +121,13 @@ message Attach { // unmediated egress path; supervisor-dependent operations fail closed. // A backend may terminate, pause, or keep a disconnected workload contained. message Confirm {} -// Start with the policy retained by Attach. Unsupported provider files must be -// rejected before workload execution. +// Begin workload execution with the policy admitted by Attach and Confirm. +// For a prepared restore, complete restoration here and return the restored +// main process rather than starting a duplicate. Restoration may immediately +// execute workload instructions, so all launch-time controls must be installed +// before invoking it. A deferred restore failure fails this call, without +// silently changing the launch path selected when the boundary was opened. +// Unsupported provider files must be rejected before workload execution. message StartAgent { string sandbox_id = 1; AgentSpec spec = 2; diff --git a/python/openshell/sandbox.py b/python/openshell/sandbox.py index e9c840e481..2eaf6a64fa 100644 --- a/python/openshell/sandbox.py +++ b/python/openshell/sandbox.py @@ -639,6 +639,20 @@ def start(self) -> SandboxRef: self.sandbox = self._client.start(self.sandbox.name, workspace=self._workspace) return self.sandbox + def suspend(self) -> SandboxRef: + self.sandbox = self._client.suspend( + self.sandbox.name, workspace=self._workspace + ) + return self.sandbox + + def resume(self, *, restart_if_restore_fails: bool = False) -> SandboxRef: + self.sandbox = self._client.resume( + self.sandbox.name, + workspace=self._workspace, + restart_if_restore_fails=restart_if_restore_fails, + ) + return self.sandbox + class SandboxClient: """gRPC client for sandbox CRUD and command execution.""" @@ -1106,6 +1120,39 @@ def start(self, name: str, *, workspace: str) -> SandboxRef: ) return _sandbox_ref(response.sandbox) + def suspend(self, name: str, *, workspace: str) -> SandboxRef: + """Suspend a ready sandbox, retaining its memory state. + + Requires a compute driver and isolation backend that support suspend + and resume. + """ + response = self._stub.SuspendSandbox( + openshell_pb2.SuspendSandboxRequest( + workspace_scope=_workspace_scope(workspace), + name=name, + ), + timeout=self._timeout, + ) + return _sandbox_ref(response.sandbox) + + def resume( + self, + name: str, + *, + workspace: str, + restart_if_restore_fails: bool = False, + ) -> SandboxRef: + """Resume a suspended sandbox in a new runtime generation.""" + response = self._stub.ResumeSandbox( + openshell_pb2.ResumeSandboxRequest( + workspace_scope=_workspace_scope(workspace), + name=name, + restart_if_restore_fails=restart_if_restore_fails, + ), + timeout=self._timeout, + ) + return _sandbox_ref(response.sandbox) + def wait_deleted( self, name: str, @@ -1152,6 +1199,17 @@ def wait_stopped( timeout_seconds=timeout_seconds, ) + def wait_suspended( + self, name: str, *, workspace: str, timeout_seconds: float = 300.0 + ) -> SandboxRef: + return self._wait_for_phase( + name, + workspace=workspace, + target_phase=openshell_pb2.SANDBOX_PHASE_SUSPENDED, + target_name="suspended", + timeout_seconds=timeout_seconds, + ) + def _wait_for_phase( self, name: str, @@ -1176,6 +1234,16 @@ def _wait_for_phase( and sandbox.status.phase == openshell_pb2.SANDBOX_PHASE_STOPPED ): raise SandboxError(f"sandbox {name} stopped before becoming ready") + if target_phase == openshell_pb2.SANDBOX_PHASE_READY and ( + sandbox.status.phase + in ( + openshell_pb2.SANDBOX_PHASE_SUSPENDING, + openshell_pb2.SANDBOX_PHASE_SUSPENDED, + ) + ): + raise SandboxError( + f"sandbox {name} is suspended; resume it before waiting for ready" + ) if sandbox.status.phase == openshell_pb2.SANDBOX_PHASE_ERROR: raise SandboxError(f"sandbox {name} entered error phase") time.sleep(1) diff --git a/python/openshell/sandbox_test.py b/python/openshell/sandbox_test.py index 019d3cc674..82de216263 100644 --- a/python/openshell/sandbox_test.py +++ b/python/openshell/sandbox_test.py @@ -1992,6 +1992,8 @@ def __init__( self.delete_request: openshell_pb2.DeleteSandboxRequest | None = None self.stop_request: openshell_pb2.StopSandboxRequest | None = None self.start_request: openshell_pb2.StartSandboxRequest | None = None + self.suspend_request: openshell_pb2.SuspendSandboxRequest | None = None + self.resume_request: openshell_pb2.ResumeSandboxRequest | None = None self.create_template_request: ( openshell_pb2.CreateSandboxTemplateRequest | None ) = None @@ -2063,6 +2065,38 @@ def StartSandbox( ) ) + def SuspendSandbox( + self, + request: openshell_pb2.SuspendSandboxRequest, + timeout: float | None = None, + ) -> Any: + self.suspend_request = request + _ = timeout + return SimpleNamespace( + sandbox=_make_sandbox_proto( + "sandbox-1", + _request_sandbox(request), + phase=openshell_pb2.SANDBOX_PHASE_SUSPENDING, + workspace=_request_workspace(request) or "default", + ) + ) + + def ResumeSandbox( + self, + request: openshell_pb2.ResumeSandboxRequest, + timeout: float | None = None, + ) -> Any: + self.resume_request = request + _ = timeout + return SimpleNamespace( + sandbox=_make_sandbox_proto( + "sandbox-1", + _request_sandbox(request), + phase=openshell_pb2.SANDBOX_PHASE_STARTING, + workspace=_request_workspace(request) or "default", + ) + ) + def CreateSandbox( self, request: openshell_pb2.CreateSandboxRequest, @@ -2513,6 +2547,51 @@ def test_stop_and_start_forward_workspace_and_return_phase() -> None: assert starting.phase == openshell_pb2.SANDBOX_PHASE_STARTING +def test_suspend_and_resume_forward_workspace_and_options() -> None: + stub = _FakeSandboxStub() + client = _client_with_fake_stub(stub) + + suspending = client.suspend("job-1", workspace="team-a") + assert stub.suspend_request is not None + assert _request_sandbox(stub.suspend_request) == "job-1" + assert _request_workspace(stub.suspend_request) == "team-a" + assert suspending.phase == openshell_pb2.SANDBOX_PHASE_SUSPENDING + + resumed = client.resume("job-1", workspace="team-a", restart_if_restore_fails=True) + assert stub.resume_request is not None + assert _request_sandbox(stub.resume_request) == "job-1" + assert _request_workspace(stub.resume_request) == "team-a" + assert stub.resume_request.restart_if_restore_fails + assert resumed.phase == openshell_pb2.SANDBOX_PHASE_STARTING + + client.resume("job-1", workspace="team-a") + assert not stub.resume_request.restart_if_restore_fails + + +def test_wait_ready_fails_fast_when_suspended() -> None: + class SuspendedStub(_FakeSandboxStub): + def GetSandbox( + self, + request: openshell_pb2.GetSandboxRequest, + timeout: float | None = None, + ) -> Any: + _ = timeout + return SimpleNamespace( + sandbox=_make_sandbox_proto( + "sandbox-1", + _request_sandbox(request), + phase=openshell_pb2.SANDBOX_PHASE_SUSPENDED, + workspace=_request_workspace(request) or "default", + ) + ) + + client = _client_with_fake_stub(SuspendedStub()) + with pytest.raises(SandboxError, match="is suspended"): + client.wait_ready("job-1", workspace="default", timeout_seconds=30) + suspended = client.wait_suspended("job-1", workspace="default", timeout_seconds=1) + assert suspended.phase == openshell_pb2.SANDBOX_PHASE_SUSPENDED + + @pytest.mark.parametrize( ("phase", "should_succeed"), [ diff --git a/sdk/go/openshell/v1/client.go b/sdk/go/openshell/v1/client.go index 4a6c2195c7..30e564f6c4 100644 --- a/sdk/go/openshell/v1/client.go +++ b/sdk/go/openshell/v1/client.go @@ -21,6 +21,7 @@ type ClientInterface interface { Sandboxes() SandboxInterface SandboxTemplates() SandboxTemplateInterface CreateSandboxFromTemplate(ctx context.Context, workspace, name, templateName string, spec *SandboxSpec, opts ...CreateOption) (*Sandbox, error) + SandboxSuspendResume() SandboxSuspendResumeInterface Providers() ProviderInterface Services() ServiceInterface Exec() ExecInterface @@ -53,6 +54,7 @@ type Client struct { sandboxes SandboxInterface templateCreate SandboxTemplateCreateInterface + suspendResume SandboxSuspendResumeInterface templates SandboxTemplateInterface providers ProviderInterface services ServiceInterface @@ -99,6 +101,7 @@ func NewClient(cfg Config) (*Client, error) { sandboxes := newSandboxClient(conn) c.sandboxes = sandboxes c.templateCreate = sandboxes + c.suspendResume = sandboxes c.templates = newSandboxTemplateClient(conn) c.providers = newProviderClient(conn) c.services = newServiceClient(conn) @@ -126,6 +129,9 @@ func (c *Client) CreateSandboxFromTemplate(ctx context.Context, workspace, name, return c.templateCreate.CreateFromTemplate(ctx, workspace, name, templateName, spec, opts...) } +// SandboxSuspendResume returns the sandbox suspend and resume sub-client. +func (c *Client) SandboxSuspendResume() SandboxSuspendResumeInterface { return c.suspendResume } + // Providers returns the provider sub-client. func (c *Client) Providers() ProviderInterface { return c.providers } diff --git a/sdk/go/openshell/v1/fake/fake.go b/sdk/go/openshell/v1/fake/fake.go index 92fa3e1260..73aa99ec68 100644 --- a/sdk/go/openshell/v1/fake/fake.go +++ b/sdk/go/openshell/v1/fake/fake.go @@ -25,6 +25,7 @@ type Client struct { sandboxes v1.SandboxInterface templateCreate v1.SandboxTemplateCreateInterface + suspendResume v1.SandboxSuspendResumeInterface templates v1.SandboxTemplateInterface providers v1.ProviderInterface services v1.ServiceInterface @@ -84,6 +85,7 @@ func NewClient(opts ...ClientOption) *Client { sandboxes := newFakeSandboxClient(fc.sandboxStore, fc.templateStore, fc.sandboxBroadcaster, fc.isClosed) fc.sandboxes = sandboxes fc.templateCreate = sandboxes + fc.suspendResume = sandboxes fc.templates = newFakeSandboxTemplateClient(fc.templateStore, fc.isClosed) fc.providers = newFakeProviderClient(fc.providerStore, fc.isClosed) fc.services = newFakeServiceClient(fc.isClosed) @@ -121,6 +123,11 @@ func (fc *Client) CreateSandboxFromTemplate(ctx context.Context, workspace, name return fc.templateCreate.CreateFromTemplate(ctx, workspace, name, templateName, spec, opts...) } +// SandboxSuspendResume returns the sandbox suspend and resume sub-client. +func (fc *Client) SandboxSuspendResume() v1.SandboxSuspendResumeInterface { + return fc.suspendResume +} + // Providers returns the provider sub-client. func (fc *Client) Providers() v1.ProviderInterface { return fc.providers } diff --git a/sdk/go/openshell/v1/fake/sandbox.go b/sdk/go/openshell/v1/fake/sandbox.go index cd460ca7be..221e1f7524 100644 --- a/sdk/go/openshell/v1/fake/sandbox.go +++ b/sdk/go/openshell/v1/fake/sandbox.go @@ -292,6 +292,7 @@ type fakeSandboxClient struct { var _ v1.SandboxInterface = (*fakeSandboxClient)(nil) var _ v1.SandboxTemplateCreateInterface = (*fakeSandboxClient)(nil) +var _ v1.SandboxSuspendResumeInterface = (*fakeSandboxClient)(nil) // newFakeSandboxClient creates a new fakeSandboxClient. func newFakeSandboxClient( @@ -539,6 +540,78 @@ func (c *fakeSandboxClient) Start(_ context.Context, workspace, name string) (*t return updated, nil } +// Suspend transitions a Ready sandbox to the Suspended phase. +func (c *fakeSandboxClient) Suspend(_ context.Context, workspace, name string) (*types.Sandbox, error) { + return c.transitionFrom(workspace, name, types.SandboxSuspended, types.SandboxReady, types.SandboxSuspending, types.SandboxSuspended) +} + +// Resume transitions a Suspended sandbox back to the Ready phase. +func (c *fakeSandboxClient) Resume(_ context.Context, workspace, name string, _ ...v1.ResumeOptions) (*types.Sandbox, error) { + return c.transitionFrom(workspace, name, types.SandboxReady, types.SandboxSuspended) +} + +// WaitSuspended returns the sandbox once it is in the Suspended phase. In the +// fake implementation Suspend completes synchronously, so any other phase is +// reported as an error. +func (c *fakeSandboxClient) WaitSuspended(ctx context.Context, workspace, name string, _ ...v1.WaitOptions) (*types.Sandbox, error) { + if c.closedFunc() { + return nil, &types.StatusError{Code: types.ErrorUnavailable, Message: "client is closed"} + } + if err := ctx.Err(); err != nil { + code := types.ErrorInternal + switch err { + case context.DeadlineExceeded: + code = types.ErrorDeadlineExceeded + case context.Canceled: + code = types.ErrorCancelled + } + return nil, &types.StatusError{Code: code, Message: err.Error(), Cause: err} + } + + sb, err := c.store.Get(workspace, name) + if err != nil { + return nil, err + } + if sb.Status.Phase != types.SandboxSuspended { + return nil, &types.StatusError{Code: types.ErrorInternal, Message: fmt.Sprintf("sandbox %q is %s, not Suspended", name, sb.Status.Phase)} + } + return sb, nil +} + +// transitionFrom moves a sandbox to target when its current phase is one of +// allowed, mirroring the gateway's FAILED_PRECONDITION for other phases. +func (c *fakeSandboxClient) transitionFrom(workspace, name string, target types.SandboxPhase, allowed ...types.SandboxPhase) (*types.Sandbox, error) { + if c.closedFunc() { + return nil, &types.StatusError{Code: types.ErrorUnavailable, Message: "client is closed"} + } + + sb, err := c.store.Get(workspace, name) + if err != nil { + return nil, err + } + if !slices.Contains(allowed, sb.Status.Phase) { + return nil, &types.StatusError{Code: types.ErrorConflict, Message: fmt.Sprintf("sandbox %q cannot move from %s to %s", name, sb.Status.Phase, target)} + } + if sb.Status.Phase == target { + return sb, nil + } + + sb.Status.Phase = target + sb.ResourceVersion++ + + updated, err := c.store.Update(workspace, sb) + if err != nil { + return nil, err + } + + c.broadcaster.Broadcast(types.Event[*types.Sandbox]{ + Type: types.EventModified, + Object: copySandbox(updated), + }, name) + + return updated, nil +} + // WaitStopped polls until a sandbox reaches the Stopped phase. func (c *fakeSandboxClient) WaitStopped(ctx context.Context, workspace, name string, _ ...v1.WaitOptions) (*types.Sandbox, error) { if c.closedFunc() { diff --git a/sdk/go/openshell/v1/fake/sandbox_test.go b/sdk/go/openshell/v1/fake/sandbox_test.go index 8c53e8bba5..3f4419ba2f 100644 --- a/sdk/go/openshell/v1/fake/sandbox_test.go +++ b/sdk/go/openshell/v1/fake/sandbox_test.go @@ -1007,3 +1007,33 @@ func TestSandbox_GetLogs_ClosedReturnsUnavailable(t *testing.T) { require.Error(t, err) assert.True(t, types.IsUnavailable(err)) } + +func TestSandbox_SuspendAndResume(t *testing.T) { + sc := newTestSandboxClient() + ctx := context.Background() + + _, err := sc.Create(ctx, "default", "frozen", &types.SandboxSpec{}) + require.NoError(t, err) + + _, err = sc.Suspend(ctx, "default", "frozen") + require.Error(t, err, "suspend requires Ready") + assert.True(t, types.IsConflict(err)) + + _, err = sc.WaitReady(ctx, "default", "frozen") + require.NoError(t, err) + + suspended, err := sc.Suspend(ctx, "default", "frozen") + require.NoError(t, err) + assert.Equal(t, types.SandboxSuspended, suspended.Status.Phase) + + waited, err := sc.WaitSuspended(ctx, "default", "frozen") + require.NoError(t, err) + assert.Equal(t, types.SandboxSuspended, waited.Status.Phase) + + resumed, err := sc.Resume(ctx, "default", "frozen", types.ResumeOptions{RestartIfRestoreFails: true}) + require.NoError(t, err) + assert.Equal(t, types.SandboxReady, resumed.Status.Phase) + + _, err = sc.Resume(ctx, "default", "frozen") + require.Error(t, err, "resume requires Suspended") +} diff --git a/sdk/go/openshell/v1/internal/converter/sandbox.go b/sdk/go/openshell/v1/internal/converter/sandbox.go index e75eb41de3..e679fba176 100644 --- a/sdk/go/openshell/v1/internal/converter/sandbox.go +++ b/sdk/go/openshell/v1/internal/converter/sandbox.go @@ -228,6 +228,10 @@ func SandboxPhaseFromProto(phase pb.SandboxPhase) types.SandboxPhase { return types.SandboxStarting case pb.SandboxPhase_SANDBOX_PHASE_COMPLETED: return types.SandboxCompleted + case pb.SandboxPhase_SANDBOX_PHASE_SUSPENDING: + return types.SandboxSuspending + case pb.SandboxPhase_SANDBOX_PHASE_SUSPENDED: + return types.SandboxSuspended default: return types.SandboxUnknown } @@ -254,6 +258,10 @@ func SandboxPhaseToProto(phase types.SandboxPhase) pb.SandboxPhase { return pb.SandboxPhase_SANDBOX_PHASE_STARTING case types.SandboxCompleted: return pb.SandboxPhase_SANDBOX_PHASE_COMPLETED + case types.SandboxSuspending: + return pb.SandboxPhase_SANDBOX_PHASE_SUSPENDING + case types.SandboxSuspended: + return pb.SandboxPhase_SANDBOX_PHASE_SUSPENDED default: return pb.SandboxPhase_SANDBOX_PHASE_UNKNOWN } diff --git a/sdk/go/openshell/v1/internal/converter/sandbox_test.go b/sdk/go/openshell/v1/internal/converter/sandbox_test.go index e3886a4b9e..756fd72338 100644 --- a/sdk/go/openshell/v1/internal/converter/sandbox_test.go +++ b/sdk/go/openshell/v1/internal/converter/sandbox_test.go @@ -382,6 +382,8 @@ func TestSandboxPhaseFromProto(t *testing.T) { {pb.SandboxPhase_SANDBOX_PHASE_STOPPED, v1.SandboxStopped}, {pb.SandboxPhase_SANDBOX_PHASE_COMPLETED, v1.SandboxCompleted}, {pb.SandboxPhase_SANDBOX_PHASE_STARTING, v1.SandboxStarting}, + {pb.SandboxPhase_SANDBOX_PHASE_SUSPENDING, v1.SandboxSuspending}, + {pb.SandboxPhase_SANDBOX_PHASE_SUSPENDED, v1.SandboxSuspended}, {pb.SandboxPhase_SANDBOX_PHASE_UNSPECIFIED, v1.SandboxUnknown}, {pb.SandboxPhase(999), v1.SandboxUnknown}, } @@ -405,6 +407,8 @@ func TestSandboxPhaseToProto(t *testing.T) { {v1.SandboxStopped, pb.SandboxPhase_SANDBOX_PHASE_STOPPED}, {v1.SandboxCompleted, pb.SandboxPhase_SANDBOX_PHASE_COMPLETED}, {v1.SandboxStarting, pb.SandboxPhase_SANDBOX_PHASE_STARTING}, + {v1.SandboxSuspending, pb.SandboxPhase_SANDBOX_PHASE_SUSPENDING}, + {v1.SandboxSuspended, pb.SandboxPhase_SANDBOX_PHASE_SUSPENDED}, {v1.SandboxPhase("bogus"), pb.SandboxPhase_SANDBOX_PHASE_UNKNOWN}, } diff --git a/sdk/go/openshell/v1/options.go b/sdk/go/openshell/v1/options.go index 9bbb9da865..5d603552ea 100644 --- a/sdk/go/openshell/v1/options.go +++ b/sdk/go/openshell/v1/options.go @@ -30,6 +30,9 @@ type WatchOptions = types.WatchOptions // WaitOptions configures wait behavior. Use context for timeout control. type WaitOptions = types.WaitOptions +// ResumeOptions configures how a suspended sandbox resumes. +type ResumeOptions = types.ResumeOptions + // ExecOptions configures command execution. type ExecOptions = types.ExecOptions diff --git a/sdk/go/openshell/v1/sandbox.go b/sdk/go/openshell/v1/sandbox.go index cd811ffdc9..1e6c24cc9c 100644 --- a/sdk/go/openshell/v1/sandbox.go +++ b/sdk/go/openshell/v1/sandbox.go @@ -110,3 +110,15 @@ type SandboxInterface interface { type SandboxTemplateCreateInterface interface { CreateFromTemplate(ctx context.Context, workspace, name, templateName string, spec *SandboxSpec, opts ...CreateOption) (*Sandbox, error) } + +// SandboxSuspendResumeInterface defines sandbox suspend and resume without +// widening SandboxInterface. Suspend and resume require a compute driver and +// isolation backend that retain workload memory state. +type SandboxSuspendResumeInterface interface { + // Suspend freezes a Ready sandbox and retains its memory state. + Suspend(ctx context.Context, workspace, name string) (*Sandbox, error) + // Resume restores a Suspended sandbox in a new runtime generation. + Resume(ctx context.Context, workspace, name string, opts ...ResumeOptions) (*Sandbox, error) + // WaitSuspended polls until the sandbox reaches the Suspended phase. + WaitSuspended(ctx context.Context, workspace, name string, opts ...WaitOptions) (*Sandbox, error) +} diff --git a/sdk/go/openshell/v1/sandbox_client.go b/sdk/go/openshell/v1/sandbox_client.go index d18e671127..d3b36cbdd8 100644 --- a/sdk/go/openshell/v1/sandbox_client.go +++ b/sdk/go/openshell/v1/sandbox_client.go @@ -23,6 +23,7 @@ type sandboxClient struct { var _ SandboxInterface = (*sandboxClient)(nil) var _ SandboxTemplateCreateInterface = (*sandboxClient)(nil) +var _ SandboxSuspendResumeInterface = (*sandboxClient)(nil) func newSandboxClient(conn grpc.ClientConnInterface) *sandboxClient { return &sandboxClient{client: pb.NewOpenShellClient(conn)} @@ -202,6 +203,33 @@ func (s *sandboxClient) Start(ctx context.Context, workspace, name string) (*San return converter.SandboxFromProto(resp.GetSandbox()), nil } +func (s *sandboxClient) Suspend(ctx context.Context, workspace, name string) (*Sandbox, error) { + resp, err := s.client.SuspendSandbox(ctx, &pb.SuspendSandboxRequest{ + Name: name, + WorkspaceScope: namedWorkspaceScope(workspace), + }) + if err != nil { + return nil, converter.FromGRPCError(err) + } + return converter.SandboxFromProto(resp.GetSandbox()), nil +} + +func (s *sandboxClient) Resume(ctx context.Context, workspace, name string, opts ...ResumeOptions) (*Sandbox, error) { + var options ResumeOptions + if len(opts) > 0 { + options = opts[0] + } + resp, err := s.client.ResumeSandbox(ctx, &pb.ResumeSandboxRequest{ + Name: name, + WorkspaceScope: namedWorkspaceScope(workspace), + RestartIfRestoreFails: options.RestartIfRestoreFails, + }) + if err != nil { + return nil, converter.FromGRPCError(err) + } + return converter.SandboxFromProto(resp.GetSandbox()), nil +} + func (s *sandboxClient) AttachProvider(ctx context.Context, workspace, sandboxName, providerName string, expectedResourceVersion uint64) (*AttachProviderResult, error) { resp, err := s.client.AttachSandboxProvider(ctx, &pb.AttachSandboxProviderRequest{ Provider: providerName, @@ -277,6 +305,10 @@ func (s *sandboxClient) WaitStopped(ctx context.Context, workspace, name string, return s.waitForPhase(ctx, workspace, name, SandboxStopped, opts...) } +func (s *sandboxClient) WaitSuspended(ctx context.Context, workspace, name string, opts ...WaitOptions) (*Sandbox, error) { + return s.waitForPhase(ctx, workspace, name, SandboxSuspended, opts...) +} + func (s *sandboxClient) waitForPhase(ctx context.Context, workspace, name string, target SandboxPhase, opts ...WaitOptions) (*Sandbox, error) { interval := defaultPollInterval if len(opts) > 0 && opts[0].PollInterval > 0 { @@ -327,6 +359,11 @@ func checkTerminalPhase(sb *Sandbox, name string, target SandboxPhase) (*Sandbox return nil, &StatusError{Code: ErrorInternal, Message: fmt.Sprintf("sandbox %q is in error state", name)} case SandboxDeleting: return nil, &StatusError{Code: ErrorInternal, Message: fmt.Sprintf("sandbox %q is being deleted", name)} + case SandboxSuspending, SandboxSuspended: + if target == SandboxSuspended { + return nil, nil + } + return nil, &StatusError{Code: ErrorInternal, Message: fmt.Sprintf("sandbox %q is suspended; resume it before waiting for %s", name, target)} default: return nil, nil } diff --git a/sdk/go/openshell/v1/sandbox_client_test.go b/sdk/go/openshell/v1/sandbox_client_test.go index ed6103e0d9..8e2e83b50d 100644 --- a/sdk/go/openshell/v1/sandbox_client_test.go +++ b/sdk/go/openshell/v1/sandbox_client_test.go @@ -42,6 +42,7 @@ type mockSandboxServer struct { detachErr error listProvErr error createRequest *pb.CreateSandboxRequest + resumeRequest *pb.ResumeSandboxRequest watchEvents []*pb.SandboxStreamEvent watchErr error watchPostEventsErr error @@ -181,6 +182,31 @@ func (s *mockSandboxServer) StartSandbox(_ context.Context, req *pb.StartSandbox return &pb.SandboxResponse{Sandbox: proto.Clone(sb).(*pb.Sandbox)}, nil } +func (s *mockSandboxServer) SuspendSandbox(_ context.Context, req *pb.SuspendSandboxRequest) (*pb.SandboxResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + name := req.GetName() + sb, ok := s.sandboxes[name] + if !ok { + return nil, status.Errorf(codes.NotFound, "sandbox %q not found", name) + } + sb.Status.Phase = pb.SandboxPhase_SANDBOX_PHASE_SUSPENDED + return &pb.SandboxResponse{Sandbox: proto.Clone(sb).(*pb.Sandbox)}, nil +} + +func (s *mockSandboxServer) ResumeSandbox(_ context.Context, req *pb.ResumeSandboxRequest) (*pb.SandboxResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + s.resumeRequest = req + name := req.GetName() + sb, ok := s.sandboxes[name] + if !ok { + return nil, status.Errorf(codes.NotFound, "sandbox %q not found", name) + } + sb.Status.Phase = pb.SandboxPhase_SANDBOX_PHASE_STARTING + return &pb.SandboxResponse{Sandbox: proto.Clone(sb).(*pb.Sandbox)}, nil +} + func (s *mockSandboxServer) AttachSandboxProvider(_ context.Context, req *pb.AttachSandboxProviderRequest) (*pb.AttachSandboxProviderResponse, error) { s.mu.Lock() defer s.mu.Unlock() @@ -667,6 +693,36 @@ func TestSandboxStopAndStart(t *testing.T) { assert.Equal(t, SandboxStarting, starting.Status.Phase) } +func TestSandboxSuspendAndResume(t *testing.T) { + mock := newMockSandboxServer() + mock.sandboxes["frozen"] = &pb.Sandbox{ + Metadata: &dm.ObjectMeta{Name: "frozen", Workspace: "team-a"}, + Status: &pb.SandboxStatus{Phase: pb.SandboxPhase_SANDBOX_PHASE_READY}, + } + client, cleanup := setupSandboxTest(t, mock) + defer cleanup() + + suspended, err := client.Suspend(context.Background(), "team-a", "frozen") + require.NoError(t, err) + assert.Equal(t, SandboxSuspended, suspended.Status.Phase) + + waited, err := client.WaitSuspended(context.Background(), "team-a", "frozen") + require.NoError(t, err) + assert.Equal(t, SandboxSuspended, waited.Status.Phase) + + _, err = client.WaitReady(context.Background(), "team-a", "frozen") + require.Error(t, err) + assert.Contains(t, err.Error(), "suspended") + + resumed, err := client.Resume(context.Background(), "team-a", "frozen", ResumeOptions{RestartIfRestoreFails: true}) + require.NoError(t, err) + assert.Equal(t, SandboxStarting, resumed.Status.Phase) + mock.mu.Lock() + assert.True(t, mock.resumeRequest.GetRestartIfRestoreFails()) + assert.Equal(t, "frozen", mock.resumeRequest.GetName()) + mock.mu.Unlock() +} + // --- T030: AttachProvider, DetachProvider, ListProviders tests --- func TestSandboxAttachProvider(t *testing.T) { diff --git a/sdk/go/openshell/v1/types.go b/sdk/go/openshell/v1/types.go index e565d966cb..a09acd28fa 100644 --- a/sdk/go/openshell/v1/types.go +++ b/sdk/go/openshell/v1/types.go @@ -21,6 +21,8 @@ const ( SandboxStopped = types.SandboxStopped SandboxStarting = types.SandboxStarting SandboxCompleted = types.SandboxCompleted + SandboxSuspending = types.SandboxSuspending + SandboxSuspended = types.SandboxSuspended ) // SandboxRestartPolicy controls replacement after the canonical main process exits. diff --git a/sdk/go/openshell/v1/types/options.go b/sdk/go/openshell/v1/types/options.go index 9277efa3e8..eccf21e979 100644 --- a/sdk/go/openshell/v1/types/options.go +++ b/sdk/go/openshell/v1/types/options.go @@ -83,6 +83,14 @@ type WatchOptions struct { StopOnTerminal bool } +// ResumeOptions configures how a suspended sandbox resumes. +type ResumeOptions struct { + // RestartIfRestoreFails lets the isolation backend boot the workload + // cleanly when it cannot restore the retained memory state. When false, + // resume fails instead. + RestartIfRestoreFails bool +} + // WaitOptions configures wait behavior. Use context for timeout control. type WaitOptions struct { PollInterval time.Duration diff --git a/sdk/go/openshell/v1/types/types.go b/sdk/go/openshell/v1/types/types.go index 99d8e24bf9..ce3cccb195 100644 --- a/sdk/go/openshell/v1/types/types.go +++ b/sdk/go/openshell/v1/types/types.go @@ -19,6 +19,8 @@ const ( SandboxStopped SandboxPhase = "Stopped" SandboxStarting SandboxPhase = "Starting" SandboxCompleted SandboxPhase = "Completed" + SandboxSuspending SandboxPhase = "Suspending" + SandboxSuspended SandboxPhase = "Suspended" ) // SandboxRestartPolicy controls replacement after the canonical main process exits. diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index f180617bf6..d60dd50a68 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -103,21 +103,28 @@ const ( SandboxPhase_SANDBOX_PHASE_STARTING SandboxPhase = 8 // The canonical main process exited successfully and its result is final. SandboxPhase_SANDBOX_PHASE_COMPLETED SandboxPhase = 9 + // The gateway requested suspension and the driver has not confirmed it. + SandboxPhase_SANDBOX_PHASE_SUSPENDING SandboxPhase = 11 + // The workload is frozen and its memory state is retained by the isolation + // backend. ResumeSandbox restores it; StartSandbox discards it. + SandboxPhase_SANDBOX_PHASE_SUSPENDED SandboxPhase = 12 ) // Enum value maps for SandboxPhase. var ( SandboxPhase_name = map[int32]string{ - 0: "SANDBOX_PHASE_UNSPECIFIED", - 1: "SANDBOX_PHASE_PROVISIONING", - 2: "SANDBOX_PHASE_READY", - 3: "SANDBOX_PHASE_ERROR", - 4: "SANDBOX_PHASE_DELETING", - 5: "SANDBOX_PHASE_UNKNOWN", - 6: "SANDBOX_PHASE_STOPPING", - 7: "SANDBOX_PHASE_STOPPED", - 8: "SANDBOX_PHASE_STARTING", - 9: "SANDBOX_PHASE_COMPLETED", + 0: "SANDBOX_PHASE_UNSPECIFIED", + 1: "SANDBOX_PHASE_PROVISIONING", + 2: "SANDBOX_PHASE_READY", + 3: "SANDBOX_PHASE_ERROR", + 4: "SANDBOX_PHASE_DELETING", + 5: "SANDBOX_PHASE_UNKNOWN", + 6: "SANDBOX_PHASE_STOPPING", + 7: "SANDBOX_PHASE_STOPPED", + 8: "SANDBOX_PHASE_STARTING", + 9: "SANDBOX_PHASE_COMPLETED", + 11: "SANDBOX_PHASE_SUSPENDING", + 12: "SANDBOX_PHASE_SUSPENDED", } SandboxPhase_value = map[string]int32{ "SANDBOX_PHASE_UNSPECIFIED": 0, @@ -130,6 +137,8 @@ var ( "SANDBOX_PHASE_STOPPED": 7, "SANDBOX_PHASE_STARTING": 8, "SANDBOX_PHASE_COMPLETED": 9, + "SANDBOX_PHASE_SUSPENDING": 11, + "SANDBOX_PHASE_SUSPENDED": 12, } ) @@ -4806,6 +4815,124 @@ func (x *StartSandboxRequest) GetRequestId() string { return "" } +// Suspend sandbox request. +type SuspendSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Workspace scope. Only a named workspace selection is accepted. + WorkspaceScope *datamodelv1.WorkspaceSelector `protobuf:"bytes,2,opt,name=workspace_scope,json=workspaceScope,proto3" json:"workspace_scope,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SuspendSandboxRequest) Reset() { + *x = SuspendSandboxRequest{} + mi := &file_openshell_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SuspendSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SuspendSandboxRequest) ProtoMessage() {} + +func (x *SuspendSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[50] + 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 SuspendSandboxRequest.ProtoReflect.Descriptor instead. +func (*SuspendSandboxRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{50} +} + +func (x *SuspendSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { + if x != nil { + return x.WorkspaceScope + } + return nil +} + +func (x *SuspendSandboxRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// Resume sandbox request. +type ResumeSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Workspace scope. Only a named workspace selection is accepted. + WorkspaceScope *datamodelv1.WorkspaceSelector `protobuf:"bytes,2,opt,name=workspace_scope,json=workspaceScope,proto3" json:"workspace_scope,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // If true, the isolation backend may boot the workload cleanly when it + // cannot restore the retained memory state. If false, resume fails instead. + RestartIfRestoreFails bool `protobuf:"varint,3,opt,name=restart_if_restore_fails,json=restartIfRestoreFails,proto3" json:"restart_if_restore_fails,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResumeSandboxRequest) Reset() { + *x = ResumeSandboxRequest{} + mi := &file_openshell_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResumeSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResumeSandboxRequest) ProtoMessage() {} + +func (x *ResumeSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[51] + 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 ResumeSandboxRequest.ProtoReflect.Descriptor instead. +func (*ResumeSandboxRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{51} +} + +func (x *ResumeSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { + if x != nil { + return x.WorkspaceScope + } + return nil +} + +func (x *ResumeSandboxRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ResumeSandboxRequest) GetRestartIfRestoreFails() bool { + if x != nil { + return x.RestartIfRestoreFails + } + return false +} + // Sandbox response. type SandboxResponse struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -4819,7 +4946,7 @@ type SandboxResponse struct { func (x *SandboxResponse) Reset() { *x = SandboxResponse{} - mi := &file_openshell_proto_msgTypes[50] + mi := &file_openshell_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4831,7 +4958,7 @@ func (x *SandboxResponse) String() string { func (*SandboxResponse) ProtoMessage() {} func (x *SandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[50] + mi := &file_openshell_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4844,7 +4971,7 @@ func (x *SandboxResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxResponse.ProtoReflect.Descriptor instead. func (*SandboxResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{50} + return file_openshell_proto_rawDescGZIP(), []int{52} } func (x *SandboxResponse) GetSandbox() *Sandbox { @@ -4873,7 +5000,7 @@ type ListSandboxesResponse struct { func (x *ListSandboxesResponse) Reset() { *x = ListSandboxesResponse{} - mi := &file_openshell_proto_msgTypes[51] + mi := &file_openshell_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4885,7 +5012,7 @@ func (x *ListSandboxesResponse) String() string { func (*ListSandboxesResponse) ProtoMessage() {} func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[51] + mi := &file_openshell_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4898,7 +5025,7 @@ func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{51} + return file_openshell_proto_rawDescGZIP(), []int{53} } func (x *ListSandboxesResponse) GetSandboxes() []*Sandbox { @@ -4927,7 +5054,7 @@ type ListSandboxProvidersResponse struct { func (x *ListSandboxProvidersResponse) Reset() { *x = ListSandboxProvidersResponse{} - mi := &file_openshell_proto_msgTypes[52] + mi := &file_openshell_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4939,7 +5066,7 @@ func (x *ListSandboxProvidersResponse) String() string { func (*ListSandboxProvidersResponse) ProtoMessage() {} func (x *ListSandboxProvidersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[52] + mi := &file_openshell_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4952,7 +5079,7 @@ func (x *ListSandboxProvidersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxProvidersResponse.ProtoReflect.Descriptor instead. func (*ListSandboxProvidersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{52} + return file_openshell_proto_rawDescGZIP(), []int{54} } func (x *ListSandboxProvidersResponse) GetProviders() []*datamodelv1.Provider { @@ -4983,7 +5110,7 @@ type AttachSandboxProviderResponse struct { func (x *AttachSandboxProviderResponse) Reset() { *x = AttachSandboxProviderResponse{} - mi := &file_openshell_proto_msgTypes[53] + mi := &file_openshell_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4995,7 +5122,7 @@ func (x *AttachSandboxProviderResponse) String() string { func (*AttachSandboxProviderResponse) ProtoMessage() {} func (x *AttachSandboxProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[53] + mi := &file_openshell_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5008,7 +5135,7 @@ func (x *AttachSandboxProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachSandboxProviderResponse.ProtoReflect.Descriptor instead. func (*AttachSandboxProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{53} + return file_openshell_proto_rawDescGZIP(), []int{55} } func (x *AttachSandboxProviderResponse) GetSandbox() *Sandbox { @@ -5046,7 +5173,7 @@ type DetachSandboxProviderResponse struct { func (x *DetachSandboxProviderResponse) Reset() { *x = DetachSandboxProviderResponse{} - mi := &file_openshell_proto_msgTypes[54] + mi := &file_openshell_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5058,7 +5185,7 @@ func (x *DetachSandboxProviderResponse) String() string { func (*DetachSandboxProviderResponse) ProtoMessage() {} func (x *DetachSandboxProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[54] + mi := &file_openshell_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5071,7 +5198,7 @@ func (x *DetachSandboxProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachSandboxProviderResponse.ProtoReflect.Descriptor instead. func (*DetachSandboxProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{54} + return file_openshell_proto_rawDescGZIP(), []int{56} } func (x *DetachSandboxProviderResponse) GetSandbox() *Sandbox { @@ -5113,7 +5240,7 @@ type ProviderDesiredIdentity struct { func (x *ProviderDesiredIdentity) Reset() { *x = ProviderDesiredIdentity{} - mi := &file_openshell_proto_msgTypes[55] + mi := &file_openshell_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5125,7 +5252,7 @@ func (x *ProviderDesiredIdentity) String() string { func (*ProviderDesiredIdentity) ProtoMessage() {} func (x *ProviderDesiredIdentity) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[55] + mi := &file_openshell_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5138,7 +5265,7 @@ func (x *ProviderDesiredIdentity) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderDesiredIdentity.ProtoReflect.Descriptor instead. func (*ProviderDesiredIdentity) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{55} + return file_openshell_proto_rawDescGZIP(), []int{57} } func (x *ProviderDesiredIdentity) GetSandboxId() string { @@ -5213,7 +5340,7 @@ type ConfigSnapshotRevision struct { func (x *ConfigSnapshotRevision) Reset() { *x = ConfigSnapshotRevision{} - mi := &file_openshell_proto_msgTypes[56] + mi := &file_openshell_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5225,7 +5352,7 @@ func (x *ConfigSnapshotRevision) String() string { func (*ConfigSnapshotRevision) ProtoMessage() {} func (x *ConfigSnapshotRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[56] + mi := &file_openshell_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5238,7 +5365,7 @@ func (x *ConfigSnapshotRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigSnapshotRevision.ProtoReflect.Descriptor instead. func (*ConfigSnapshotRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{56} + return file_openshell_proto_rawDescGZIP(), []int{58} } func (x *ConfigSnapshotRevision) GetComponent() isConfigSnapshotRevision_Component { @@ -5315,7 +5442,7 @@ type SandboxConfigRevision struct { func (x *SandboxConfigRevision) Reset() { *x = SandboxConfigRevision{} - mi := &file_openshell_proto_msgTypes[57] + mi := &file_openshell_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5327,7 +5454,7 @@ func (x *SandboxConfigRevision) String() string { func (*SandboxConfigRevision) ProtoMessage() {} func (x *SandboxConfigRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[57] + mi := &file_openshell_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5340,7 +5467,7 @@ func (x *SandboxConfigRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfigRevision.ProtoReflect.Descriptor instead. func (*SandboxConfigRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{57} + return file_openshell_proto_rawDescGZIP(), []int{59} } func (x *SandboxConfigRevision) GetConfigRevision() uint64 { @@ -5399,7 +5526,7 @@ type ConfigUpdateOperation struct { func (x *ConfigUpdateOperation) Reset() { *x = ConfigUpdateOperation{} - mi := &file_openshell_proto_msgTypes[58] + mi := &file_openshell_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5411,7 +5538,7 @@ func (x *ConfigUpdateOperation) String() string { func (*ConfigUpdateOperation) ProtoMessage() {} func (x *ConfigUpdateOperation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[58] + mi := &file_openshell_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5424,7 +5551,7 @@ func (x *ConfigUpdateOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdateOperation.ProtoReflect.Descriptor instead. func (*ConfigUpdateOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{58} + return file_openshell_proto_rawDescGZIP(), []int{60} } func (x *ConfigUpdateOperation) GetOperationId() string { @@ -5514,7 +5641,7 @@ type ProviderMutationReceipt struct { func (x *ProviderMutationReceipt) Reset() { *x = ProviderMutationReceipt{} - mi := &file_openshell_proto_msgTypes[59] + mi := &file_openshell_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5526,7 +5653,7 @@ func (x *ProviderMutationReceipt) String() string { func (*ProviderMutationReceipt) ProtoMessage() {} func (x *ProviderMutationReceipt) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[59] + mi := &file_openshell_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5539,7 +5666,7 @@ func (x *ProviderMutationReceipt) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderMutationReceipt.ProtoReflect.Descriptor instead. func (*ProviderMutationReceipt) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{59} + return file_openshell_proto_rawDescGZIP(), []int{61} } func (x *ProviderMutationReceipt) GetReceiptId() string { @@ -5615,7 +5742,7 @@ type ProviderReadinessObservation struct { func (x *ProviderReadinessObservation) Reset() { *x = ProviderReadinessObservation{} - mi := &file_openshell_proto_msgTypes[60] + mi := &file_openshell_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5627,7 +5754,7 @@ func (x *ProviderReadinessObservation) String() string { func (*ProviderReadinessObservation) ProtoMessage() {} func (x *ProviderReadinessObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[60] + mi := &file_openshell_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5640,7 +5767,7 @@ func (x *ProviderReadinessObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderReadinessObservation.ProtoReflect.Descriptor instead. func (*ProviderReadinessObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{60} + return file_openshell_proto_rawDescGZIP(), []int{62} } func (x *ProviderReadinessObservation) GetSessionId() string { @@ -5739,7 +5866,7 @@ type ProviderReadinessStatus struct { func (x *ProviderReadinessStatus) Reset() { *x = ProviderReadinessStatus{} - mi := &file_openshell_proto_msgTypes[61] + mi := &file_openshell_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5751,7 +5878,7 @@ func (x *ProviderReadinessStatus) String() string { func (*ProviderReadinessStatus) ProtoMessage() {} func (x *ProviderReadinessStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[61] + mi := &file_openshell_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5764,7 +5891,7 @@ func (x *ProviderReadinessStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderReadinessStatus.ProtoReflect.Descriptor instead. func (*ProviderReadinessStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{61} + return file_openshell_proto_rawDescGZIP(), []int{63} } func (x *ProviderReadinessStatus) GetReceipt() *ProviderMutationReceipt { @@ -5838,7 +5965,7 @@ type GetSandboxProviderStatusRequest struct { func (x *GetSandboxProviderStatusRequest) Reset() { *x = GetSandboxProviderStatusRequest{} - mi := &file_openshell_proto_msgTypes[62] + mi := &file_openshell_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5850,7 +5977,7 @@ func (x *GetSandboxProviderStatusRequest) String() string { func (*GetSandboxProviderStatusRequest) ProtoMessage() {} func (x *GetSandboxProviderStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[62] + mi := &file_openshell_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5863,7 +5990,7 @@ func (x *GetSandboxProviderStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxProviderStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxProviderStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{62} + return file_openshell_proto_rawDescGZIP(), []int{64} } func (x *GetSandboxProviderStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -5903,7 +6030,7 @@ type GetSandboxProviderStatusResponse struct { func (x *GetSandboxProviderStatusResponse) Reset() { *x = GetSandboxProviderStatusResponse{} - mi := &file_openshell_proto_msgTypes[63] + mi := &file_openshell_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5915,7 +6042,7 @@ func (x *GetSandboxProviderStatusResponse) String() string { func (*GetSandboxProviderStatusResponse) ProtoMessage() {} func (x *GetSandboxProviderStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[63] + mi := &file_openshell_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5928,7 +6055,7 @@ func (x *GetSandboxProviderStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxProviderStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxProviderStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{63} + return file_openshell_proto_rawDescGZIP(), []int{65} } func (x *GetSandboxProviderStatusResponse) GetStatus() *ProviderReadinessStatus { @@ -5950,7 +6077,7 @@ type ReportProviderReadinessRequest struct { func (x *ReportProviderReadinessRequest) Reset() { *x = ReportProviderReadinessRequest{} - mi := &file_openshell_proto_msgTypes[64] + mi := &file_openshell_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5962,7 +6089,7 @@ func (x *ReportProviderReadinessRequest) String() string { func (*ReportProviderReadinessRequest) ProtoMessage() {} func (x *ReportProviderReadinessRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[64] + mi := &file_openshell_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5975,7 +6102,7 @@ func (x *ReportProviderReadinessRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportProviderReadinessRequest.ProtoReflect.Descriptor instead. func (*ReportProviderReadinessRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{64} + return file_openshell_proto_rawDescGZIP(), []int{66} } func (x *ReportProviderReadinessRequest) GetSandboxId() string { @@ -6005,7 +6132,7 @@ type ReportProviderReadinessResponse struct { func (x *ReportProviderReadinessResponse) Reset() { *x = ReportProviderReadinessResponse{} - mi := &file_openshell_proto_msgTypes[65] + mi := &file_openshell_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6017,7 +6144,7 @@ func (x *ReportProviderReadinessResponse) String() string { func (*ReportProviderReadinessResponse) ProtoMessage() {} func (x *ReportProviderReadinessResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[65] + mi := &file_openshell_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6030,7 +6157,7 @@ func (x *ReportProviderReadinessResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportProviderReadinessResponse.ProtoReflect.Descriptor instead. func (*ReportProviderReadinessResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{65} + return file_openshell_proto_rawDescGZIP(), []int{67} } func (x *ReportProviderReadinessResponse) GetAcceptedSequence() uint64 { @@ -6067,7 +6194,7 @@ type DeleteSandboxResponse struct { func (x *DeleteSandboxResponse) Reset() { *x = DeleteSandboxResponse{} - mi := &file_openshell_proto_msgTypes[66] + mi := &file_openshell_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6079,7 +6206,7 @@ func (x *DeleteSandboxResponse) String() string { func (*DeleteSandboxResponse) ProtoMessage() {} func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[66] + mi := &file_openshell_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6092,7 +6219,7 @@ func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxResponse.ProtoReflect.Descriptor instead. func (*DeleteSandboxResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{66} + return file_openshell_proto_rawDescGZIP(), []int{68} } func (x *DeleteSandboxResponse) GetOutcome() DeletionOutcome { @@ -6121,7 +6248,7 @@ type CreateSshSessionRequest struct { func (x *CreateSshSessionRequest) Reset() { *x = CreateSshSessionRequest{} - mi := &file_openshell_proto_msgTypes[67] + mi := &file_openshell_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6133,7 +6260,7 @@ func (x *CreateSshSessionRequest) String() string { func (*CreateSshSessionRequest) ProtoMessage() {} func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[67] + mi := &file_openshell_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6146,7 +6273,7 @@ func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSshSessionRequest.ProtoReflect.Descriptor instead. func (*CreateSshSessionRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{67} + return file_openshell_proto_rawDescGZIP(), []int{69} } func (x *CreateSshSessionRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6197,7 +6324,7 @@ type CreateSshSessionResponse struct { func (x *CreateSshSessionResponse) Reset() { *x = CreateSshSessionResponse{} - mi := &file_openshell_proto_msgTypes[68] + mi := &file_openshell_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6209,7 +6336,7 @@ func (x *CreateSshSessionResponse) String() string { func (*CreateSshSessionResponse) ProtoMessage() {} func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[68] + mi := &file_openshell_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6222,7 +6349,7 @@ func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSshSessionResponse.ProtoReflect.Descriptor instead. func (*CreateSshSessionResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{68} + return file_openshell_proto_rawDescGZIP(), []int{70} } func (x *CreateSshSessionResponse) GetSandboxId() string { @@ -6297,7 +6424,7 @@ type ExposeServiceRequest struct { func (x *ExposeServiceRequest) Reset() { *x = ExposeServiceRequest{} - mi := &file_openshell_proto_msgTypes[69] + mi := &file_openshell_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6309,7 +6436,7 @@ func (x *ExposeServiceRequest) String() string { func (*ExposeServiceRequest) ProtoMessage() {} func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[69] + mi := &file_openshell_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6322,7 +6449,7 @@ func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExposeServiceRequest.ProtoReflect.Descriptor instead. func (*ExposeServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{69} + return file_openshell_proto_rawDescGZIP(), []int{71} } func (x *ExposeServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6388,7 +6515,7 @@ type GetServiceRequest struct { func (x *GetServiceRequest) Reset() { *x = GetServiceRequest{} - mi := &file_openshell_proto_msgTypes[70] + mi := &file_openshell_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6400,7 +6527,7 @@ func (x *GetServiceRequest) String() string { func (*GetServiceRequest) ProtoMessage() {} func (x *GetServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[70] + mi := &file_openshell_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6413,7 +6540,7 @@ func (x *GetServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetServiceRequest.ProtoReflect.Descriptor instead. func (*GetServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{70} + return file_openshell_proto_rawDescGZIP(), []int{72} } func (x *GetServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6456,7 +6583,7 @@ type ListServicesRequest struct { func (x *ListServicesRequest) Reset() { *x = ListServicesRequest{} - mi := &file_openshell_proto_msgTypes[71] + mi := &file_openshell_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6468,7 +6595,7 @@ func (x *ListServicesRequest) String() string { func (*ListServicesRequest) ProtoMessage() {} func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[71] + mi := &file_openshell_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6481,7 +6608,7 @@ func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesRequest.ProtoReflect.Descriptor instead. func (*ListServicesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{71} + return file_openshell_proto_rawDescGZIP(), []int{73} } func (x *ListServicesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6524,7 +6651,7 @@ type ListServicesResponse struct { func (x *ListServicesResponse) Reset() { *x = ListServicesResponse{} - mi := &file_openshell_proto_msgTypes[72] + mi := &file_openshell_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6536,7 +6663,7 @@ func (x *ListServicesResponse) String() string { func (*ListServicesResponse) ProtoMessage() {} func (x *ListServicesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[72] + mi := &file_openshell_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6549,7 +6676,7 @@ func (x *ListServicesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesResponse.ProtoReflect.Descriptor instead. func (*ListServicesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{72} + return file_openshell_proto_rawDescGZIP(), []int{74} } func (x *ListServicesResponse) GetServices() []*ServiceEndpointResponse { @@ -6584,7 +6711,7 @@ type DeleteServiceRequest struct { func (x *DeleteServiceRequest) Reset() { *x = DeleteServiceRequest{} - mi := &file_openshell_proto_msgTypes[73] + mi := &file_openshell_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6596,7 +6723,7 @@ func (x *DeleteServiceRequest) String() string { func (*DeleteServiceRequest) ProtoMessage() {} func (x *DeleteServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[73] + mi := &file_openshell_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6609,7 +6736,7 @@ func (x *DeleteServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteServiceRequest.ProtoReflect.Descriptor instead. func (*DeleteServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{73} + return file_openshell_proto_rawDescGZIP(), []int{75} } func (x *DeleteServiceRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -6657,7 +6784,7 @@ type DeleteServiceResponse struct { func (x *DeleteServiceResponse) Reset() { *x = DeleteServiceResponse{} - mi := &file_openshell_proto_msgTypes[74] + mi := &file_openshell_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6669,7 +6796,7 @@ func (x *DeleteServiceResponse) String() string { func (*DeleteServiceResponse) ProtoMessage() {} func (x *DeleteServiceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[74] + mi := &file_openshell_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6682,7 +6809,7 @@ func (x *DeleteServiceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteServiceResponse.ProtoReflect.Descriptor instead. func (*DeleteServiceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{74} + return file_openshell_proto_rawDescGZIP(), []int{76} } func (x *DeleteServiceResponse) GetOutcome() DeletionOutcome { @@ -6715,7 +6842,7 @@ type ServiceEndpoint struct { func (x *ServiceEndpoint) Reset() { *x = ServiceEndpoint{} - mi := &file_openshell_proto_msgTypes[75] + mi := &file_openshell_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6727,7 +6854,7 @@ func (x *ServiceEndpoint) String() string { func (*ServiceEndpoint) ProtoMessage() {} func (x *ServiceEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[75] + mi := &file_openshell_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6740,7 +6867,7 @@ func (x *ServiceEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceEndpoint.ProtoReflect.Descriptor instead. func (*ServiceEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{75} + return file_openshell_proto_rawDescGZIP(), []int{77} } func (x *ServiceEndpoint) GetMetadata() *datamodelv1.ObjectMeta { @@ -6803,7 +6930,7 @@ type ServiceEndpointResponse struct { func (x *ServiceEndpointResponse) Reset() { *x = ServiceEndpointResponse{} - mi := &file_openshell_proto_msgTypes[76] + mi := &file_openshell_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6815,7 +6942,7 @@ func (x *ServiceEndpointResponse) String() string { func (*ServiceEndpointResponse) ProtoMessage() {} func (x *ServiceEndpointResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[76] + mi := &file_openshell_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6828,7 +6955,7 @@ func (x *ServiceEndpointResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceEndpointResponse.ProtoReflect.Descriptor instead. func (*ServiceEndpointResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{76} + return file_openshell_proto_rawDescGZIP(), []int{78} } func (x *ServiceEndpointResponse) GetEndpoint() *ServiceEndpoint { @@ -6859,7 +6986,7 @@ type RevokeSshSessionRequest struct { func (x *RevokeSshSessionRequest) Reset() { *x = RevokeSshSessionRequest{} - mi := &file_openshell_proto_msgTypes[77] + mi := &file_openshell_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6871,7 +6998,7 @@ func (x *RevokeSshSessionRequest) String() string { func (*RevokeSshSessionRequest) ProtoMessage() {} func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[77] + mi := &file_openshell_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6884,7 +7011,7 @@ func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RevokeSshSessionRequest.ProtoReflect.Descriptor instead. func (*RevokeSshSessionRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{77} + return file_openshell_proto_rawDescGZIP(), []int{79} } func (x *RevokeSshSessionRequest) GetToken() string { @@ -6911,7 +7038,7 @@ type RevokeSshSessionResponse struct { func (x *RevokeSshSessionResponse) Reset() { *x = RevokeSshSessionResponse{} - mi := &file_openshell_proto_msgTypes[78] + mi := &file_openshell_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6923,7 +7050,7 @@ func (x *RevokeSshSessionResponse) String() string { func (*RevokeSshSessionResponse) ProtoMessage() {} func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[78] + mi := &file_openshell_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6936,7 +7063,7 @@ func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RevokeSshSessionResponse.ProtoReflect.Descriptor instead. func (*RevokeSshSessionResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{78} + return file_openshell_proto_rawDescGZIP(), []int{80} } func (x *RevokeSshSessionResponse) GetOutcome() DeletionOutcome { @@ -6986,7 +7113,7 @@ type ExecSandboxRequest struct { func (x *ExecSandboxRequest) Reset() { *x = ExecSandboxRequest{} - mi := &file_openshell_proto_msgTypes[79] + mi := &file_openshell_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6998,7 +7125,7 @@ func (x *ExecSandboxRequest) String() string { func (*ExecSandboxRequest) ProtoMessage() {} func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[79] + mi := &file_openshell_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7011,7 +7138,7 @@ func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxRequest.ProtoReflect.Descriptor instead. func (*ExecSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{79} + return file_openshell_proto_rawDescGZIP(), []int{81} } func (x *ExecSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -7108,7 +7235,7 @@ type ExecSandboxStdout struct { func (x *ExecSandboxStdout) Reset() { *x = ExecSandboxStdout{} - mi := &file_openshell_proto_msgTypes[80] + mi := &file_openshell_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7120,7 +7247,7 @@ func (x *ExecSandboxStdout) String() string { func (*ExecSandboxStdout) ProtoMessage() {} func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[80] + mi := &file_openshell_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7133,7 +7260,7 @@ func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxStdout.ProtoReflect.Descriptor instead. func (*ExecSandboxStdout) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{80} + return file_openshell_proto_rawDescGZIP(), []int{82} } func (x *ExecSandboxStdout) GetData() []byte { @@ -7153,7 +7280,7 @@ type ExecSandboxStderr struct { func (x *ExecSandboxStderr) Reset() { *x = ExecSandboxStderr{} - mi := &file_openshell_proto_msgTypes[81] + mi := &file_openshell_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7165,7 +7292,7 @@ func (x *ExecSandboxStderr) String() string { func (*ExecSandboxStderr) ProtoMessage() {} func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[81] + mi := &file_openshell_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7178,7 +7305,7 @@ func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxStderr.ProtoReflect.Descriptor instead. func (*ExecSandboxStderr) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{81} + return file_openshell_proto_rawDescGZIP(), []int{83} } func (x *ExecSandboxStderr) GetData() []byte { @@ -7198,7 +7325,7 @@ type ExecSandboxExit struct { func (x *ExecSandboxExit) Reset() { *x = ExecSandboxExit{} - mi := &file_openshell_proto_msgTypes[82] + mi := &file_openshell_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7210,7 +7337,7 @@ func (x *ExecSandboxExit) String() string { func (*ExecSandboxExit) ProtoMessage() {} func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[82] + mi := &file_openshell_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7223,7 +7350,7 @@ func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxExit.ProtoReflect.Descriptor instead. func (*ExecSandboxExit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{82} + return file_openshell_proto_rawDescGZIP(), []int{84} } func (x *ExecSandboxExit) GetExitCode() int32 { @@ -7248,7 +7375,7 @@ type ExecSandboxEvent struct { func (x *ExecSandboxEvent) Reset() { *x = ExecSandboxEvent{} - mi := &file_openshell_proto_msgTypes[83] + mi := &file_openshell_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7260,7 +7387,7 @@ func (x *ExecSandboxEvent) String() string { func (*ExecSandboxEvent) ProtoMessage() {} func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[83] + mi := &file_openshell_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7273,7 +7400,7 @@ func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxEvent.ProtoReflect.Descriptor instead. func (*ExecSandboxEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{83} + return file_openshell_proto_rawDescGZIP(), []int{85} } func (x *ExecSandboxEvent) GetPayload() isExecSandboxEvent_Payload { @@ -7355,7 +7482,7 @@ type TcpForwardInit struct { func (x *TcpForwardInit) Reset() { *x = TcpForwardInit{} - mi := &file_openshell_proto_msgTypes[84] + mi := &file_openshell_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7367,7 +7494,7 @@ func (x *TcpForwardInit) String() string { func (*TcpForwardInit) ProtoMessage() {} func (x *TcpForwardInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[84] + mi := &file_openshell_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7380,7 +7507,7 @@ func (x *TcpForwardInit) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpForwardInit.ProtoReflect.Descriptor instead. func (*TcpForwardInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{84} + return file_openshell_proto_rawDescGZIP(), []int{86} } func (x *TcpForwardInit) GetSandbox() string { @@ -7466,7 +7593,7 @@ type TcpForwardFrame struct { func (x *TcpForwardFrame) Reset() { *x = TcpForwardFrame{} - mi := &file_openshell_proto_msgTypes[85] + mi := &file_openshell_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7478,7 +7605,7 @@ func (x *TcpForwardFrame) String() string { func (*TcpForwardFrame) ProtoMessage() {} func (x *TcpForwardFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[85] + mi := &file_openshell_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7491,7 +7618,7 @@ func (x *TcpForwardFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpForwardFrame.ProtoReflect.Descriptor instead. func (*TcpForwardFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{85} + return file_openshell_proto_rawDescGZIP(), []int{87} } func (x *TcpForwardFrame) GetPayload() isTcpForwardFrame_Payload { @@ -7550,7 +7677,7 @@ type ExecSandboxInput struct { func (x *ExecSandboxInput) Reset() { *x = ExecSandboxInput{} - mi := &file_openshell_proto_msgTypes[86] + mi := &file_openshell_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7562,7 +7689,7 @@ func (x *ExecSandboxInput) String() string { func (*ExecSandboxInput) ProtoMessage() {} func (x *ExecSandboxInput) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[86] + mi := &file_openshell_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7575,7 +7702,7 @@ func (x *ExecSandboxInput) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxInput.ProtoReflect.Descriptor instead. func (*ExecSandboxInput) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{86} + return file_openshell_proto_rawDescGZIP(), []int{88} } func (x *ExecSandboxInput) GetPayload() isExecSandboxInput_Payload { @@ -7648,7 +7775,7 @@ type ExecSandboxWindowResize struct { func (x *ExecSandboxWindowResize) Reset() { *x = ExecSandboxWindowResize{} - mi := &file_openshell_proto_msgTypes[87] + mi := &file_openshell_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7660,7 +7787,7 @@ func (x *ExecSandboxWindowResize) String() string { func (*ExecSandboxWindowResize) ProtoMessage() {} func (x *ExecSandboxWindowResize) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[87] + mi := &file_openshell_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7673,7 +7800,7 @@ func (x *ExecSandboxWindowResize) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxWindowResize.ProtoReflect.Descriptor instead. func (*ExecSandboxWindowResize) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{87} + return file_openshell_proto_rawDescGZIP(), []int{89} } func (x *ExecSandboxWindowResize) GetCols() uint32 { @@ -7709,7 +7836,7 @@ type SshSession struct { func (x *SshSession) Reset() { *x = SshSession{} - mi := &file_openshell_proto_msgTypes[88] + mi := &file_openshell_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7721,7 +7848,7 @@ func (x *SshSession) String() string { func (*SshSession) ProtoMessage() {} func (x *SshSession) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[88] + mi := &file_openshell_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7734,7 +7861,7 @@ func (x *SshSession) ProtoReflect() protoreflect.Message { // Deprecated: Use SshSession.ProtoReflect.Descriptor instead. func (*SshSession) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{88} + return file_openshell_proto_rawDescGZIP(), []int{90} } func (x *SshSession) GetMetadata() *datamodelv1.ObjectMeta { @@ -7823,7 +7950,7 @@ type WatchSandboxRequest struct { func (x *WatchSandboxRequest) Reset() { *x = WatchSandboxRequest{} - mi := &file_openshell_proto_msgTypes[89] + mi := &file_openshell_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7835,7 +7962,7 @@ func (x *WatchSandboxRequest) String() string { func (*WatchSandboxRequest) ProtoMessage() {} func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[89] + mi := &file_openshell_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7848,7 +7975,7 @@ func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchSandboxRequest.ProtoReflect.Descriptor instead. func (*WatchSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{89} + return file_openshell_proto_rawDescGZIP(), []int{91} } func (x *WatchSandboxRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -7964,7 +8091,7 @@ type SandboxStreamEvent struct { func (x *SandboxStreamEvent) Reset() { *x = SandboxStreamEvent{} - mi := &file_openshell_proto_msgTypes[90] + mi := &file_openshell_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7976,7 +8103,7 @@ func (x *SandboxStreamEvent) String() string { func (*SandboxStreamEvent) ProtoMessage() {} func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[90] + mi := &file_openshell_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7989,7 +8116,7 @@ func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStreamEvent.ProtoReflect.Descriptor instead. func (*SandboxStreamEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{90} + return file_openshell_proto_rawDescGZIP(), []int{92} } func (x *SandboxStreamEvent) GetPayload() isSandboxStreamEvent_Payload { @@ -8111,7 +8238,7 @@ type SandboxLogLine struct { func (x *SandboxLogLine) Reset() { *x = SandboxLogLine{} - mi := &file_openshell_proto_msgTypes[91] + mi := &file_openshell_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8123,7 +8250,7 @@ func (x *SandboxLogLine) String() string { func (*SandboxLogLine) ProtoMessage() {} func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[91] + mi := &file_openshell_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8136,7 +8263,7 @@ func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxLogLine.ProtoReflect.Descriptor instead. func (*SandboxLogLine) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{91} + return file_openshell_proto_rawDescGZIP(), []int{93} } func (x *SandboxLogLine) GetSandboxId() string { @@ -8202,7 +8329,7 @@ type SandboxStreamWarning struct { func (x *SandboxStreamWarning) Reset() { *x = SandboxStreamWarning{} - mi := &file_openshell_proto_msgTypes[92] + mi := &file_openshell_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8214,7 +8341,7 @@ func (x *SandboxStreamWarning) String() string { func (*SandboxStreamWarning) ProtoMessage() {} func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[92] + mi := &file_openshell_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8227,7 +8354,7 @@ func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStreamWarning.ProtoReflect.Descriptor instead. func (*SandboxStreamWarning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{92} + return file_openshell_proto_rawDescGZIP(), []int{94} } func (x *SandboxStreamWarning) GetMessage() string { @@ -8252,7 +8379,7 @@ type CreateProviderRequest struct { func (x *CreateProviderRequest) Reset() { *x = CreateProviderRequest{} - mi := &file_openshell_proto_msgTypes[93] + mi := &file_openshell_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8264,7 +8391,7 @@ func (x *CreateProviderRequest) String() string { func (*CreateProviderRequest) ProtoMessage() {} func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[93] + mi := &file_openshell_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8277,7 +8404,7 @@ func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateProviderRequest.ProtoReflect.Descriptor instead. func (*CreateProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{93} + return file_openshell_proto_rawDescGZIP(), []int{95} } func (x *CreateProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8313,7 +8440,7 @@ type GetProviderRequest struct { func (x *GetProviderRequest) Reset() { *x = GetProviderRequest{} - mi := &file_openshell_proto_msgTypes[94] + mi := &file_openshell_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8325,7 +8452,7 @@ func (x *GetProviderRequest) String() string { func (*GetProviderRequest) ProtoMessage() {} func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[94] + mi := &file_openshell_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8338,7 +8465,7 @@ func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRequest.ProtoReflect.Descriptor instead. func (*GetProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{94} + return file_openshell_proto_rawDescGZIP(), []int{96} } func (x *GetProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8373,7 +8500,7 @@ type GetProviderCredentialsRequest struct { func (x *GetProviderCredentialsRequest) Reset() { *x = GetProviderCredentialsRequest{} - mi := &file_openshell_proto_msgTypes[95] + mi := &file_openshell_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8385,7 +8512,7 @@ func (x *GetProviderCredentialsRequest) String() string { func (*GetProviderCredentialsRequest) ProtoMessage() {} func (x *GetProviderCredentialsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[95] + mi := &file_openshell_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8398,7 +8525,7 @@ func (x *GetProviderCredentialsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderCredentialsRequest.ProtoReflect.Descriptor instead. func (*GetProviderCredentialsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{95} + return file_openshell_proto_rawDescGZIP(), []int{97} } func (x *GetProviderCredentialsRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8441,7 +8568,7 @@ type ProviderCredentialValue struct { func (x *ProviderCredentialValue) Reset() { *x = ProviderCredentialValue{} - mi := &file_openshell_proto_msgTypes[96] + mi := &file_openshell_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8453,7 +8580,7 @@ func (x *ProviderCredentialValue) String() string { func (*ProviderCredentialValue) ProtoMessage() {} func (x *ProviderCredentialValue) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[96] + mi := &file_openshell_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8466,7 +8593,7 @@ func (x *ProviderCredentialValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialValue.ProtoReflect.Descriptor instead. func (*ProviderCredentialValue) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{96} + return file_openshell_proto_rawDescGZIP(), []int{98} } func (x *ProviderCredentialValue) GetValue() string { @@ -8493,7 +8620,7 @@ type GetProviderCredentialsResponse struct { func (x *GetProviderCredentialsResponse) Reset() { *x = GetProviderCredentialsResponse{} - mi := &file_openshell_proto_msgTypes[97] + mi := &file_openshell_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8505,7 +8632,7 @@ func (x *GetProviderCredentialsResponse) String() string { func (*GetProviderCredentialsResponse) ProtoMessage() {} func (x *GetProviderCredentialsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[97] + mi := &file_openshell_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8518,7 +8645,7 @@ func (x *GetProviderCredentialsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderCredentialsResponse.ProtoReflect.Descriptor instead. func (*GetProviderCredentialsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{97} + return file_openshell_proto_rawDescGZIP(), []int{99} } func (x *GetProviderCredentialsResponse) GetCredentials() map[string]*ProviderCredentialValue { @@ -8547,7 +8674,7 @@ type ListProvidersRequest struct { func (x *ListProvidersRequest) Reset() { *x = ListProvidersRequest{} - mi := &file_openshell_proto_msgTypes[98] + mi := &file_openshell_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8559,7 +8686,7 @@ func (x *ListProvidersRequest) String() string { func (*ListProvidersRequest) ProtoMessage() {} func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[98] + mi := &file_openshell_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8572,7 +8699,7 @@ func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProvidersRequest.ProtoReflect.Descriptor instead. func (*ListProvidersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{98} + return file_openshell_proto_rawDescGZIP(), []int{100} } func (x *ListProvidersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8624,7 +8751,7 @@ type UpdateProviderRequest struct { func (x *UpdateProviderRequest) Reset() { *x = UpdateProviderRequest{} - mi := &file_openshell_proto_msgTypes[99] + mi := &file_openshell_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8636,7 +8763,7 @@ func (x *UpdateProviderRequest) String() string { func (*UpdateProviderRequest) ProtoMessage() {} func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[99] + mi := &file_openshell_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8649,7 +8776,7 @@ func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{99} + return file_openshell_proto_rawDescGZIP(), []int{101} } func (x *UpdateProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8703,7 +8830,7 @@ type DeleteProviderRequest struct { func (x *DeleteProviderRequest) Reset() { *x = DeleteProviderRequest{} - mi := &file_openshell_proto_msgTypes[100] + mi := &file_openshell_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8715,7 +8842,7 @@ func (x *DeleteProviderRequest) String() string { func (*DeleteProviderRequest) ProtoMessage() {} func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[100] + mi := &file_openshell_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8728,7 +8855,7 @@ func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{100} + return file_openshell_proto_rawDescGZIP(), []int{102} } func (x *DeleteProviderRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8774,7 +8901,7 @@ type ProviderResponse struct { func (x *ProviderResponse) Reset() { *x = ProviderResponse{} - mi := &file_openshell_proto_msgTypes[101] + mi := &file_openshell_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8786,7 +8913,7 @@ func (x *ProviderResponse) String() string { func (*ProviderResponse) ProtoMessage() {} func (x *ProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[101] + mi := &file_openshell_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8799,7 +8926,7 @@ func (x *ProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderResponse.ProtoReflect.Descriptor instead. func (*ProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{101} + return file_openshell_proto_rawDescGZIP(), []int{103} } func (x *ProviderResponse) GetProvider() *datamodelv1.Provider { @@ -8835,7 +8962,7 @@ type ListProvidersResponse struct { func (x *ListProvidersResponse) Reset() { *x = ListProvidersResponse{} - mi := &file_openshell_proto_msgTypes[102] + mi := &file_openshell_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8847,7 +8974,7 @@ func (x *ListProvidersResponse) String() string { func (*ListProvidersResponse) ProtoMessage() {} func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[102] + mi := &file_openshell_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8860,7 +8987,7 @@ func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProvidersResponse.ProtoReflect.Descriptor instead. func (*ListProvidersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{102} + return file_openshell_proto_rawDescGZIP(), []int{104} } func (x *ListProvidersResponse) GetProviders() []*datamodelv1.Provider { @@ -8894,7 +9021,7 @@ type ListProviderProfilesRequest struct { func (x *ListProviderProfilesRequest) Reset() { *x = ListProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[103] + mi := &file_openshell_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8906,7 +9033,7 @@ func (x *ListProviderProfilesRequest) String() string { func (*ListProviderProfilesRequest) ProtoMessage() {} func (x *ListProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[103] + mi := &file_openshell_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8919,7 +9046,7 @@ func (x *ListProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ListProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{103} + return file_openshell_proto_rawDescGZIP(), []int{105} } func (x *ListProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -8955,7 +9082,7 @@ type GetProviderProfileRequest struct { func (x *GetProviderProfileRequest) Reset() { *x = GetProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[104] + mi := &file_openshell_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8967,7 +9094,7 @@ func (x *GetProviderProfileRequest) String() string { func (*GetProviderProfileRequest) ProtoMessage() {} func (x *GetProviderProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[104] + mi := &file_openshell_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8980,7 +9107,7 @@ func (x *GetProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderProfileRequest.ProtoReflect.Descriptor instead. func (*GetProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{104} + return file_openshell_proto_rawDescGZIP(), []int{106} } func (x *GetProviderProfileRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -9008,7 +9135,7 @@ type ProviderProfileImportItem struct { func (x *ProviderProfileImportItem) Reset() { *x = ProviderProfileImportItem{} - mi := &file_openshell_proto_msgTypes[105] + mi := &file_openshell_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9020,7 +9147,7 @@ func (x *ProviderProfileImportItem) String() string { func (*ProviderProfileImportItem) ProtoMessage() {} func (x *ProviderProfileImportItem) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[105] + mi := &file_openshell_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9033,7 +9160,7 @@ func (x *ProviderProfileImportItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileImportItem.ProtoReflect.Descriptor instead. func (*ProviderProfileImportItem) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{105} + return file_openshell_proto_rawDescGZIP(), []int{107} } func (x *ProviderProfileImportItem) GetProfile() *ProviderProfile { @@ -9064,7 +9191,7 @@ type ProviderProfileDiagnostic struct { func (x *ProviderProfileDiagnostic) Reset() { *x = ProviderProfileDiagnostic{} - mi := &file_openshell_proto_msgTypes[106] + mi := &file_openshell_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9076,7 +9203,7 @@ func (x *ProviderProfileDiagnostic) String() string { func (*ProviderProfileDiagnostic) ProtoMessage() {} func (x *ProviderProfileDiagnostic) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[106] + mi := &file_openshell_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9089,7 +9216,7 @@ func (x *ProviderProfileDiagnostic) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileDiagnostic.ProtoReflect.Descriptor instead. func (*ProviderProfileDiagnostic) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{106} + return file_openshell_proto_rawDescGZIP(), []int{108} } func (x *ProviderProfileDiagnostic) GetSource() string { @@ -9146,7 +9273,7 @@ type ProviderCredentialTokenGrantAudienceOverride struct { func (x *ProviderCredentialTokenGrantAudienceOverride) Reset() { *x = ProviderCredentialTokenGrantAudienceOverride{} - mi := &file_openshell_proto_msgTypes[107] + mi := &file_openshell_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9158,7 +9285,7 @@ func (x *ProviderCredentialTokenGrantAudienceOverride) String() string { func (*ProviderCredentialTokenGrantAudienceOverride) ProtoMessage() {} func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[107] + mi := &file_openshell_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9171,7 +9298,7 @@ func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protorefle // Deprecated: Use ProviderCredentialTokenGrantAudienceOverride.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrantAudienceOverride) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{107} + return file_openshell_proto_rawDescGZIP(), []int{109} } func (x *ProviderCredentialTokenGrantAudienceOverride) GetHost() string { @@ -9225,7 +9352,7 @@ type ProviderCredentialTokenGrantSubjectToken struct { func (x *ProviderCredentialTokenGrantSubjectToken) Reset() { *x = ProviderCredentialTokenGrantSubjectToken{} - mi := &file_openshell_proto_msgTypes[108] + mi := &file_openshell_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9237,7 +9364,7 @@ func (x *ProviderCredentialTokenGrantSubjectToken) String() string { func (*ProviderCredentialTokenGrantSubjectToken) ProtoMessage() {} func (x *ProviderCredentialTokenGrantSubjectToken) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[108] + mi := &file_openshell_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9250,7 +9377,7 @@ func (x *ProviderCredentialTokenGrantSubjectToken) ProtoReflect() protoreflect.M // Deprecated: Use ProviderCredentialTokenGrantSubjectToken.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrantSubjectToken) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{108} + return file_openshell_proto_rawDescGZIP(), []int{110} } func (x *ProviderCredentialTokenGrantSubjectToken) GetSource() string { @@ -9306,7 +9433,7 @@ type ProviderCredentialTokenGrant struct { func (x *ProviderCredentialTokenGrant) Reset() { *x = ProviderCredentialTokenGrant{} - mi := &file_openshell_proto_msgTypes[109] + mi := &file_openshell_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9318,7 +9445,7 @@ func (x *ProviderCredentialTokenGrant) String() string { func (*ProviderCredentialTokenGrant) ProtoMessage() {} func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[109] + mi := &file_openshell_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9331,7 +9458,7 @@ func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialTokenGrant.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrant) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{109} + return file_openshell_proto_rawDescGZIP(), []int{111} } func (x *ProviderCredentialTokenGrant) GetTokenEndpoint() string { @@ -9435,7 +9562,7 @@ type ProviderProfileCredential struct { func (x *ProviderProfileCredential) Reset() { *x = ProviderProfileCredential{} - mi := &file_openshell_proto_msgTypes[110] + mi := &file_openshell_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9447,7 +9574,7 @@ func (x *ProviderProfileCredential) String() string { func (*ProviderProfileCredential) ProtoMessage() {} func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[110] + mi := &file_openshell_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9460,7 +9587,7 @@ func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileCredential.ProtoReflect.Descriptor instead. func (*ProviderProfileCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{110} + return file_openshell_proto_rawDescGZIP(), []int{112} } func (x *ProviderProfileCredential) GetName() string { @@ -9559,7 +9686,7 @@ type ProviderCredentialRefreshMaterial struct { func (x *ProviderCredentialRefreshMaterial) Reset() { *x = ProviderCredentialRefreshMaterial{} - mi := &file_openshell_proto_msgTypes[111] + mi := &file_openshell_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9571,7 +9698,7 @@ func (x *ProviderCredentialRefreshMaterial) String() string { func (*ProviderCredentialRefreshMaterial) ProtoMessage() {} func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[111] + mi := &file_openshell_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9584,7 +9711,7 @@ func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message // Deprecated: Use ProviderCredentialRefreshMaterial.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshMaterial) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{111} + return file_openshell_proto_rawDescGZIP(), []int{113} } func (x *ProviderCredentialRefreshMaterial) GetName() string { @@ -9629,7 +9756,7 @@ type ProviderCredentialRefreshOutput struct { func (x *ProviderCredentialRefreshOutput) Reset() { *x = ProviderCredentialRefreshOutput{} - mi := &file_openshell_proto_msgTypes[112] + mi := &file_openshell_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9641,7 +9768,7 @@ func (x *ProviderCredentialRefreshOutput) String() string { func (*ProviderCredentialRefreshOutput) ProtoMessage() {} func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[112] + mi := &file_openshell_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9654,7 +9781,7 @@ func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefreshOutput.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshOutput) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{112} + return file_openshell_proto_rawDescGZIP(), []int{114} } func (x *ProviderCredentialRefreshOutput) GetOutput() string { @@ -9686,7 +9813,7 @@ type ProviderCredentialRefresh struct { func (x *ProviderCredentialRefresh) Reset() { *x = ProviderCredentialRefresh{} - mi := &file_openshell_proto_msgTypes[113] + mi := &file_openshell_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9698,7 +9825,7 @@ func (x *ProviderCredentialRefresh) String() string { func (*ProviderCredentialRefresh) ProtoMessage() {} func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[113] + mi := &file_openshell_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9711,7 +9838,7 @@ func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefresh.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefresh) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{113} + return file_openshell_proto_rawDescGZIP(), []int{115} } func (x *ProviderCredentialRefresh) GetStrategy() ProviderCredentialRefreshStrategy { @@ -9792,7 +9919,7 @@ type ProviderCredentialRefreshStatus struct { func (x *ProviderCredentialRefreshStatus) Reset() { *x = ProviderCredentialRefreshStatus{} - mi := &file_openshell_proto_msgTypes[114] + mi := &file_openshell_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9804,7 +9931,7 @@ func (x *ProviderCredentialRefreshStatus) String() string { func (*ProviderCredentialRefreshStatus) ProtoMessage() {} func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[114] + mi := &file_openshell_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9817,7 +9944,7 @@ func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefreshStatus.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{114} + return file_openshell_proto_rawDescGZIP(), []int{116} } func (x *ProviderCredentialRefreshStatus) GetProvider() string { @@ -9922,7 +10049,7 @@ type ProviderProfileDiscovery struct { func (x *ProviderProfileDiscovery) Reset() { *x = ProviderProfileDiscovery{} - mi := &file_openshell_proto_msgTypes[115] + mi := &file_openshell_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9934,7 +10061,7 @@ func (x *ProviderProfileDiscovery) String() string { func (*ProviderProfileDiscovery) ProtoMessage() {} func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[115] + mi := &file_openshell_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9947,7 +10074,7 @@ func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileDiscovery.ProtoReflect.Descriptor instead. func (*ProviderProfileDiscovery) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{115} + return file_openshell_proto_rawDescGZIP(), []int{117} } func (x *ProviderProfileDiscovery) GetCredentials() []string { @@ -9969,7 +10096,7 @@ type GetProviderRefreshStatusRequest struct { func (x *GetProviderRefreshStatusRequest) Reset() { *x = GetProviderRefreshStatusRequest{} - mi := &file_openshell_proto_msgTypes[116] + mi := &file_openshell_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9981,7 +10108,7 @@ func (x *GetProviderRefreshStatusRequest) String() string { func (*GetProviderRefreshStatusRequest) ProtoMessage() {} func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[116] + mi := &file_openshell_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9994,7 +10121,7 @@ func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRefreshStatusRequest.ProtoReflect.Descriptor instead. func (*GetProviderRefreshStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{116} + return file_openshell_proto_rawDescGZIP(), []int{118} } func (x *GetProviderRefreshStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10027,7 +10154,7 @@ type GetProviderRefreshStatusResponse struct { func (x *GetProviderRefreshStatusResponse) Reset() { *x = GetProviderRefreshStatusResponse{} - mi := &file_openshell_proto_msgTypes[117] + mi := &file_openshell_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10039,7 +10166,7 @@ func (x *GetProviderRefreshStatusResponse) String() string { func (*GetProviderRefreshStatusResponse) ProtoMessage() {} func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[117] + mi := &file_openshell_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10052,7 +10179,7 @@ func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRefreshStatusResponse.ProtoReflect.Descriptor instead. func (*GetProviderRefreshStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{117} + return file_openshell_proto_rawDescGZIP(), []int{119} } func (x *GetProviderRefreshStatusResponse) GetCredentials() []*ProviderCredentialRefreshStatus { @@ -10084,7 +10211,7 @@ type ConfigureProviderRefreshRequest struct { func (x *ConfigureProviderRefreshRequest) Reset() { *x = ConfigureProviderRefreshRequest{} - mi := &file_openshell_proto_msgTypes[118] + mi := &file_openshell_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10096,7 +10223,7 @@ func (x *ConfigureProviderRefreshRequest) String() string { func (*ConfigureProviderRefreshRequest) ProtoMessage() {} func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[118] + mi := &file_openshell_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10109,7 +10236,7 @@ func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureProviderRefreshRequest.ProtoReflect.Descriptor instead. func (*ConfigureProviderRefreshRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{118} + return file_openshell_proto_rawDescGZIP(), []int{120} } func (x *ConfigureProviderRefreshRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10177,7 +10304,7 @@ type ConfigureProviderRefreshResponse struct { func (x *ConfigureProviderRefreshResponse) Reset() { *x = ConfigureProviderRefreshResponse{} - mi := &file_openshell_proto_msgTypes[119] + mi := &file_openshell_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10189,7 +10316,7 @@ func (x *ConfigureProviderRefreshResponse) String() string { func (*ConfigureProviderRefreshResponse) ProtoMessage() {} func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[119] + mi := &file_openshell_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10202,7 +10329,7 @@ func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureProviderRefreshResponse.ProtoReflect.Descriptor instead. func (*ConfigureProviderRefreshResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{119} + return file_openshell_proto_rawDescGZIP(), []int{121} } func (x *ConfigureProviderRefreshResponse) GetStatus() *ProviderCredentialRefreshStatus { @@ -10227,7 +10354,7 @@ type RotateProviderCredentialRequest struct { func (x *RotateProviderCredentialRequest) Reset() { *x = RotateProviderCredentialRequest{} - mi := &file_openshell_proto_msgTypes[120] + mi := &file_openshell_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10239,7 +10366,7 @@ func (x *RotateProviderCredentialRequest) String() string { func (*RotateProviderCredentialRequest) ProtoMessage() {} func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[120] + mi := &file_openshell_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10252,7 +10379,7 @@ func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateProviderCredentialRequest.ProtoReflect.Descriptor instead. func (*RotateProviderCredentialRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{120} + return file_openshell_proto_rawDescGZIP(), []int{122} } func (x *RotateProviderCredentialRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10292,7 +10419,7 @@ type RotateProviderCredentialResponse struct { func (x *RotateProviderCredentialResponse) Reset() { *x = RotateProviderCredentialResponse{} - mi := &file_openshell_proto_msgTypes[121] + mi := &file_openshell_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10304,7 +10431,7 @@ func (x *RotateProviderCredentialResponse) String() string { func (*RotateProviderCredentialResponse) ProtoMessage() {} func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[121] + mi := &file_openshell_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10317,7 +10444,7 @@ func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateProviderCredentialResponse.ProtoReflect.Descriptor instead. func (*RotateProviderCredentialResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{121} + return file_openshell_proto_rawDescGZIP(), []int{123} } func (x *RotateProviderCredentialResponse) GetStatus() *ProviderCredentialRefreshStatus { @@ -10343,7 +10470,7 @@ type DeleteProviderRefreshRequest struct { func (x *DeleteProviderRefreshRequest) Reset() { *x = DeleteProviderRefreshRequest{} - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10355,7 +10482,7 @@ func (x *DeleteProviderRefreshRequest) String() string { func (*DeleteProviderRefreshRequest) ProtoMessage() {} func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10368,7 +10495,7 @@ func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRefreshRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderRefreshRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{122} + return file_openshell_proto_rawDescGZIP(), []int{124} } func (x *DeleteProviderRefreshRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10415,7 +10542,7 @@ type DeleteProviderRefreshResponse struct { func (x *DeleteProviderRefreshResponse) Reset() { *x = DeleteProviderRefreshResponse{} - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10427,7 +10554,7 @@ func (x *DeleteProviderRefreshResponse) String() string { func (*DeleteProviderRefreshResponse) ProtoMessage() {} func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10440,7 +10567,7 @@ func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRefreshResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderRefreshResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{123} + return file_openshell_proto_rawDescGZIP(), []int{125} } func (x *DeleteProviderRefreshResponse) GetOutcome() DeletionOutcome { @@ -10483,7 +10610,7 @@ type ProviderProfile struct { func (x *ProviderProfile) Reset() { *x = ProviderProfile{} - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10495,7 +10622,7 @@ func (x *ProviderProfile) String() string { func (*ProviderProfile) ProtoMessage() {} func (x *ProviderProfile) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10508,7 +10635,7 @@ func (x *ProviderProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfile.ProtoReflect.Descriptor instead. func (*ProviderProfile) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{124} + return file_openshell_proto_rawDescGZIP(), []int{126} } func (x *ProviderProfile) GetId() string { @@ -10624,7 +10751,7 @@ type ProviderProfileFile struct { func (x *ProviderProfileFile) Reset() { *x = ProviderProfileFile{} - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10636,7 +10763,7 @@ func (x *ProviderProfileFile) String() string { func (*ProviderProfileFile) ProtoMessage() {} func (x *ProviderProfileFile) 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 { @@ -10649,7 +10776,7 @@ func (x *ProviderProfileFile) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileFile.ProtoReflect.Descriptor instead. func (*ProviderProfileFile) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{125} + return file_openshell_proto_rawDescGZIP(), []int{127} } func (x *ProviderProfileFile) GetPath() string { @@ -10683,7 +10810,7 @@ type ProviderProfileResponse struct { func (x *ProviderProfileResponse) Reset() { *x = ProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10695,7 +10822,7 @@ func (x *ProviderProfileResponse) String() string { func (*ProviderProfileResponse) ProtoMessage() {} func (x *ProviderProfileResponse) 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 { @@ -10708,7 +10835,7 @@ func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileResponse.ProtoReflect.Descriptor instead. func (*ProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{126} + return file_openshell_proto_rawDescGZIP(), []int{128} } func (x *ProviderProfileResponse) GetProfile() *ProviderProfile { @@ -10730,7 +10857,7 @@ type ListProviderProfilesResponse struct { func (x *ListProviderProfilesResponse) Reset() { *x = ListProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10742,7 +10869,7 @@ func (x *ListProviderProfilesResponse) String() string { func (*ListProviderProfilesResponse) ProtoMessage() {} func (x *ListProviderProfilesResponse) 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 { @@ -10755,7 +10882,7 @@ func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ListProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{127} + return file_openshell_proto_rawDescGZIP(), []int{129} } func (x *ListProviderProfilesResponse) GetProfiles() []*ProviderProfile { @@ -10787,7 +10914,7 @@ type ImportProviderProfilesRequest struct { func (x *ImportProviderProfilesRequest) Reset() { *x = ImportProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10799,7 +10926,7 @@ func (x *ImportProviderProfilesRequest) String() string { func (*ImportProviderProfilesRequest) ProtoMessage() {} func (x *ImportProviderProfilesRequest) 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 { @@ -10812,7 +10939,7 @@ func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{128} + return file_openshell_proto_rawDescGZIP(), []int{130} } func (x *ImportProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10848,7 +10975,7 @@ type ImportProviderProfilesResponse struct { func (x *ImportProviderProfilesResponse) Reset() { *x = ImportProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10860,7 +10987,7 @@ func (x *ImportProviderProfilesResponse) String() string { func (*ImportProviderProfilesResponse) ProtoMessage() {} func (x *ImportProviderProfilesResponse) 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 { @@ -10873,7 +11000,7 @@ func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{129} + return file_openshell_proto_rawDescGZIP(), []int{131} } func (x *ImportProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -10919,7 +11046,7 @@ type UpdateProviderProfilesRequest struct { func (x *UpdateProviderProfilesRequest) Reset() { *x = UpdateProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10931,7 +11058,7 @@ func (x *UpdateProviderProfilesRequest) String() string { func (*UpdateProviderProfilesRequest) ProtoMessage() {} func (x *UpdateProviderProfilesRequest) 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 { @@ -10944,7 +11071,7 @@ func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{130} + return file_openshell_proto_rawDescGZIP(), []int{132} } func (x *UpdateProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10994,7 +11121,7 @@ type UpdateProviderProfilesResponse struct { func (x *UpdateProviderProfilesResponse) Reset() { *x = UpdateProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11006,7 +11133,7 @@ func (x *UpdateProviderProfilesResponse) String() string { func (*UpdateProviderProfilesResponse) ProtoMessage() {} func (x *UpdateProviderProfilesResponse) 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 { @@ -11019,7 +11146,7 @@ func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{131} + return file_openshell_proto_rawDescGZIP(), []int{133} } func (x *UpdateProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11055,7 +11182,7 @@ type LintProviderProfilesRequest struct { func (x *LintProviderProfilesRequest) Reset() { *x = LintProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11067,7 +11194,7 @@ func (x *LintProviderProfilesRequest) String() string { func (*LintProviderProfilesRequest) ProtoMessage() {} func (x *LintProviderProfilesRequest) 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 { @@ -11080,7 +11207,7 @@ func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*LintProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{132} + return file_openshell_proto_rawDescGZIP(), []int{134} } func (x *LintProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11111,7 +11238,7 @@ type LintProviderProfilesResponse struct { func (x *LintProviderProfilesResponse) Reset() { *x = LintProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11123,7 +11250,7 @@ func (x *LintProviderProfilesResponse) String() string { func (*LintProviderProfilesResponse) ProtoMessage() {} func (x *LintProviderProfilesResponse) 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 { @@ -11136,7 +11263,7 @@ func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*LintProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{133} + return file_openshell_proto_rawDescGZIP(), []int{135} } func (x *LintProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -11170,7 +11297,7 @@ type DeleteProviderResponse struct { func (x *DeleteProviderResponse) Reset() { *x = DeleteProviderResponse{} - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11182,7 +11309,7 @@ func (x *DeleteProviderResponse) String() string { func (*DeleteProviderResponse) ProtoMessage() {} func (x *DeleteProviderResponse) 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 { @@ -11195,7 +11322,7 @@ func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{134} + return file_openshell_proto_rawDescGZIP(), []int{136} } func (x *DeleteProviderResponse) GetOutcome() DeletionOutcome { @@ -11221,7 +11348,7 @@ type DeleteProviderProfileRequest struct { func (x *DeleteProviderProfileRequest) Reset() { *x = DeleteProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11233,7 +11360,7 @@ func (x *DeleteProviderProfileRequest) String() string { func (*DeleteProviderProfileRequest) ProtoMessage() {} func (x *DeleteProviderProfileRequest) 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 { @@ -11246,7 +11373,7 @@ func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{135} + return file_openshell_proto_rawDescGZIP(), []int{137} } func (x *DeleteProviderProfileRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11287,7 +11414,7 @@ type DeleteProviderProfileResponse struct { func (x *DeleteProviderProfileResponse) Reset() { *x = DeleteProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11299,7 +11426,7 @@ func (x *DeleteProviderProfileResponse) String() string { func (*DeleteProviderProfileResponse) ProtoMessage() {} func (x *DeleteProviderProfileResponse) 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 { @@ -11312,7 +11439,7 @@ func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{136} + return file_openshell_proto_rawDescGZIP(), []int{138} } func (x *DeleteProviderProfileResponse) GetOutcome() DeletionOutcome { @@ -11341,7 +11468,7 @@ type GetSandboxProviderEnvironmentRequest struct { func (x *GetSandboxProviderEnvironmentRequest) Reset() { *x = GetSandboxProviderEnvironmentRequest{} - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11353,7 +11480,7 @@ func (x *GetSandboxProviderEnvironmentRequest) String() string { func (*GetSandboxProviderEnvironmentRequest) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentRequest) 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 { @@ -11366,7 +11493,7 @@ func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Messa // Deprecated: Use GetSandboxProviderEnvironmentRequest.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{137} + return file_openshell_proto_rawDescGZIP(), []int{139} } func (x *GetSandboxProviderEnvironmentRequest) GetSandboxId() string { @@ -11402,7 +11529,7 @@ type StaticCredentialEndpointBinding struct { func (x *StaticCredentialEndpointBinding) Reset() { *x = StaticCredentialEndpointBinding{} - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[140] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11414,7 +11541,7 @@ func (x *StaticCredentialEndpointBinding) String() string { func (*StaticCredentialEndpointBinding) ProtoMessage() {} func (x *StaticCredentialEndpointBinding) 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 { @@ -11427,7 +11554,7 @@ func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialEndpointBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialEndpointBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{138} + return file_openshell_proto_rawDescGZIP(), []int{140} } func (x *StaticCredentialEndpointBinding) GetHost() string { @@ -11471,7 +11598,7 @@ type StaticCredentialBinding struct { func (x *StaticCredentialBinding) Reset() { *x = StaticCredentialBinding{} - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11483,7 +11610,7 @@ func (x *StaticCredentialBinding) String() string { func (*StaticCredentialBinding) ProtoMessage() {} func (x *StaticCredentialBinding) 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 { @@ -11496,7 +11623,7 @@ func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{139} + return file_openshell_proto_rawDescGZIP(), []int{141} } func (x *StaticCredentialBinding) GetEndpoints() []*StaticCredentialEndpointBinding { @@ -11566,7 +11693,7 @@ type GetSandboxProviderEnvironmentResponse struct { func (x *GetSandboxProviderEnvironmentResponse) Reset() { *x = GetSandboxProviderEnvironmentResponse{} - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[142] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11578,7 +11705,7 @@ func (x *GetSandboxProviderEnvironmentResponse) String() string { func (*GetSandboxProviderEnvironmentResponse) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentResponse) 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 { @@ -11591,7 +11718,7 @@ func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Mess // Deprecated: Use GetSandboxProviderEnvironmentResponse.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{140} + return file_openshell_proto_rawDescGZIP(), []int{142} } func (x *GetSandboxProviderEnvironmentResponse) GetEnvironment() map[string]string { @@ -11700,7 +11827,7 @@ type ProviderEnvironmentValue struct { func (x *ProviderEnvironmentValue) Reset() { *x = ProviderEnvironmentValue{} - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[143] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11712,7 +11839,7 @@ func (x *ProviderEnvironmentValue) String() string { func (*ProviderEnvironmentValue) ProtoMessage() {} func (x *ProviderEnvironmentValue) 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 { @@ -11725,7 +11852,7 @@ func (x *ProviderEnvironmentValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderEnvironmentValue.ProtoReflect.Descriptor instead. func (*ProviderEnvironmentValue) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{141} + return file_openshell_proto_rawDescGZIP(), []int{143} } func (x *ProviderEnvironmentValue) GetName() string { @@ -11791,7 +11918,7 @@ type ProviderEnvironmentSnapshot struct { func (x *ProviderEnvironmentSnapshot) Reset() { *x = ProviderEnvironmentSnapshot{} - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[144] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11803,7 +11930,7 @@ func (x *ProviderEnvironmentSnapshot) String() string { func (*ProviderEnvironmentSnapshot) ProtoMessage() {} func (x *ProviderEnvironmentSnapshot) 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 { @@ -11816,7 +11943,7 @@ func (x *ProviderEnvironmentSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderEnvironmentSnapshot.ProtoReflect.Descriptor instead. func (*ProviderEnvironmentSnapshot) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{142} + return file_openshell_proto_rawDescGZIP(), []int{144} } func (x *ProviderEnvironmentSnapshot) GetProviderEnvRevision() uint64 { @@ -11885,7 +12012,7 @@ type ExchangeProviderSubjectTokenRequest struct { func (x *ExchangeProviderSubjectTokenRequest) Reset() { *x = ExchangeProviderSubjectTokenRequest{} - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11897,7 +12024,7 @@ func (x *ExchangeProviderSubjectTokenRequest) String() string { func (*ExchangeProviderSubjectTokenRequest) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenRequest) 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 { @@ -11910,7 +12037,7 @@ func (x *ExchangeProviderSubjectTokenRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use ExchangeProviderSubjectTokenRequest.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{143} + return file_openshell_proto_rawDescGZIP(), []int{145} } func (x *ExchangeProviderSubjectTokenRequest) GetSandboxId() string { @@ -11952,7 +12079,7 @@ type ExchangeProviderSubjectTokenResponse struct { func (x *ExchangeProviderSubjectTokenResponse) Reset() { *x = ExchangeProviderSubjectTokenResponse{} - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11964,7 +12091,7 @@ func (x *ExchangeProviderSubjectTokenResponse) String() string { func (*ExchangeProviderSubjectTokenResponse) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenResponse) 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 { @@ -11977,7 +12104,7 @@ func (x *ExchangeProviderSubjectTokenResponse) ProtoReflect() protoreflect.Messa // Deprecated: Use ExchangeProviderSubjectTokenResponse.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{144} + return file_openshell_proto_rawDescGZIP(), []int{146} } func (x *ExchangeProviderSubjectTokenResponse) GetAccessToken() string { @@ -12051,7 +12178,7 @@ type UpdateConfigRequest struct { func (x *UpdateConfigRequest) Reset() { *x = UpdateConfigRequest{} - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[147] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12063,7 +12190,7 @@ func (x *UpdateConfigRequest) String() string { func (*UpdateConfigRequest) ProtoMessage() {} func (x *UpdateConfigRequest) 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 { @@ -12076,7 +12203,7 @@ func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigRequest.ProtoReflect.Descriptor instead. func (*UpdateConfigRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{145} + return file_openshell_proto_rawDescGZIP(), []int{147} } func (x *UpdateConfigRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -12173,7 +12300,7 @@ type PolicyMergeOperation struct { func (x *PolicyMergeOperation) Reset() { *x = PolicyMergeOperation{} - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12185,7 +12312,7 @@ func (x *PolicyMergeOperation) String() string { func (*PolicyMergeOperation) ProtoMessage() {} func (x *PolicyMergeOperation) 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 { @@ -12198,7 +12325,7 @@ func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyMergeOperation.ProtoReflect.Descriptor instead. func (*PolicyMergeOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{146} + return file_openshell_proto_rawDescGZIP(), []int{148} } func (x *PolicyMergeOperation) GetOperation() isPolicyMergeOperation_Operation { @@ -12312,7 +12439,7 @@ type AddNetworkRule struct { func (x *AddNetworkRule) Reset() { *x = AddNetworkRule{} - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12324,7 +12451,7 @@ func (x *AddNetworkRule) String() string { func (*AddNetworkRule) ProtoMessage() {} func (x *AddNetworkRule) 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 { @@ -12337,7 +12464,7 @@ func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use AddNetworkRule.ProtoReflect.Descriptor instead. func (*AddNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{147} + return file_openshell_proto_rawDescGZIP(), []int{149} } func (x *AddNetworkRule) GetRuleName() string { @@ -12365,7 +12492,7 @@ type RemoveNetworkEndpoint struct { func (x *RemoveNetworkEndpoint) Reset() { *x = RemoveNetworkEndpoint{} - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12377,7 +12504,7 @@ func (x *RemoveNetworkEndpoint) String() string { func (*RemoveNetworkEndpoint) ProtoMessage() {} func (x *RemoveNetworkEndpoint) 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 { @@ -12390,7 +12517,7 @@ func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkEndpoint.ProtoReflect.Descriptor instead. func (*RemoveNetworkEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{148} + return file_openshell_proto_rawDescGZIP(), []int{150} } func (x *RemoveNetworkEndpoint) GetRuleName() string { @@ -12423,7 +12550,7 @@ type RemoveNetworkRule struct { func (x *RemoveNetworkRule) Reset() { *x = RemoveNetworkRule{} - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12435,7 +12562,7 @@ func (x *RemoveNetworkRule) String() string { func (*RemoveNetworkRule) ProtoMessage() {} func (x *RemoveNetworkRule) 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 { @@ -12448,7 +12575,7 @@ func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkRule.ProtoReflect.Descriptor instead. func (*RemoveNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{149} + return file_openshell_proto_rawDescGZIP(), []int{151} } func (x *RemoveNetworkRule) GetRuleName() string { @@ -12477,7 +12604,7 @@ type L7RuleTarget struct { func (x *L7RuleTarget) Reset() { *x = L7RuleTarget{} - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12489,7 +12616,7 @@ func (x *L7RuleTarget) String() string { func (*L7RuleTarget) ProtoMessage() {} func (x *L7RuleTarget) 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 { @@ -12502,7 +12629,7 @@ func (x *L7RuleTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RuleTarget.ProtoReflect.Descriptor instead. func (*L7RuleTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{150} + return file_openshell_proto_rawDescGZIP(), []int{152} } func (x *L7RuleTarget) GetRuleName() string { @@ -12557,7 +12684,7 @@ type AddDenyRules struct { func (x *AddDenyRules) Reset() { *x = AddDenyRules{} - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12569,7 +12696,7 @@ func (x *AddDenyRules) String() string { func (*AddDenyRules) ProtoMessage() {} func (x *AddDenyRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[153] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12582,7 +12709,7 @@ func (x *AddDenyRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddDenyRules.ProtoReflect.Descriptor instead. func (*AddDenyRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{151} + return file_openshell_proto_rawDescGZIP(), []int{153} } func (x *AddDenyRules) GetDenyRules() []*sandboxv1.L7DenyRule { @@ -12609,7 +12736,7 @@ type AddAllowRules struct { func (x *AddAllowRules) Reset() { *x = AddAllowRules{} - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[154] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12621,7 +12748,7 @@ func (x *AddAllowRules) String() string { func (*AddAllowRules) ProtoMessage() {} func (x *AddAllowRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[154] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12634,7 +12761,7 @@ func (x *AddAllowRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAllowRules.ProtoReflect.Descriptor instead. func (*AddAllowRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{152} + return file_openshell_proto_rawDescGZIP(), []int{154} } func (x *AddAllowRules) GetRules() []*sandboxv1.L7Rule { @@ -12661,7 +12788,7 @@ type RemoveNetworkBinary struct { func (x *RemoveNetworkBinary) Reset() { *x = RemoveNetworkBinary{} - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[155] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12673,7 +12800,7 @@ func (x *RemoveNetworkBinary) String() string { func (*RemoveNetworkBinary) ProtoMessage() {} func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[155] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12686,7 +12813,7 @@ func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkBinary.ProtoReflect.Descriptor instead. func (*RemoveNetworkBinary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{153} + return file_openshell_proto_rawDescGZIP(), []int{155} } func (x *RemoveNetworkBinary) GetRuleName() string { @@ -12722,7 +12849,7 @@ type UpdateConfigResponse struct { func (x *UpdateConfigResponse) Reset() { *x = UpdateConfigResponse{} - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[156] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12734,7 +12861,7 @@ func (x *UpdateConfigResponse) String() string { func (*UpdateConfigResponse) ProtoMessage() {} func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[156] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12747,7 +12874,7 @@ func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigResponse.ProtoReflect.Descriptor instead. func (*UpdateConfigResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{154} + return file_openshell_proto_rawDescGZIP(), []int{156} } func (x *UpdateConfigResponse) GetVersion() uint32 { @@ -12801,7 +12928,7 @@ type GetSandboxPolicyStatusRequest struct { func (x *GetSandboxPolicyStatusRequest) Reset() { *x = GetSandboxPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[157] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12813,7 +12940,7 @@ func (x *GetSandboxPolicyStatusRequest) String() string { func (*GetSandboxPolicyStatusRequest) ProtoMessage() {} func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[157] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12826,7 +12953,7 @@ func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{155} + return file_openshell_proto_rawDescGZIP(), []int{157} } func (x *GetSandboxPolicyStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -12870,7 +12997,7 @@ type GetSandboxPolicyStatusResponse struct { func (x *GetSandboxPolicyStatusResponse) Reset() { *x = GetSandboxPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[158] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12882,7 +13009,7 @@ func (x *GetSandboxPolicyStatusResponse) String() string { func (*GetSandboxPolicyStatusResponse) ProtoMessage() {} func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[158] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12895,7 +13022,7 @@ func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{156} + return file_openshell_proto_rawDescGZIP(), []int{158} } func (x *GetSandboxPolicyStatusResponse) GetRevision() *SandboxPolicyRevision { @@ -12932,7 +13059,7 @@ type ListSandboxPoliciesRequest struct { func (x *ListSandboxPoliciesRequest) Reset() { *x = ListSandboxPoliciesRequest{} - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[159] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12944,7 +13071,7 @@ func (x *ListSandboxPoliciesRequest) String() string { func (*ListSandboxPoliciesRequest) ProtoMessage() {} func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[159] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12957,7 +13084,7 @@ func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{157} + return file_openshell_proto_rawDescGZIP(), []int{159} } func (x *ListSandboxPoliciesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -13009,7 +13136,7 @@ type ListSandboxPoliciesResponse struct { func (x *ListSandboxPoliciesResponse) Reset() { *x = ListSandboxPoliciesResponse{} - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[160] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13021,7 +13148,7 @@ func (x *ListSandboxPoliciesResponse) String() string { func (*ListSandboxPoliciesResponse) ProtoMessage() {} func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[160] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13034,7 +13161,7 @@ func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{158} + return file_openshell_proto_rawDescGZIP(), []int{160} } func (x *ListSandboxPoliciesResponse) GetRevisions() []*SandboxPolicyRevision { @@ -13068,7 +13195,7 @@ type ReportPolicyStatusRequest struct { func (x *ReportPolicyStatusRequest) Reset() { *x = ReportPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[161] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13080,7 +13207,7 @@ func (x *ReportPolicyStatusRequest) String() string { func (*ReportPolicyStatusRequest) ProtoMessage() {} func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[161] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13093,7 +13220,7 @@ func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{159} + return file_openshell_proto_rawDescGZIP(), []int{161} } func (x *ReportPolicyStatusRequest) GetSandboxId() string { @@ -13133,7 +13260,7 @@ type ReportPolicyStatusResponse struct { func (x *ReportPolicyStatusResponse) Reset() { *x = ReportPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[162] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13145,7 +13272,7 @@ func (x *ReportPolicyStatusResponse) String() string { func (*ReportPolicyStatusResponse) ProtoMessage() {} func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[162] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13158,7 +13285,7 @@ func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{160} + return file_openshell_proto_rawDescGZIP(), []int{162} } type SandboxConfigurationAdmission struct { @@ -13176,7 +13303,7 @@ type SandboxConfigurationAdmission struct { func (x *SandboxConfigurationAdmission) Reset() { *x = SandboxConfigurationAdmission{} - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[163] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13188,7 +13315,7 @@ func (x *SandboxConfigurationAdmission) String() string { func (*SandboxConfigurationAdmission) ProtoMessage() {} func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[163] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13201,7 +13328,7 @@ func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfigurationAdmission.ProtoReflect.Descriptor instead. func (*SandboxConfigurationAdmission) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{161} + return file_openshell_proto_rawDescGZIP(), []int{163} } func (x *SandboxConfigurationAdmission) GetInstanceId() string { @@ -13265,7 +13392,7 @@ type ReportSandboxConfigurationRequest struct { func (x *ReportSandboxConfigurationRequest) Reset() { *x = ReportSandboxConfigurationRequest{} - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[164] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13277,7 +13404,7 @@ func (x *ReportSandboxConfigurationRequest) String() string { func (*ReportSandboxConfigurationRequest) ProtoMessage() {} func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[164] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13290,7 +13417,7 @@ func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ReportSandboxConfigurationRequest.ProtoReflect.Descriptor instead. func (*ReportSandboxConfigurationRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{162} + return file_openshell_proto_rawDescGZIP(), []int{164} } func (x *ReportSandboxConfigurationRequest) GetSandboxId() string { @@ -13322,7 +13449,7 @@ type ReportSandboxConfigurationResponse struct { func (x *ReportSandboxConfigurationResponse) Reset() { *x = ReportSandboxConfigurationResponse{} - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[165] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13334,7 +13461,7 @@ func (x *ReportSandboxConfigurationResponse) String() string { func (*ReportSandboxConfigurationResponse) ProtoMessage() {} func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[165] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13347,7 +13474,7 @@ func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ReportSandboxConfigurationResponse.ProtoReflect.Descriptor instead. func (*ReportSandboxConfigurationResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{163} + return file_openshell_proto_rawDescGZIP(), []int{165} } // A versioned policy revision with metadata. @@ -13380,7 +13507,7 @@ type SandboxPolicyRevision struct { func (x *SandboxPolicyRevision) Reset() { *x = SandboxPolicyRevision{} - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[166] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13392,7 +13519,7 @@ func (x *SandboxPolicyRevision) String() string { func (*SandboxPolicyRevision) ProtoMessage() {} func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[166] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13405,7 +13532,7 @@ func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxPolicyRevision.ProtoReflect.Descriptor instead. func (*SandboxPolicyRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{164} + return file_openshell_proto_rawDescGZIP(), []int{166} } func (x *SandboxPolicyRevision) GetVersion() uint32 { @@ -13485,7 +13612,7 @@ type GetSandboxLogsRequest struct { func (x *GetSandboxLogsRequest) Reset() { *x = GetSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[167] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13497,7 +13624,7 @@ func (x *GetSandboxLogsRequest) String() string { func (*GetSandboxLogsRequest) ProtoMessage() {} func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[167] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13510,7 +13637,7 @@ func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*GetSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{165} + return file_openshell_proto_rawDescGZIP(), []int{167} } func (x *GetSandboxLogsRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -13568,7 +13695,7 @@ type PushSandboxLogsRequest struct { func (x *PushSandboxLogsRequest) Reset() { *x = PushSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[168] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13580,7 +13707,7 @@ func (x *PushSandboxLogsRequest) String() string { func (*PushSandboxLogsRequest) ProtoMessage() {} func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[168] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13593,7 +13720,7 @@ func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*PushSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{166} + return file_openshell_proto_rawDescGZIP(), []int{168} } func (x *PushSandboxLogsRequest) GetSandboxId() string { @@ -13619,7 +13746,7 @@ type PushSandboxLogsResponse struct { func (x *PushSandboxLogsResponse) Reset() { *x = PushSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[169] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13631,7 +13758,7 @@ func (x *PushSandboxLogsResponse) String() string { func (*PushSandboxLogsResponse) ProtoMessage() {} func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[169] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13644,7 +13771,7 @@ func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*PushSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{167} + return file_openshell_proto_rawDescGZIP(), []int{169} } // Get sandbox logs response. @@ -13660,7 +13787,7 @@ type GetSandboxLogsResponse struct { func (x *GetSandboxLogsResponse) Reset() { *x = GetSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[170] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13672,7 +13799,7 @@ func (x *GetSandboxLogsResponse) String() string { func (*GetSandboxLogsResponse) ProtoMessage() {} func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[170] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13685,7 +13812,7 @@ func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*GetSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{168} + return file_openshell_proto_rawDescGZIP(), []int{170} } func (x *GetSandboxLogsResponse) GetLogs() []*SandboxLogLine { @@ -13719,7 +13846,7 @@ type SupervisorMessage struct { func (x *SupervisorMessage) Reset() { *x = SupervisorMessage{} - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[171] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13731,7 +13858,7 @@ func (x *SupervisorMessage) String() string { func (*SupervisorMessage) ProtoMessage() {} func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[171] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13744,7 +13871,7 @@ func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMessage.ProtoReflect.Descriptor instead. func (*SupervisorMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{169} + return file_openshell_proto_rawDescGZIP(), []int{171} } func (x *SupervisorMessage) GetPayload() isSupervisorMessage_Payload { @@ -13852,7 +13979,7 @@ type GatewayMessage struct { func (x *GatewayMessage) Reset() { *x = GatewayMessage{} - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[172] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13864,7 +13991,7 @@ func (x *GatewayMessage) String() string { func (*GatewayMessage) ProtoMessage() {} func (x *GatewayMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[172] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13877,7 +14004,7 @@ func (x *GatewayMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayMessage.ProtoReflect.Descriptor instead. func (*GatewayMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{170} + return file_openshell_proto_rawDescGZIP(), []int{172} } func (x *GatewayMessage) GetPayload() isGatewayMessage_Payload { @@ -14027,7 +14154,7 @@ type SupervisorHello struct { func (x *SupervisorHello) Reset() { *x = SupervisorHello{} - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[173] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14039,7 +14166,7 @@ func (x *SupervisorHello) String() string { func (*SupervisorHello) ProtoMessage() {} func (x *SupervisorHello) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[173] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14052,7 +14179,7 @@ func (x *SupervisorHello) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHello.ProtoReflect.Descriptor instead. func (*SupervisorHello) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{171} + return file_openshell_proto_rawDescGZIP(), []int{173} } func (x *SupervisorHello) GetSandboxId() string { @@ -14125,7 +14252,7 @@ type SessionAccepted struct { func (x *SessionAccepted) Reset() { *x = SessionAccepted{} - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[174] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14137,7 +14264,7 @@ func (x *SessionAccepted) String() string { func (*SessionAccepted) ProtoMessage() {} func (x *SessionAccepted) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[174] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14150,7 +14277,7 @@ func (x *SessionAccepted) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionAccepted.ProtoReflect.Descriptor instead. func (*SessionAccepted) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{172} + return file_openshell_proto_rawDescGZIP(), []int{174} } func (x *SessionAccepted) GetSessionId() string { @@ -14199,7 +14326,7 @@ type ConfigUpdate struct { func (x *ConfigUpdate) Reset() { *x = ConfigUpdate{} - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[175] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14211,7 +14338,7 @@ func (x *ConfigUpdate) String() string { func (*ConfigUpdate) ProtoMessage() {} func (x *ConfigUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[175] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14224,7 +14351,7 @@ func (x *ConfigUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdate.ProtoReflect.Descriptor instead. func (*ConfigUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{173} + return file_openshell_proto_rawDescGZIP(), []int{175} } func (x *ConfigUpdate) GetUpdateId() string { @@ -14261,7 +14388,7 @@ type ConfigApplyFailure struct { func (x *ConfigApplyFailure) Reset() { *x = ConfigApplyFailure{} - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[176] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14273,7 +14400,7 @@ func (x *ConfigApplyFailure) String() string { func (*ConfigApplyFailure) ProtoMessage() {} func (x *ConfigApplyFailure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[176] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14286,7 +14413,7 @@ func (x *ConfigApplyFailure) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigApplyFailure.ProtoReflect.Descriptor instead. func (*ConfigApplyFailure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{174} + return file_openshell_proto_rawDescGZIP(), []int{176} } func (x *ConfigApplyFailure) GetCode() string { @@ -14330,7 +14457,7 @@ type ConfigUpdateResult struct { func (x *ConfigUpdateResult) Reset() { *x = ConfigUpdateResult{} - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[177] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14342,7 +14469,7 @@ func (x *ConfigUpdateResult) String() string { func (*ConfigUpdateResult) ProtoMessage() {} func (x *ConfigUpdateResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[177] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14355,7 +14482,7 @@ func (x *ConfigUpdateResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigUpdateResult.ProtoReflect.Descriptor instead. func (*ConfigUpdateResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{175} + return file_openshell_proto_rawDescGZIP(), []int{177} } func (x *ConfigUpdateResult) GetUpdateId() string { @@ -14406,7 +14533,7 @@ type PolicyLoadResult struct { func (x *PolicyLoadResult) Reset() { *x = PolicyLoadResult{} - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[178] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14418,7 +14545,7 @@ func (x *PolicyLoadResult) String() string { func (*PolicyLoadResult) ProtoMessage() {} func (x *PolicyLoadResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[178] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14431,7 +14558,7 @@ func (x *PolicyLoadResult) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyLoadResult.ProtoReflect.Descriptor instead. func (*PolicyLoadResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{176} + return file_openshell_proto_rawDescGZIP(), []int{178} } func (x *PolicyLoadResult) GetVersion() uint32 { @@ -14466,7 +14593,7 @@ type SessionRejected struct { func (x *SessionRejected) Reset() { *x = SessionRejected{} - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[179] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14478,7 +14605,7 @@ func (x *SessionRejected) String() string { func (*SessionRejected) ProtoMessage() {} func (x *SessionRejected) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[179] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14491,7 +14618,7 @@ func (x *SessionRejected) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRejected.ProtoReflect.Descriptor instead. func (*SessionRejected) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{177} + return file_openshell_proto_rawDescGZIP(), []int{179} } func (x *SessionRejected) GetReason() string { @@ -14520,7 +14647,7 @@ type SessionRedirect struct { func (x *SessionRedirect) Reset() { *x = SessionRedirect{} - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[180] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14532,7 +14659,7 @@ func (x *SessionRedirect) String() string { func (*SessionRedirect) ProtoMessage() {} func (x *SessionRedirect) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[180] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14545,7 +14672,7 @@ func (x *SessionRedirect) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRedirect.ProtoReflect.Descriptor instead. func (*SessionRedirect) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{178} + return file_openshell_proto_rawDescGZIP(), []int{180} } func (x *SessionRedirect) GetPeerEndpoint() string { @@ -14571,7 +14698,7 @@ type SupervisorHeartbeat struct { func (x *SupervisorHeartbeat) Reset() { *x = SupervisorHeartbeat{} - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[181] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14583,7 +14710,7 @@ func (x *SupervisorHeartbeat) String() string { func (*SupervisorHeartbeat) ProtoMessage() {} func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[181] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14596,7 +14723,7 @@ func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHeartbeat.ProtoReflect.Descriptor instead. func (*SupervisorHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{179} + return file_openshell_proto_rawDescGZIP(), []int{181} } // Gateway heartbeat. @@ -14608,7 +14735,7 @@ type GatewayHeartbeat struct { func (x *GatewayHeartbeat) Reset() { *x = GatewayHeartbeat{} - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[182] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14620,7 +14747,7 @@ func (x *GatewayHeartbeat) String() string { func (*GatewayHeartbeat) ProtoMessage() {} func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[182] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14633,7 +14760,7 @@ func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayHeartbeat.ProtoReflect.Descriptor instead. func (*GatewayHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{180} + return file_openshell_proto_rawDescGZIP(), []int{182} } // Terminal result reported before the supervisor shuts down. A successful RPC @@ -14650,7 +14777,7 @@ type ReportMainProcessExitRequest struct { func (x *ReportMainProcessExitRequest) Reset() { *x = ReportMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[183] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14662,7 +14789,7 @@ func (x *ReportMainProcessExitRequest) String() string { func (*ReportMainProcessExitRequest) ProtoMessage() {} func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[183] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14675,7 +14802,7 @@ func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{181} + return file_openshell_proto_rawDescGZIP(), []int{183} } func (x *ReportMainProcessExitRequest) GetSandboxId() string { @@ -14707,7 +14834,7 @@ type ReportMainProcessExitResponse struct { func (x *ReportMainProcessExitResponse) Reset() { *x = ReportMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[184] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14719,7 +14846,7 @@ func (x *ReportMainProcessExitResponse) String() string { func (*ReportMainProcessExitResponse) ProtoMessage() {} func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[184] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14732,7 +14859,7 @@ func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{182} + return file_openshell_proto_rawDescGZIP(), []int{184} } // Terminal-delivery completion reported after all expected foreground SSH @@ -14747,7 +14874,7 @@ type FinalizeMainProcessExitRequest struct { func (x *FinalizeMainProcessExitRequest) Reset() { *x = FinalizeMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[185] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14759,7 +14886,7 @@ func (x *FinalizeMainProcessExitRequest) String() string { func (*FinalizeMainProcessExitRequest) ProtoMessage() {} func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[185] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14772,7 +14899,7 @@ func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{183} + return file_openshell_proto_rawDescGZIP(), []int{185} } func (x *FinalizeMainProcessExitRequest) GetSandboxId() string { @@ -14797,7 +14924,7 @@ type FinalizeMainProcessExitResponse struct { func (x *FinalizeMainProcessExitResponse) Reset() { *x = FinalizeMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[186] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14809,7 +14936,7 @@ func (x *FinalizeMainProcessExitResponse) String() string { func (*FinalizeMainProcessExitResponse) ProtoMessage() {} func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[186] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14822,7 +14949,7 @@ func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{184} + return file_openshell_proto_rawDescGZIP(), []int{186} } // Gateway requests the supervisor to open a relay channel. @@ -14851,7 +14978,7 @@ type RelayOpen struct { func (x *RelayOpen) Reset() { *x = RelayOpen{} - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[187] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14863,7 +14990,7 @@ func (x *RelayOpen) String() string { func (*RelayOpen) ProtoMessage() {} func (x *RelayOpen) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[187] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14876,7 +15003,7 @@ func (x *RelayOpen) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpen.ProtoReflect.Descriptor instead. func (*RelayOpen) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{185} + return file_openshell_proto_rawDescGZIP(), []int{187} } func (x *RelayOpen) GetChannelId() string { @@ -14943,7 +15070,7 @@ type SshRelayTarget struct { func (x *SshRelayTarget) Reset() { *x = SshRelayTarget{} - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[188] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14955,7 +15082,7 @@ func (x *SshRelayTarget) String() string { func (*SshRelayTarget) ProtoMessage() {} func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[188] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14968,7 +15095,7 @@ func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use SshRelayTarget.ProtoReflect.Descriptor instead. func (*SshRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{186} + return file_openshell_proto_rawDescGZIP(), []int{188} } // TCP target dialed by the supervisor from inside the sandbox. @@ -14984,7 +15111,7 @@ type TcpRelayTarget struct { func (x *TcpRelayTarget) Reset() { *x = TcpRelayTarget{} - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[189] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14996,7 +15123,7 @@ func (x *TcpRelayTarget) String() string { func (*TcpRelayTarget) ProtoMessage() {} func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[189] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15009,7 +15136,7 @@ func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpRelayTarget.ProtoReflect.Descriptor instead. func (*TcpRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{187} + return file_openshell_proto_rawDescGZIP(), []int{189} } func (x *TcpRelayTarget) GetHost() string { @@ -15037,7 +15164,7 @@ type RelayInit struct { func (x *RelayInit) Reset() { *x = RelayInit{} - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[190] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15049,7 +15176,7 @@ func (x *RelayInit) String() string { func (*RelayInit) ProtoMessage() {} func (x *RelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[190] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15062,7 +15189,7 @@ func (x *RelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayInit.ProtoReflect.Descriptor instead. func (*RelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{188} + return file_openshell_proto_rawDescGZIP(), []int{190} } func (x *RelayInit) GetChannelId() string { @@ -15089,7 +15216,7 @@ type RelayFrame struct { func (x *RelayFrame) Reset() { *x = RelayFrame{} - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[191] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15101,7 +15228,7 @@ func (x *RelayFrame) String() string { func (*RelayFrame) ProtoMessage() {} func (x *RelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[191] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15114,7 +15241,7 @@ func (x *RelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayFrame.ProtoReflect.Descriptor instead. func (*RelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{189} + return file_openshell_proto_rawDescGZIP(), []int{191} } func (x *RelayFrame) GetPayload() isRelayFrame_Payload { @@ -15174,7 +15301,7 @@ type PeerRelayInit struct { func (x *PeerRelayInit) Reset() { *x = PeerRelayInit{} - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[192] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15186,7 +15313,7 @@ func (x *PeerRelayInit) String() string { func (*PeerRelayInit) ProtoMessage() {} func (x *PeerRelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[192] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15199,7 +15326,7 @@ func (x *PeerRelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerRelayInit.ProtoReflect.Descriptor instead. func (*PeerRelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{190} + return file_openshell_proto_rawDescGZIP(), []int{192} } func (x *PeerRelayInit) GetSandboxId() string { @@ -15237,7 +15364,7 @@ type PeerRelayFrame struct { func (x *PeerRelayFrame) Reset() { *x = PeerRelayFrame{} - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15249,7 +15376,7 @@ func (x *PeerRelayFrame) String() string { func (*PeerRelayFrame) ProtoMessage() {} func (x *PeerRelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[193] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15262,7 +15389,7 @@ func (x *PeerRelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerRelayFrame.ProtoReflect.Descriptor instead. func (*PeerRelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{191} + return file_openshell_proto_rawDescGZIP(), []int{193} } func (x *PeerRelayFrame) GetPayload() isPeerRelayFrame_Payload { @@ -15317,7 +15444,7 @@ type PeerConfigSandboxTarget struct { func (x *PeerConfigSandboxTarget) Reset() { *x = PeerConfigSandboxTarget{} - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15329,7 +15456,7 @@ func (x *PeerConfigSandboxTarget) String() string { func (*PeerConfigSandboxTarget) ProtoMessage() {} func (x *PeerConfigSandboxTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[194] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15342,7 +15469,7 @@ func (x *PeerConfigSandboxTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerConfigSandboxTarget.ProtoReflect.Descriptor instead. func (*PeerConfigSandboxTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{192} + return file_openshell_proto_rawDescGZIP(), []int{194} } func (x *PeerConfigSandboxTarget) GetSandboxId() string { @@ -15370,7 +15497,7 @@ type PeerConfigProviderTarget struct { func (x *PeerConfigProviderTarget) Reset() { *x = PeerConfigProviderTarget{} - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15382,7 +15509,7 @@ func (x *PeerConfigProviderTarget) String() string { func (*PeerConfigProviderTarget) ProtoMessage() {} func (x *PeerConfigProviderTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[195] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15395,7 +15522,7 @@ func (x *PeerConfigProviderTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerConfigProviderTarget.ProtoReflect.Descriptor instead. func (*PeerConfigProviderTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{193} + return file_openshell_proto_rawDescGZIP(), []int{195} } func (x *PeerConfigProviderTarget) GetWorkspace() string { @@ -15427,7 +15554,7 @@ type PeerNotifyConfigUpdateRequest struct { func (x *PeerNotifyConfigUpdateRequest) Reset() { *x = PeerNotifyConfigUpdateRequest{} - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15439,7 +15566,7 @@ func (x *PeerNotifyConfigUpdateRequest) String() string { func (*PeerNotifyConfigUpdateRequest) ProtoMessage() {} func (x *PeerNotifyConfigUpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[196] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15452,7 +15579,7 @@ func (x *PeerNotifyConfigUpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerNotifyConfigUpdateRequest.ProtoReflect.Descriptor instead. func (*PeerNotifyConfigUpdateRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{194} + return file_openshell_proto_rawDescGZIP(), []int{196} } func (x *PeerNotifyConfigUpdateRequest) GetScope() isPeerNotifyConfigUpdateRequest_Scope { @@ -15536,7 +15663,7 @@ type PeerNotifyConfigUpdateResponse struct { func (x *PeerNotifyConfigUpdateResponse) Reset() { *x = PeerNotifyConfigUpdateResponse{} - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15548,7 +15675,7 @@ func (x *PeerNotifyConfigUpdateResponse) String() string { func (*PeerNotifyConfigUpdateResponse) ProtoMessage() {} func (x *PeerNotifyConfigUpdateResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[197] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15561,7 +15688,7 @@ func (x *PeerNotifyConfigUpdateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerNotifyConfigUpdateResponse.ProtoReflect.Descriptor instead. func (*PeerNotifyConfigUpdateResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{195} + return file_openshell_proto_rawDescGZIP(), []int{197} } func (x *PeerNotifyConfigUpdateResponse) GetStaleOwner() bool { @@ -15586,7 +15713,7 @@ type RelayOpenResult struct { func (x *RelayOpenResult) Reset() { *x = RelayOpenResult{} - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15598,7 +15725,7 @@ func (x *RelayOpenResult) String() string { func (*RelayOpenResult) ProtoMessage() {} func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[198] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15611,7 +15738,7 @@ func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpenResult.ProtoReflect.Descriptor instead. func (*RelayOpenResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{196} + return file_openshell_proto_rawDescGZIP(), []int{198} } func (x *RelayOpenResult) GetChannelId() string { @@ -15648,7 +15775,7 @@ type RelayClose struct { func (x *RelayClose) Reset() { *x = RelayClose{} - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15660,7 +15787,7 @@ func (x *RelayClose) String() string { func (*RelayClose) ProtoMessage() {} func (x *RelayClose) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[199] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15673,7 +15800,7 @@ func (x *RelayClose) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayClose.ProtoReflect.Descriptor instead. func (*RelayClose) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{197} + return file_openshell_proto_rawDescGZIP(), []int{199} } func (x *RelayClose) GetChannelId() string { @@ -15707,7 +15834,7 @@ type L7RequestSample struct { func (x *L7RequestSample) Reset() { *x = L7RequestSample{} - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[200] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15719,7 +15846,7 @@ func (x *L7RequestSample) String() string { func (*L7RequestSample) ProtoMessage() {} func (x *L7RequestSample) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[200] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15732,7 +15859,7 @@ func (x *L7RequestSample) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RequestSample.ProtoReflect.Descriptor instead. func (*L7RequestSample) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{198} + return file_openshell_proto_rawDescGZIP(), []int{200} } func (x *L7RequestSample) GetMethod() string { @@ -15806,7 +15933,7 @@ type DenialSummary struct { func (x *DenialSummary) Reset() { *x = DenialSummary{} - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[201] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15818,7 +15945,7 @@ func (x *DenialSummary) String() string { func (*DenialSummary) ProtoMessage() {} func (x *DenialSummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[201] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15831,7 +15958,7 @@ func (x *DenialSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialSummary.ProtoReflect.Descriptor instead. func (*DenialSummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{199} + return file_openshell_proto_rawDescGZIP(), []int{201} } func (x *DenialSummary) GetSandboxId() string { @@ -15966,7 +16093,7 @@ type DenialGroupCount struct { func (x *DenialGroupCount) Reset() { *x = DenialGroupCount{} - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[202] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15978,7 +16105,7 @@ func (x *DenialGroupCount) String() string { func (*DenialGroupCount) ProtoMessage() {} func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[202] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15991,7 +16118,7 @@ func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialGroupCount.ProtoReflect.Descriptor instead. func (*DenialGroupCount) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{200} + return file_openshell_proto_rawDescGZIP(), []int{202} } func (x *DenialGroupCount) GetDenyGroup() string { @@ -16024,7 +16151,7 @@ type NetworkActivitySummary struct { func (x *NetworkActivitySummary) Reset() { *x = NetworkActivitySummary{} - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[203] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16036,7 +16163,7 @@ func (x *NetworkActivitySummary) String() string { func (*NetworkActivitySummary) ProtoMessage() {} func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[203] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16049,7 +16176,7 @@ func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkActivitySummary.ProtoReflect.Descriptor instead. func (*NetworkActivitySummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{201} + return file_openshell_proto_rawDescGZIP(), []int{203} } func (x *NetworkActivitySummary) GetNetworkActivityCount() uint32 { @@ -16137,7 +16264,7 @@ type PolicyChunk struct { func (x *PolicyChunk) Reset() { *x = PolicyChunk{} - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[204] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16149,7 +16276,7 @@ func (x *PolicyChunk) String() string { func (*PolicyChunk) ProtoMessage() {} func (x *PolicyChunk) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[204] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16162,7 +16289,7 @@ func (x *PolicyChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyChunk.ProtoReflect.Descriptor instead. func (*PolicyChunk) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{202} + return file_openshell_proto_rawDescGZIP(), []int{204} } func (x *PolicyChunk) GetId() string { @@ -16350,7 +16477,7 @@ type DraftPolicyUpdate struct { func (x *DraftPolicyUpdate) Reset() { *x = DraftPolicyUpdate{} - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[205] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16362,7 +16489,7 @@ func (x *DraftPolicyUpdate) String() string { func (*DraftPolicyUpdate) ProtoMessage() {} func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[205] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16375,7 +16502,7 @@ func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftPolicyUpdate.ProtoReflect.Descriptor instead. func (*DraftPolicyUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{203} + return file_openshell_proto_rawDescGZIP(), []int{205} } func (x *DraftPolicyUpdate) GetDraftVersion() uint64 { @@ -16434,7 +16561,7 @@ type SubmitPolicyAnalysisRequest struct { func (x *SubmitPolicyAnalysisRequest) Reset() { *x = SubmitPolicyAnalysisRequest{} - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[206] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16446,7 +16573,7 @@ func (x *SubmitPolicyAnalysisRequest) String() string { func (*SubmitPolicyAnalysisRequest) ProtoMessage() {} func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[206] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16459,7 +16586,7 @@ func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisRequest.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{204} + return file_openshell_proto_rawDescGZIP(), []int{206} } func (x *SubmitPolicyAnalysisRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16522,7 +16649,7 @@ type SubmitPolicyAnalysisResponse struct { func (x *SubmitPolicyAnalysisResponse) Reset() { *x = SubmitPolicyAnalysisResponse{} - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[207] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16534,7 +16661,7 @@ func (x *SubmitPolicyAnalysisResponse) String() string { func (*SubmitPolicyAnalysisResponse) ProtoMessage() {} func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[207] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16547,7 +16674,7 @@ func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisResponse.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{205} + return file_openshell_proto_rawDescGZIP(), []int{207} } func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunks() uint32 { @@ -16592,7 +16719,7 @@ type GetDraftPolicyRequest struct { func (x *GetDraftPolicyRequest) Reset() { *x = GetDraftPolicyRequest{} - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[208] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16604,7 +16731,7 @@ func (x *GetDraftPolicyRequest) String() string { func (*GetDraftPolicyRequest) ProtoMessage() {} func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[208] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16617,7 +16744,7 @@ func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyRequest.ProtoReflect.Descriptor instead. func (*GetDraftPolicyRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{206} + return file_openshell_proto_rawDescGZIP(), []int{208} } func (x *GetDraftPolicyRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16657,7 +16784,7 @@ type GetDraftPolicyResponse struct { func (x *GetDraftPolicyResponse) Reset() { *x = GetDraftPolicyResponse{} - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[209] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16669,7 +16796,7 @@ func (x *GetDraftPolicyResponse) String() string { func (*GetDraftPolicyResponse) ProtoMessage() {} func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[209] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16682,7 +16809,7 @@ func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyResponse.ProtoReflect.Descriptor instead. func (*GetDraftPolicyResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{207} + return file_openshell_proto_rawDescGZIP(), []int{209} } func (x *GetDraftPolicyResponse) GetChunks() []*PolicyChunk { @@ -16733,7 +16860,7 @@ type ApproveDraftChunkRequest struct { func (x *ApproveDraftChunkRequest) Reset() { *x = ApproveDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[210] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16745,7 +16872,7 @@ func (x *ApproveDraftChunkRequest) String() string { func (*ApproveDraftChunkRequest) ProtoMessage() {} func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[210] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16758,7 +16885,7 @@ func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkRequest.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{208} + return file_openshell_proto_rawDescGZIP(), []int{210} } func (x *ApproveDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16808,7 +16935,7 @@ type ApproveDraftChunkResponse struct { func (x *ApproveDraftChunkResponse) Reset() { *x = ApproveDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[211] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16820,7 +16947,7 @@ func (x *ApproveDraftChunkResponse) String() string { func (*ApproveDraftChunkResponse) ProtoMessage() {} func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[211] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16833,7 +16960,7 @@ func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkResponse.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{209} + return file_openshell_proto_rawDescGZIP(), []int{211} } func (x *ApproveDraftChunkResponse) GetPolicyVersion() uint32 { @@ -16869,7 +16996,7 @@ type RejectDraftChunkRequest struct { func (x *RejectDraftChunkRequest) Reset() { *x = RejectDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[212] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16881,7 +17008,7 @@ func (x *RejectDraftChunkRequest) String() string { func (*RejectDraftChunkRequest) ProtoMessage() {} func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[212] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16894,7 +17021,7 @@ func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkRequest.ProtoReflect.Descriptor instead. func (*RejectDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{210} + return file_openshell_proto_rawDescGZIP(), []int{212} } func (x *RejectDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16940,7 +17067,7 @@ type RejectDraftChunkResponse struct { func (x *RejectDraftChunkResponse) Reset() { *x = RejectDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[213] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16952,7 +17079,7 @@ func (x *RejectDraftChunkResponse) String() string { func (*RejectDraftChunkResponse) ProtoMessage() {} func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[213] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16965,7 +17092,7 @@ func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkResponse.ProtoReflect.Descriptor instead. func (*RejectDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{211} + return file_openshell_proto_rawDescGZIP(), []int{213} } // Approve all pending chunks. @@ -16979,7 +17106,7 @@ type DraftChunkApproval struct { func (x *DraftChunkApproval) Reset() { *x = DraftChunkApproval{} - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[214] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16991,7 +17118,7 @@ func (x *DraftChunkApproval) String() string { func (*DraftChunkApproval) ProtoMessage() {} func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[214] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17004,7 +17131,7 @@ func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftChunkApproval.ProtoReflect.Descriptor instead. func (*DraftChunkApproval) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{212} + return file_openshell_proto_rawDescGZIP(), []int{214} } func (x *DraftChunkApproval) GetChunkId() string { @@ -17040,7 +17167,7 @@ type ApproveAllDraftChunksRequest struct { func (x *ApproveAllDraftChunksRequest) Reset() { *x = ApproveAllDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[215] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17052,7 +17179,7 @@ func (x *ApproveAllDraftChunksRequest) String() string { func (*ApproveAllDraftChunksRequest) ProtoMessage() {} func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[215] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17065,7 +17192,7 @@ func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{213} + return file_openshell_proto_rawDescGZIP(), []int{215} } func (x *ApproveAllDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17120,7 +17247,7 @@ type ApproveAllDraftChunksResponse struct { func (x *ApproveAllDraftChunksResponse) Reset() { *x = ApproveAllDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[216] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17132,7 +17259,7 @@ func (x *ApproveAllDraftChunksResponse) String() string { func (*ApproveAllDraftChunksResponse) ProtoMessage() {} func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[216] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17145,7 +17272,7 @@ func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{214} + return file_openshell_proto_rawDescGZIP(), []int{216} } func (x *ApproveAllDraftChunksResponse) GetPolicyVersion() uint32 { @@ -17195,7 +17322,7 @@ type EditDraftChunkRequest struct { func (x *EditDraftChunkRequest) Reset() { *x = EditDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[217] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17207,7 +17334,7 @@ func (x *EditDraftChunkRequest) String() string { func (*EditDraftChunkRequest) ProtoMessage() {} func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[217] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17220,7 +17347,7 @@ func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkRequest.ProtoReflect.Descriptor instead. func (*EditDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{215} + return file_openshell_proto_rawDescGZIP(), []int{217} } func (x *EditDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17266,7 +17393,7 @@ type EditDraftChunkResponse struct { func (x *EditDraftChunkResponse) Reset() { *x = EditDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[218] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17278,7 +17405,7 @@ func (x *EditDraftChunkResponse) String() string { func (*EditDraftChunkResponse) ProtoMessage() {} func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[218] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17291,7 +17418,7 @@ func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkResponse.ProtoReflect.Descriptor instead. func (*EditDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{216} + return file_openshell_proto_rawDescGZIP(), []int{218} } // Reverse an approval (remove merged rule from active policy). @@ -17311,7 +17438,7 @@ type UndoDraftChunkRequest struct { func (x *UndoDraftChunkRequest) Reset() { *x = UndoDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[219] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17323,7 +17450,7 @@ func (x *UndoDraftChunkRequest) String() string { func (*UndoDraftChunkRequest) ProtoMessage() {} func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[219] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17336,7 +17463,7 @@ func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkRequest.ProtoReflect.Descriptor instead. func (*UndoDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{217} + return file_openshell_proto_rawDescGZIP(), []int{219} } func (x *UndoDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17379,7 +17506,7 @@ type UndoDraftChunkResponse struct { func (x *UndoDraftChunkResponse) Reset() { *x = UndoDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[220] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17391,7 +17518,7 @@ func (x *UndoDraftChunkResponse) String() string { func (*UndoDraftChunkResponse) ProtoMessage() {} func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[220] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17404,7 +17531,7 @@ func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkResponse.ProtoReflect.Descriptor instead. func (*UndoDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{218} + return file_openshell_proto_rawDescGZIP(), []int{220} } func (x *UndoDraftChunkResponse) GetPolicyVersion() uint32 { @@ -17436,7 +17563,7 @@ type ClearDraftChunksRequest struct { func (x *ClearDraftChunksRequest) Reset() { *x = ClearDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[221] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17448,7 +17575,7 @@ func (x *ClearDraftChunksRequest) String() string { func (*ClearDraftChunksRequest) ProtoMessage() {} func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[221] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17461,7 +17588,7 @@ func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ClearDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{219} + return file_openshell_proto_rawDescGZIP(), []int{221} } func (x *ClearDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17495,7 +17622,7 @@ type ClearDraftChunksResponse struct { func (x *ClearDraftChunksResponse) Reset() { *x = ClearDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[222] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17507,7 +17634,7 @@ func (x *ClearDraftChunksResponse) String() string { func (*ClearDraftChunksResponse) ProtoMessage() {} func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[222] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17520,7 +17647,7 @@ func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ClearDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{220} + return file_openshell_proto_rawDescGZIP(), []int{222} } func (x *ClearDraftChunksResponse) GetChunksCleared() uint32 { @@ -17542,7 +17669,7 @@ type GetDraftHistoryRequest struct { func (x *GetDraftHistoryRequest) Reset() { *x = GetDraftHistoryRequest{} - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[223] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17554,7 +17681,7 @@ func (x *GetDraftHistoryRequest) String() string { func (*GetDraftHistoryRequest) ProtoMessage() {} func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[223] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17567,7 +17694,7 @@ func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryRequest.ProtoReflect.Descriptor instead. func (*GetDraftHistoryRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{221} + return file_openshell_proto_rawDescGZIP(), []int{223} } func (x *GetDraftHistoryRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17601,7 +17728,7 @@ type DraftHistoryEntry struct { func (x *DraftHistoryEntry) Reset() { *x = DraftHistoryEntry{} - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[224] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17613,7 +17740,7 @@ func (x *DraftHistoryEntry) String() string { func (*DraftHistoryEntry) ProtoMessage() {} func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[224] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17626,7 +17753,7 @@ func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftHistoryEntry.ProtoReflect.Descriptor instead. func (*DraftHistoryEntry) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{222} + return file_openshell_proto_rawDescGZIP(), []int{224} } func (x *DraftHistoryEntry) GetEventTime() *timestamppb.Timestamp { @@ -17667,7 +17794,7 @@ type GetDraftHistoryResponse struct { func (x *GetDraftHistoryResponse) Reset() { *x = GetDraftHistoryResponse{} - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[225] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17679,7 +17806,7 @@ func (x *GetDraftHistoryResponse) String() string { func (*GetDraftHistoryResponse) ProtoMessage() {} func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[225] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17692,7 +17819,7 @@ func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryResponse.ProtoReflect.Descriptor instead. func (*GetDraftHistoryResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{223} + return file_openshell_proto_rawDescGZIP(), []int{225} } func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry { @@ -17717,7 +17844,7 @@ type CreateWorkspaceRequest struct { func (x *CreateWorkspaceRequest) Reset() { *x = CreateWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[226] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17729,7 +17856,7 @@ func (x *CreateWorkspaceRequest) String() string { func (*CreateWorkspaceRequest) ProtoMessage() {} func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[226] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17742,7 +17869,7 @@ func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceRequest.ProtoReflect.Descriptor instead. func (*CreateWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{224} + return file_openshell_proto_rawDescGZIP(), []int{226} } func (x *CreateWorkspaceRequest) GetName() string { @@ -17776,7 +17903,7 @@ type CreateWorkspaceResponse struct { func (x *CreateWorkspaceResponse) Reset() { *x = CreateWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[227] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17788,7 +17915,7 @@ func (x *CreateWorkspaceResponse) String() string { func (*CreateWorkspaceResponse) ProtoMessage() {} func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[227] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17801,7 +17928,7 @@ func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceResponse.ProtoReflect.Descriptor instead. func (*CreateWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{225} + return file_openshell_proto_rawDescGZIP(), []int{227} } func (x *CreateWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -17822,7 +17949,7 @@ type GetWorkspaceRequest struct { func (x *GetWorkspaceRequest) Reset() { *x = GetWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[228] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17834,7 +17961,7 @@ func (x *GetWorkspaceRequest) String() string { func (*GetWorkspaceRequest) ProtoMessage() {} func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[228] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17847,7 +17974,7 @@ func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceRequest.ProtoReflect.Descriptor instead. func (*GetWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{226} + return file_openshell_proto_rawDescGZIP(), []int{228} } func (x *GetWorkspaceRequest) GetName() string { @@ -17867,7 +17994,7 @@ type GetWorkspaceResponse struct { func (x *GetWorkspaceResponse) Reset() { *x = GetWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[229] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17879,7 +18006,7 @@ func (x *GetWorkspaceResponse) String() string { func (*GetWorkspaceResponse) ProtoMessage() {} func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[229] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17892,7 +18019,7 @@ func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceResponse.ProtoReflect.Descriptor instead. func (*GetWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{227} + return file_openshell_proto_rawDescGZIP(), []int{229} } func (x *GetWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -17919,7 +18046,7 @@ type ListWorkspacesRequest struct { func (x *ListWorkspacesRequest) Reset() { *x = ListWorkspacesRequest{} - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[230] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17931,7 +18058,7 @@ func (x *ListWorkspacesRequest) String() string { func (*ListWorkspacesRequest) ProtoMessage() {} func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[230] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17944,7 +18071,7 @@ func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesRequest.ProtoReflect.Descriptor instead. func (*ListWorkspacesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{228} + return file_openshell_proto_rawDescGZIP(), []int{230} } func (x *ListWorkspacesRequest) GetPageSize() int32 { @@ -17980,7 +18107,7 @@ type ListWorkspacesResponse struct { func (x *ListWorkspacesResponse) Reset() { *x = ListWorkspacesResponse{} - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[231] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17992,7 +18119,7 @@ func (x *ListWorkspacesResponse) String() string { func (*ListWorkspacesResponse) ProtoMessage() {} func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[231] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18005,7 +18132,7 @@ func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesResponse.ProtoReflect.Descriptor instead. func (*ListWorkspacesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{229} + return file_openshell_proto_rawDescGZIP(), []int{231} } func (x *ListWorkspacesResponse) GetWorkspaces() []*datamodelv1.Workspace { @@ -18036,7 +18163,7 @@ type DeleteWorkspaceRequest struct { func (x *DeleteWorkspaceRequest) Reset() { *x = DeleteWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[232] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18048,7 +18175,7 @@ func (x *DeleteWorkspaceRequest) String() string { func (*DeleteWorkspaceRequest) ProtoMessage() {} func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[232] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18061,7 +18188,7 @@ func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{230} + return file_openshell_proto_rawDescGZIP(), []int{232} } func (x *DeleteWorkspaceRequest) GetName() string { @@ -18095,7 +18222,7 @@ type DeleteWorkspaceResponse struct { func (x *DeleteWorkspaceResponse) Reset() { *x = DeleteWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[231] + mi := &file_openshell_proto_msgTypes[233] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18107,7 +18234,7 @@ func (x *DeleteWorkspaceResponse) String() string { func (*DeleteWorkspaceResponse) ProtoMessage() {} func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[231] + mi := &file_openshell_proto_msgTypes[233] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18120,7 +18247,7 @@ func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceResponse.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{231} + return file_openshell_proto_rawDescGZIP(), []int{233} } func (x *DeleteWorkspaceResponse) GetOutcome() DeletionOutcome { @@ -18144,7 +18271,7 @@ type WorkspaceMember struct { func (x *WorkspaceMember) Reset() { *x = WorkspaceMember{} - mi := &file_openshell_proto_msgTypes[232] + mi := &file_openshell_proto_msgTypes[234] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18156,7 +18283,7 @@ func (x *WorkspaceMember) String() string { func (*WorkspaceMember) ProtoMessage() {} func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[232] + mi := &file_openshell_proto_msgTypes[234] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18169,7 +18296,7 @@ func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkspaceMember.ProtoReflect.Descriptor instead. func (*WorkspaceMember) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{232} + return file_openshell_proto_rawDescGZIP(), []int{234} } func (x *WorkspaceMember) GetMetadata() *datamodelv1.ObjectMeta { @@ -18210,7 +18337,7 @@ type AddWorkspaceMemberRequest struct { func (x *AddWorkspaceMemberRequest) Reset() { *x = AddWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[233] + mi := &file_openshell_proto_msgTypes[235] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18222,7 +18349,7 @@ func (x *AddWorkspaceMemberRequest) String() string { func (*AddWorkspaceMemberRequest) ProtoMessage() {} func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[233] + mi := &file_openshell_proto_msgTypes[235] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18235,7 +18362,7 @@ func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{233} + return file_openshell_proto_rawDescGZIP(), []int{235} } func (x *AddWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18276,7 +18403,7 @@ type AddWorkspaceMemberResponse struct { func (x *AddWorkspaceMemberResponse) Reset() { *x = AddWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[234] + mi := &file_openshell_proto_msgTypes[236] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18288,7 +18415,7 @@ func (x *AddWorkspaceMemberResponse) String() string { func (*AddWorkspaceMemberResponse) ProtoMessage() {} func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[234] + mi := &file_openshell_proto_msgTypes[236] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18301,7 +18428,7 @@ func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{234} + return file_openshell_proto_rawDescGZIP(), []int{236} } func (x *AddWorkspaceMemberResponse) GetMember() *WorkspaceMember { @@ -18327,7 +18454,7 @@ type RemoveWorkspaceMemberRequest struct { func (x *RemoveWorkspaceMemberRequest) Reset() { *x = RemoveWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[235] + mi := &file_openshell_proto_msgTypes[237] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18339,7 +18466,7 @@ func (x *RemoveWorkspaceMemberRequest) String() string { func (*RemoveWorkspaceMemberRequest) ProtoMessage() {} func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[235] + mi := &file_openshell_proto_msgTypes[237] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18352,7 +18479,7 @@ func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{235} + return file_openshell_proto_rawDescGZIP(), []int{237} } func (x *RemoveWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18393,7 +18520,7 @@ type RemoveWorkspaceMemberResponse struct { func (x *RemoveWorkspaceMemberResponse) Reset() { *x = RemoveWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[236] + mi := &file_openshell_proto_msgTypes[238] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18405,7 +18532,7 @@ func (x *RemoveWorkspaceMemberResponse) String() string { func (*RemoveWorkspaceMemberResponse) ProtoMessage() {} func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[236] + mi := &file_openshell_proto_msgTypes[238] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18418,7 +18545,7 @@ func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{236} + return file_openshell_proto_rawDescGZIP(), []int{238} } func (x *RemoveWorkspaceMemberResponse) GetOutcome() DeletionOutcome { @@ -18445,7 +18572,7 @@ type ListWorkspaceMembersRequest struct { func (x *ListWorkspaceMembersRequest) Reset() { *x = ListWorkspaceMembersRequest{} - mi := &file_openshell_proto_msgTypes[237] + mi := &file_openshell_proto_msgTypes[239] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18457,7 +18584,7 @@ func (x *ListWorkspaceMembersRequest) String() string { func (*ListWorkspaceMembersRequest) ProtoMessage() {} func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[237] + mi := &file_openshell_proto_msgTypes[239] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18470,7 +18597,7 @@ func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersRequest.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{237} + return file_openshell_proto_rawDescGZIP(), []int{239} } func (x *ListWorkspaceMembersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -18506,7 +18633,7 @@ type ListWorkspaceMembersResponse struct { func (x *ListWorkspaceMembersResponse) Reset() { *x = ListWorkspaceMembersResponse{} - mi := &file_openshell_proto_msgTypes[238] + mi := &file_openshell_proto_msgTypes[240] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18518,7 +18645,7 @@ func (x *ListWorkspaceMembersResponse) String() string { func (*ListWorkspaceMembersResponse) ProtoMessage() {} func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[238] + mi := &file_openshell_proto_msgTypes[240] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18531,7 +18658,7 @@ func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersResponse.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{238} + return file_openshell_proto_rawDescGZIP(), []int{240} } func (x *ListWorkspaceMembersResponse) GetMembers() []*WorkspaceMember { @@ -18566,7 +18693,7 @@ type ExtensionServiceCredential struct { func (x *ExtensionServiceCredential) Reset() { *x = ExtensionServiceCredential{} - mi := &file_openshell_proto_msgTypes[239] + mi := &file_openshell_proto_msgTypes[241] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18578,7 +18705,7 @@ func (x *ExtensionServiceCredential) String() string { func (*ExtensionServiceCredential) ProtoMessage() {} func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[239] + mi := &file_openshell_proto_msgTypes[241] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18591,7 +18718,7 @@ func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionServiceCredential.ProtoReflect.Descriptor instead. func (*ExtensionServiceCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{239} + return file_openshell_proto_rawDescGZIP(), []int{241} } func (x *ExtensionServiceCredential) GetServiceName() string { @@ -18631,7 +18758,7 @@ type EndpointObservation struct { func (x *EndpointObservation) Reset() { *x = EndpointObservation{} - mi := &file_openshell_proto_msgTypes[240] + mi := &file_openshell_proto_msgTypes[242] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18643,7 +18770,7 @@ func (x *EndpointObservation) String() string { func (*EndpointObservation) ProtoMessage() {} func (x *EndpointObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[240] + mi := &file_openshell_proto_msgTypes[242] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18656,7 +18783,7 @@ func (x *EndpointObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointObservation.ProtoReflect.Descriptor instead. func (*EndpointObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{240} + return file_openshell_proto_rawDescGZIP(), []int{242} } func (x *EndpointObservation) GetEndpointId() string { @@ -18709,7 +18836,7 @@ type ReportEndpointStatusRequest struct { func (x *ReportEndpointStatusRequest) Reset() { *x = ReportEndpointStatusRequest{} - mi := &file_openshell_proto_msgTypes[241] + mi := &file_openshell_proto_msgTypes[243] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18721,7 +18848,7 @@ func (x *ReportEndpointStatusRequest) String() string { func (*ReportEndpointStatusRequest) ProtoMessage() {} func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[241] + mi := &file_openshell_proto_msgTypes[243] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18734,7 +18861,7 @@ func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusRequest.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{241} + return file_openshell_proto_rawDescGZIP(), []int{243} } func (x *ReportEndpointStatusRequest) GetSandboxId() string { @@ -18803,7 +18930,7 @@ type TokenGrantStatus struct { func (x *TokenGrantStatus) Reset() { *x = TokenGrantStatus{} - mi := &file_openshell_proto_msgTypes[242] + mi := &file_openshell_proto_msgTypes[244] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18815,7 +18942,7 @@ func (x *TokenGrantStatus) String() string { func (*TokenGrantStatus) ProtoMessage() {} func (x *TokenGrantStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[242] + mi := &file_openshell_proto_msgTypes[244] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18828,7 +18955,7 @@ func (x *TokenGrantStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use TokenGrantStatus.ProtoReflect.Descriptor instead. func (*TokenGrantStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{242} + return file_openshell_proto_rawDescGZIP(), []int{244} } func (x *TokenGrantStatus) GetLastFailure() *TokenGrantFailureObservation { @@ -18855,7 +18982,7 @@ type TokenGrantFailureObservation struct { func (x *TokenGrantFailureObservation) Reset() { *x = TokenGrantFailureObservation{} - mi := &file_openshell_proto_msgTypes[243] + mi := &file_openshell_proto_msgTypes[245] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18867,7 +18994,7 @@ func (x *TokenGrantFailureObservation) String() string { func (*TokenGrantFailureObservation) ProtoMessage() {} func (x *TokenGrantFailureObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[243] + mi := &file_openshell_proto_msgTypes[245] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18880,7 +19007,7 @@ func (x *TokenGrantFailureObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use TokenGrantFailureObservation.ProtoReflect.Descriptor instead. func (*TokenGrantFailureObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{243} + return file_openshell_proto_rawDescGZIP(), []int{245} } func (x *TokenGrantFailureObservation) GetDestinationHost() string { @@ -18913,7 +19040,7 @@ type ReportEndpointStatusResponse struct { func (x *ReportEndpointStatusResponse) Reset() { *x = ReportEndpointStatusResponse{} - mi := &file_openshell_proto_msgTypes[244] + mi := &file_openshell_proto_msgTypes[246] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18925,7 +19052,7 @@ func (x *ReportEndpointStatusResponse) String() string { func (*ReportEndpointStatusResponse) ProtoMessage() {} func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[244] + mi := &file_openshell_proto_msgTypes[246] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18938,7 +19065,7 @@ func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusResponse.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{244} + return file_openshell_proto_rawDescGZIP(), []int{246} } // A configured endpoint and its last accepted network result in one record. @@ -18972,7 +19099,7 @@ type EndpointStatus struct { func (x *EndpointStatus) Reset() { *x = EndpointStatus{} - mi := &file_openshell_proto_msgTypes[245] + mi := &file_openshell_proto_msgTypes[247] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18984,7 +19111,7 @@ func (x *EndpointStatus) String() string { func (*EndpointStatus) ProtoMessage() {} func (x *EndpointStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[245] + mi := &file_openshell_proto_msgTypes[247] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18997,7 +19124,7 @@ func (x *EndpointStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointStatus.ProtoReflect.Descriptor instead. func (*EndpointStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{245} + return file_openshell_proto_rawDescGZIP(), []int{247} } func (x *EndpointStatus) GetEndpointId() string { @@ -19092,7 +19219,7 @@ type SandboxProvisioning struct { func (x *SandboxProvisioning) Reset() { *x = SandboxProvisioning{} - mi := &file_openshell_proto_msgTypes[246] + mi := &file_openshell_proto_msgTypes[248] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19104,7 +19231,7 @@ func (x *SandboxProvisioning) String() string { func (*SandboxProvisioning) ProtoMessage() {} func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[246] + mi := &file_openshell_proto_msgTypes[248] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19117,7 +19244,7 @@ func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxProvisioning.ProtoReflect.Descriptor instead. func (*SandboxProvisioning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{246} + return file_openshell_proto_rawDescGZIP(), []int{248} } func (x *SandboxProvisioning) GetAttemptId() string { @@ -19240,7 +19367,7 @@ type SandboxServiceExposure struct { func (x *SandboxServiceExposure) Reset() { *x = SandboxServiceExposure{} - mi := &file_openshell_proto_msgTypes[247] + mi := &file_openshell_proto_msgTypes[249] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19252,7 +19379,7 @@ func (x *SandboxServiceExposure) String() string { func (*SandboxServiceExposure) ProtoMessage() {} func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[247] + mi := &file_openshell_proto_msgTypes[249] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19265,7 +19392,7 @@ func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxServiceExposure.ProtoReflect.Descriptor instead. func (*SandboxServiceExposure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{247} + return file_openshell_proto_rawDescGZIP(), []int{249} } func (x *SandboxServiceExposure) GetService() string { @@ -19319,7 +19446,7 @@ type EndpointFailure struct { func (x *EndpointFailure) Reset() { *x = EndpointFailure{} - mi := &file_openshell_proto_msgTypes[248] + mi := &file_openshell_proto_msgTypes[250] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -19331,7 +19458,7 @@ func (x *EndpointFailure) String() string { func (*EndpointFailure) ProtoMessage() {} func (x *EndpointFailure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[248] + mi := &file_openshell_proto_msgTypes[250] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19344,7 +19471,7 @@ func (x *EndpointFailure) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointFailure.ProtoReflect.Descriptor instead. func (*EndpointFailure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{248} + return file_openshell_proto_rawDescGZIP(), []int{250} } func (x *EndpointFailure) GetDomain() EndpointFailureDomain { @@ -19685,7 +19812,14 @@ const file_openshell_proto_rawDesc = "" + "\x0fworkspace_scope\x18\x02 \x01(\v2).openshell.datamodel.v1.WorkspaceSelectorR\x0eworkspaceScope\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1d\n" + "\n" + - "request_id\x18\x03 \x01(\tR\trequestId\"\xd5\x01\n" + + "request_id\x18\x03 \x01(\tR\trequestId\"\x7f\n" + + "\x15SuspendSandboxRequest\x12R\n" + + "\x0fworkspace_scope\x18\x02 \x01(\v2).openshell.datamodel.v1.WorkspaceSelectorR\x0eworkspaceScope\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"\xb7\x01\n" + + "\x14ResumeSandboxRequest\x12R\n" + + "\x0fworkspace_scope\x18\x02 \x01(\v2).openshell.datamodel.v1.WorkspaceSelectorR\x0eworkspaceScope\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x127\n" + + "\x18restart_if_restore_fails\x18\x03 \x01(\bR\x15restartIfRestoreFails\"\xd5\x01\n" + "\x0fSandboxResponse\x12/\n" + "\asandbox\x18\x01 \x01(\v2\x15.openshell.v1.SandboxR\asandbox\x12Q\n" + "\fservice_urls\x18\x02 \x03(\v2..openshell.v1.SandboxResponse.ServiceUrlsEntryR\vserviceUrls\x1a>\n" + @@ -20863,7 +20997,7 @@ const file_openshell_proto_rawDesc = "" + "\x1dEXTENSION_KIND_COMPUTE_DRIVER\x10\x01\x12$\n" + " EXTENSION_KIND_CREDENTIAL_DRIVER\x10\x02\x12&\n" + "\"EXTENSION_KIND_GATEWAY_INTERCEPTOR\x10\x03\x12(\n" + - "$EXTENSION_KIND_SUPERVISOR_MIDDLEWARE\x10\x04*\xc6\x02\n" + + "$EXTENSION_KIND_SUPERVISOR_MIDDLEWARE\x10\x04*\x81\x03\n" + "\fSandboxPhase\x12\x1d\n" + "\x19SANDBOX_PHASE_UNSPECIFIED\x10\x00\x12\x1e\n" + "\x1aSANDBOX_PHASE_PROVISIONING\x10\x01\x12\x17\n" + @@ -20874,7 +21008,9 @@ const file_openshell_proto_rawDesc = "" + "\x16SANDBOX_PHASE_STOPPING\x10\x06\x12\x19\n" + "\x15SANDBOX_PHASE_STOPPED\x10\a\x12\x1a\n" + "\x16SANDBOX_PHASE_STARTING\x10\b\x12\x1b\n" + - "\x17SANDBOX_PHASE_COMPLETED\x10\t\"\x04\b\n" + + "\x17SANDBOX_PHASE_COMPLETED\x10\t\x12\x1c\n" + + "\x18SANDBOX_PHASE_SUSPENDING\x10\v\x12\x1b\n" + + "\x17SANDBOX_PHASE_SUSPENDED\x10\f\"\x04\b\n" + "\x10\n" + "*\x18SANDBOX_PHASE_RESTARTING*\xcb\x01\n" + "\x14ProviderMutationKind\x12&\n" + @@ -21008,7 +21144,7 @@ const file_openshell_proto_rawDesc = "" + "-SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH\x10\x02*i\n" + "\x15EndpointFailureDomain\x12'\n" + "#ENDPOINT_FAILURE_DOMAIN_UNSPECIFIED\x10\x00\x12'\n" + - "#ENDPOINT_FAILURE_DOMAIN_TOKEN_GRANT\x10\x012\xb6W\n" + + "#ENDPOINT_FAILURE_DOMAIN_TOKEN_GRANT\x10\x012\xa6Y\n" + "\tOpenShell\x12Z\n" + "\x06Health\x12\x1b.openshell.v1.HealthRequest\x1a\x1c.openshell.v1.HealthResponse\"\x15\x82\xb5\x18\x11\n" + "\x0funauthenticated\x12i\n" + @@ -21046,6 +21182,10 @@ const file_openshell_proto_rawDesc = "" + "\vStopSandbox\x12 .openshell.v1.StopSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\"!\x82\xb5\x18\x1d\n" + "\x06bearer\x12\x04user\"\rsandbox:write\x12s\n" + "\fStartSandbox\x12!.openshell.v1.StartSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\"!\x82\xb5\x18\x1d\n" + + "\x06bearer\x12\x04user\"\rsandbox:write\x12w\n" + + "\x0eSuspendSandbox\x12#.openshell.v1.SuspendSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\"!\x82\xb5\x18\x1d\n" + + "\x06bearer\x12\x04user\"\rsandbox:write\x12u\n" + + "\rResumeSandbox\x12\".openshell.v1.ResumeSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\"!\x82\xb5\x18\x1d\n" + "\x06bearer\x12\x04user\"\rsandbox:write\x12\x84\x01\n" + "\x10CreateSshSession\x12%.openshell.v1.CreateSshSessionRequest\x1a&.openshell.v1.CreateSshSessionResponse\"!\x82\xb5\x18\x1d\n" + "\x06bearer\x12\x04user\"\rsandbox:write\x12}\n" + @@ -21201,7 +21341,7 @@ func file_openshell_proto_rawDescGZIP() []byte { } var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 22) -var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 275) +var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 277) var file_openshell_proto_goTypes = []any{ (ExtensionKind)(0), // 0: openshell.v1.ExtensionKind (SandboxPhase)(0), // 1: openshell.v1.SandboxPhase @@ -21275,257 +21415,259 @@ var file_openshell_proto_goTypes = []any{ (*DeleteSandboxRequest)(nil), // 69: openshell.v1.DeleteSandboxRequest (*StopSandboxRequest)(nil), // 70: openshell.v1.StopSandboxRequest (*StartSandboxRequest)(nil), // 71: openshell.v1.StartSandboxRequest - (*SandboxResponse)(nil), // 72: openshell.v1.SandboxResponse - (*ListSandboxesResponse)(nil), // 73: openshell.v1.ListSandboxesResponse - (*ListSandboxProvidersResponse)(nil), // 74: openshell.v1.ListSandboxProvidersResponse - (*AttachSandboxProviderResponse)(nil), // 75: openshell.v1.AttachSandboxProviderResponse - (*DetachSandboxProviderResponse)(nil), // 76: openshell.v1.DetachSandboxProviderResponse - (*ProviderDesiredIdentity)(nil), // 77: openshell.v1.ProviderDesiredIdentity - (*ConfigSnapshotRevision)(nil), // 78: openshell.v1.ConfigSnapshotRevision - (*SandboxConfigRevision)(nil), // 79: openshell.v1.SandboxConfigRevision - (*ConfigUpdateOperation)(nil), // 80: openshell.v1.ConfigUpdateOperation - (*ProviderMutationReceipt)(nil), // 81: openshell.v1.ProviderMutationReceipt - (*ProviderReadinessObservation)(nil), // 82: openshell.v1.ProviderReadinessObservation - (*ProviderReadinessStatus)(nil), // 83: openshell.v1.ProviderReadinessStatus - (*GetSandboxProviderStatusRequest)(nil), // 84: openshell.v1.GetSandboxProviderStatusRequest - (*GetSandboxProviderStatusResponse)(nil), // 85: openshell.v1.GetSandboxProviderStatusResponse - (*ReportProviderReadinessRequest)(nil), // 86: openshell.v1.ReportProviderReadinessRequest - (*ReportProviderReadinessResponse)(nil), // 87: openshell.v1.ReportProviderReadinessResponse - (*DeleteSandboxResponse)(nil), // 88: openshell.v1.DeleteSandboxResponse - (*CreateSshSessionRequest)(nil), // 89: openshell.v1.CreateSshSessionRequest - (*CreateSshSessionResponse)(nil), // 90: openshell.v1.CreateSshSessionResponse - (*ExposeServiceRequest)(nil), // 91: openshell.v1.ExposeServiceRequest - (*GetServiceRequest)(nil), // 92: openshell.v1.GetServiceRequest - (*ListServicesRequest)(nil), // 93: openshell.v1.ListServicesRequest - (*ListServicesResponse)(nil), // 94: openshell.v1.ListServicesResponse - (*DeleteServiceRequest)(nil), // 95: openshell.v1.DeleteServiceRequest - (*DeleteServiceResponse)(nil), // 96: openshell.v1.DeleteServiceResponse - (*ServiceEndpoint)(nil), // 97: openshell.v1.ServiceEndpoint - (*ServiceEndpointResponse)(nil), // 98: openshell.v1.ServiceEndpointResponse - (*RevokeSshSessionRequest)(nil), // 99: openshell.v1.RevokeSshSessionRequest - (*RevokeSshSessionResponse)(nil), // 100: openshell.v1.RevokeSshSessionResponse - (*ExecSandboxRequest)(nil), // 101: openshell.v1.ExecSandboxRequest - (*ExecSandboxStdout)(nil), // 102: openshell.v1.ExecSandboxStdout - (*ExecSandboxStderr)(nil), // 103: openshell.v1.ExecSandboxStderr - (*ExecSandboxExit)(nil), // 104: openshell.v1.ExecSandboxExit - (*ExecSandboxEvent)(nil), // 105: openshell.v1.ExecSandboxEvent - (*TcpForwardInit)(nil), // 106: openshell.v1.TcpForwardInit - (*TcpForwardFrame)(nil), // 107: openshell.v1.TcpForwardFrame - (*ExecSandboxInput)(nil), // 108: openshell.v1.ExecSandboxInput - (*ExecSandboxWindowResize)(nil), // 109: openshell.v1.ExecSandboxWindowResize - (*SshSession)(nil), // 110: openshell.v1.SshSession - (*WatchSandboxRequest)(nil), // 111: openshell.v1.WatchSandboxRequest - (*SandboxStreamEvent)(nil), // 112: openshell.v1.SandboxStreamEvent - (*SandboxLogLine)(nil), // 113: openshell.v1.SandboxLogLine - (*SandboxStreamWarning)(nil), // 114: openshell.v1.SandboxStreamWarning - (*CreateProviderRequest)(nil), // 115: openshell.v1.CreateProviderRequest - (*GetProviderRequest)(nil), // 116: openshell.v1.GetProviderRequest - (*GetProviderCredentialsRequest)(nil), // 117: openshell.v1.GetProviderCredentialsRequest - (*ProviderCredentialValue)(nil), // 118: openshell.v1.ProviderCredentialValue - (*GetProviderCredentialsResponse)(nil), // 119: openshell.v1.GetProviderCredentialsResponse - (*ListProvidersRequest)(nil), // 120: openshell.v1.ListProvidersRequest - (*UpdateProviderRequest)(nil), // 121: openshell.v1.UpdateProviderRequest - (*DeleteProviderRequest)(nil), // 122: openshell.v1.DeleteProviderRequest - (*ProviderResponse)(nil), // 123: openshell.v1.ProviderResponse - (*ListProvidersResponse)(nil), // 124: openshell.v1.ListProvidersResponse - (*ListProviderProfilesRequest)(nil), // 125: openshell.v1.ListProviderProfilesRequest - (*GetProviderProfileRequest)(nil), // 126: openshell.v1.GetProviderProfileRequest - (*ProviderProfileImportItem)(nil), // 127: openshell.v1.ProviderProfileImportItem - (*ProviderProfileDiagnostic)(nil), // 128: openshell.v1.ProviderProfileDiagnostic - (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 129: openshell.v1.ProviderCredentialTokenGrantAudienceOverride - (*ProviderCredentialTokenGrantSubjectToken)(nil), // 130: openshell.v1.ProviderCredentialTokenGrantSubjectToken - (*ProviderCredentialTokenGrant)(nil), // 131: openshell.v1.ProviderCredentialTokenGrant - (*ProviderProfileCredential)(nil), // 132: openshell.v1.ProviderProfileCredential - (*ProviderCredentialRefreshMaterial)(nil), // 133: openshell.v1.ProviderCredentialRefreshMaterial - (*ProviderCredentialRefreshOutput)(nil), // 134: openshell.v1.ProviderCredentialRefreshOutput - (*ProviderCredentialRefresh)(nil), // 135: openshell.v1.ProviderCredentialRefresh - (*ProviderCredentialRefreshStatus)(nil), // 136: openshell.v1.ProviderCredentialRefreshStatus - (*ProviderProfileDiscovery)(nil), // 137: openshell.v1.ProviderProfileDiscovery - (*GetProviderRefreshStatusRequest)(nil), // 138: openshell.v1.GetProviderRefreshStatusRequest - (*GetProviderRefreshStatusResponse)(nil), // 139: openshell.v1.GetProviderRefreshStatusResponse - (*ConfigureProviderRefreshRequest)(nil), // 140: openshell.v1.ConfigureProviderRefreshRequest - (*ConfigureProviderRefreshResponse)(nil), // 141: openshell.v1.ConfigureProviderRefreshResponse - (*RotateProviderCredentialRequest)(nil), // 142: openshell.v1.RotateProviderCredentialRequest - (*RotateProviderCredentialResponse)(nil), // 143: openshell.v1.RotateProviderCredentialResponse - (*DeleteProviderRefreshRequest)(nil), // 144: openshell.v1.DeleteProviderRefreshRequest - (*DeleteProviderRefreshResponse)(nil), // 145: openshell.v1.DeleteProviderRefreshResponse - (*ProviderProfile)(nil), // 146: openshell.v1.ProviderProfile - (*ProviderProfileFile)(nil), // 147: openshell.v1.ProviderProfileFile - (*ProviderProfileResponse)(nil), // 148: openshell.v1.ProviderProfileResponse - (*ListProviderProfilesResponse)(nil), // 149: openshell.v1.ListProviderProfilesResponse - (*ImportProviderProfilesRequest)(nil), // 150: openshell.v1.ImportProviderProfilesRequest - (*ImportProviderProfilesResponse)(nil), // 151: openshell.v1.ImportProviderProfilesResponse - (*UpdateProviderProfilesRequest)(nil), // 152: openshell.v1.UpdateProviderProfilesRequest - (*UpdateProviderProfilesResponse)(nil), // 153: openshell.v1.UpdateProviderProfilesResponse - (*LintProviderProfilesRequest)(nil), // 154: openshell.v1.LintProviderProfilesRequest - (*LintProviderProfilesResponse)(nil), // 155: openshell.v1.LintProviderProfilesResponse - (*DeleteProviderResponse)(nil), // 156: openshell.v1.DeleteProviderResponse - (*DeleteProviderProfileRequest)(nil), // 157: openshell.v1.DeleteProviderProfileRequest - (*DeleteProviderProfileResponse)(nil), // 158: openshell.v1.DeleteProviderProfileResponse - (*GetSandboxProviderEnvironmentRequest)(nil), // 159: openshell.v1.GetSandboxProviderEnvironmentRequest - (*StaticCredentialEndpointBinding)(nil), // 160: openshell.v1.StaticCredentialEndpointBinding - (*StaticCredentialBinding)(nil), // 161: openshell.v1.StaticCredentialBinding - (*GetSandboxProviderEnvironmentResponse)(nil), // 162: openshell.v1.GetSandboxProviderEnvironmentResponse - (*ProviderEnvironmentValue)(nil), // 163: openshell.v1.ProviderEnvironmentValue - (*ProviderEnvironmentSnapshot)(nil), // 164: openshell.v1.ProviderEnvironmentSnapshot - (*ExchangeProviderSubjectTokenRequest)(nil), // 165: openshell.v1.ExchangeProviderSubjectTokenRequest - (*ExchangeProviderSubjectTokenResponse)(nil), // 166: openshell.v1.ExchangeProviderSubjectTokenResponse - (*UpdateConfigRequest)(nil), // 167: openshell.v1.UpdateConfigRequest - (*PolicyMergeOperation)(nil), // 168: openshell.v1.PolicyMergeOperation - (*AddNetworkRule)(nil), // 169: openshell.v1.AddNetworkRule - (*RemoveNetworkEndpoint)(nil), // 170: openshell.v1.RemoveNetworkEndpoint - (*RemoveNetworkRule)(nil), // 171: openshell.v1.RemoveNetworkRule - (*L7RuleTarget)(nil), // 172: openshell.v1.L7RuleTarget - (*AddDenyRules)(nil), // 173: openshell.v1.AddDenyRules - (*AddAllowRules)(nil), // 174: openshell.v1.AddAllowRules - (*RemoveNetworkBinary)(nil), // 175: openshell.v1.RemoveNetworkBinary - (*UpdateConfigResponse)(nil), // 176: openshell.v1.UpdateConfigResponse - (*GetSandboxPolicyStatusRequest)(nil), // 177: openshell.v1.GetSandboxPolicyStatusRequest - (*GetSandboxPolicyStatusResponse)(nil), // 178: openshell.v1.GetSandboxPolicyStatusResponse - (*ListSandboxPoliciesRequest)(nil), // 179: openshell.v1.ListSandboxPoliciesRequest - (*ListSandboxPoliciesResponse)(nil), // 180: openshell.v1.ListSandboxPoliciesResponse - (*ReportPolicyStatusRequest)(nil), // 181: openshell.v1.ReportPolicyStatusRequest - (*ReportPolicyStatusResponse)(nil), // 182: openshell.v1.ReportPolicyStatusResponse - (*SandboxConfigurationAdmission)(nil), // 183: openshell.v1.SandboxConfigurationAdmission - (*ReportSandboxConfigurationRequest)(nil), // 184: openshell.v1.ReportSandboxConfigurationRequest - (*ReportSandboxConfigurationResponse)(nil), // 185: openshell.v1.ReportSandboxConfigurationResponse - (*SandboxPolicyRevision)(nil), // 186: openshell.v1.SandboxPolicyRevision - (*GetSandboxLogsRequest)(nil), // 187: openshell.v1.GetSandboxLogsRequest - (*PushSandboxLogsRequest)(nil), // 188: openshell.v1.PushSandboxLogsRequest - (*PushSandboxLogsResponse)(nil), // 189: openshell.v1.PushSandboxLogsResponse - (*GetSandboxLogsResponse)(nil), // 190: openshell.v1.GetSandboxLogsResponse - (*SupervisorMessage)(nil), // 191: openshell.v1.SupervisorMessage - (*GatewayMessage)(nil), // 192: openshell.v1.GatewayMessage - (*SupervisorHello)(nil), // 193: openshell.v1.SupervisorHello - (*SessionAccepted)(nil), // 194: openshell.v1.SessionAccepted - (*ConfigUpdate)(nil), // 195: openshell.v1.ConfigUpdate - (*ConfigApplyFailure)(nil), // 196: openshell.v1.ConfigApplyFailure - (*ConfigUpdateResult)(nil), // 197: openshell.v1.ConfigUpdateResult - (*PolicyLoadResult)(nil), // 198: openshell.v1.PolicyLoadResult - (*SessionRejected)(nil), // 199: openshell.v1.SessionRejected - (*SessionRedirect)(nil), // 200: openshell.v1.SessionRedirect - (*SupervisorHeartbeat)(nil), // 201: openshell.v1.SupervisorHeartbeat - (*GatewayHeartbeat)(nil), // 202: openshell.v1.GatewayHeartbeat - (*ReportMainProcessExitRequest)(nil), // 203: openshell.v1.ReportMainProcessExitRequest - (*ReportMainProcessExitResponse)(nil), // 204: openshell.v1.ReportMainProcessExitResponse - (*FinalizeMainProcessExitRequest)(nil), // 205: openshell.v1.FinalizeMainProcessExitRequest - (*FinalizeMainProcessExitResponse)(nil), // 206: openshell.v1.FinalizeMainProcessExitResponse - (*RelayOpen)(nil), // 207: openshell.v1.RelayOpen - (*SshRelayTarget)(nil), // 208: openshell.v1.SshRelayTarget - (*TcpRelayTarget)(nil), // 209: openshell.v1.TcpRelayTarget - (*RelayInit)(nil), // 210: openshell.v1.RelayInit - (*RelayFrame)(nil), // 211: openshell.v1.RelayFrame - (*PeerRelayInit)(nil), // 212: openshell.v1.PeerRelayInit - (*PeerRelayFrame)(nil), // 213: openshell.v1.PeerRelayFrame - (*PeerConfigSandboxTarget)(nil), // 214: openshell.v1.PeerConfigSandboxTarget - (*PeerConfigProviderTarget)(nil), // 215: openshell.v1.PeerConfigProviderTarget - (*PeerNotifyConfigUpdateRequest)(nil), // 216: openshell.v1.PeerNotifyConfigUpdateRequest - (*PeerNotifyConfigUpdateResponse)(nil), // 217: openshell.v1.PeerNotifyConfigUpdateResponse - (*RelayOpenResult)(nil), // 218: openshell.v1.RelayOpenResult - (*RelayClose)(nil), // 219: openshell.v1.RelayClose - (*L7RequestSample)(nil), // 220: openshell.v1.L7RequestSample - (*DenialSummary)(nil), // 221: openshell.v1.DenialSummary - (*DenialGroupCount)(nil), // 222: openshell.v1.DenialGroupCount - (*NetworkActivitySummary)(nil), // 223: openshell.v1.NetworkActivitySummary - (*PolicyChunk)(nil), // 224: openshell.v1.PolicyChunk - (*DraftPolicyUpdate)(nil), // 225: openshell.v1.DraftPolicyUpdate - (*SubmitPolicyAnalysisRequest)(nil), // 226: openshell.v1.SubmitPolicyAnalysisRequest - (*SubmitPolicyAnalysisResponse)(nil), // 227: openshell.v1.SubmitPolicyAnalysisResponse - (*GetDraftPolicyRequest)(nil), // 228: openshell.v1.GetDraftPolicyRequest - (*GetDraftPolicyResponse)(nil), // 229: openshell.v1.GetDraftPolicyResponse - (*ApproveDraftChunkRequest)(nil), // 230: openshell.v1.ApproveDraftChunkRequest - (*ApproveDraftChunkResponse)(nil), // 231: openshell.v1.ApproveDraftChunkResponse - (*RejectDraftChunkRequest)(nil), // 232: openshell.v1.RejectDraftChunkRequest - (*RejectDraftChunkResponse)(nil), // 233: openshell.v1.RejectDraftChunkResponse - (*DraftChunkApproval)(nil), // 234: openshell.v1.DraftChunkApproval - (*ApproveAllDraftChunksRequest)(nil), // 235: openshell.v1.ApproveAllDraftChunksRequest - (*ApproveAllDraftChunksResponse)(nil), // 236: openshell.v1.ApproveAllDraftChunksResponse - (*EditDraftChunkRequest)(nil), // 237: openshell.v1.EditDraftChunkRequest - (*EditDraftChunkResponse)(nil), // 238: openshell.v1.EditDraftChunkResponse - (*UndoDraftChunkRequest)(nil), // 239: openshell.v1.UndoDraftChunkRequest - (*UndoDraftChunkResponse)(nil), // 240: openshell.v1.UndoDraftChunkResponse - (*ClearDraftChunksRequest)(nil), // 241: openshell.v1.ClearDraftChunksRequest - (*ClearDraftChunksResponse)(nil), // 242: openshell.v1.ClearDraftChunksResponse - (*GetDraftHistoryRequest)(nil), // 243: openshell.v1.GetDraftHistoryRequest - (*DraftHistoryEntry)(nil), // 244: openshell.v1.DraftHistoryEntry - (*GetDraftHistoryResponse)(nil), // 245: openshell.v1.GetDraftHistoryResponse - (*CreateWorkspaceRequest)(nil), // 246: openshell.v1.CreateWorkspaceRequest - (*CreateWorkspaceResponse)(nil), // 247: openshell.v1.CreateWorkspaceResponse - (*GetWorkspaceRequest)(nil), // 248: openshell.v1.GetWorkspaceRequest - (*GetWorkspaceResponse)(nil), // 249: openshell.v1.GetWorkspaceResponse - (*ListWorkspacesRequest)(nil), // 250: openshell.v1.ListWorkspacesRequest - (*ListWorkspacesResponse)(nil), // 251: openshell.v1.ListWorkspacesResponse - (*DeleteWorkspaceRequest)(nil), // 252: openshell.v1.DeleteWorkspaceRequest - (*DeleteWorkspaceResponse)(nil), // 253: openshell.v1.DeleteWorkspaceResponse - (*WorkspaceMember)(nil), // 254: openshell.v1.WorkspaceMember - (*AddWorkspaceMemberRequest)(nil), // 255: openshell.v1.AddWorkspaceMemberRequest - (*AddWorkspaceMemberResponse)(nil), // 256: openshell.v1.AddWorkspaceMemberResponse - (*RemoveWorkspaceMemberRequest)(nil), // 257: openshell.v1.RemoveWorkspaceMemberRequest - (*RemoveWorkspaceMemberResponse)(nil), // 258: openshell.v1.RemoveWorkspaceMemberResponse - (*ListWorkspaceMembersRequest)(nil), // 259: openshell.v1.ListWorkspaceMembersRequest - (*ListWorkspaceMembersResponse)(nil), // 260: openshell.v1.ListWorkspaceMembersResponse - (*ExtensionServiceCredential)(nil), // 261: openshell.v1.ExtensionServiceCredential - (*EndpointObservation)(nil), // 262: openshell.v1.EndpointObservation - (*ReportEndpointStatusRequest)(nil), // 263: openshell.v1.ReportEndpointStatusRequest - (*TokenGrantStatus)(nil), // 264: openshell.v1.TokenGrantStatus - (*TokenGrantFailureObservation)(nil), // 265: openshell.v1.TokenGrantFailureObservation - (*ReportEndpointStatusResponse)(nil), // 266: openshell.v1.ReportEndpointStatusResponse - (*EndpointStatus)(nil), // 267: openshell.v1.EndpointStatus - (*SandboxProvisioning)(nil), // 268: openshell.v1.SandboxProvisioning - (*SandboxServiceExposure)(nil), // 269: openshell.v1.SandboxServiceExposure - (*EndpointFailure)(nil), // 270: openshell.v1.EndpointFailure - nil, // 271: openshell.v1.SandboxSpec.EnvironmentEntry - nil, // 272: openshell.v1.SandboxTemplate.LabelsEntry - nil, // 273: openshell.v1.SandboxTemplate.AnnotationsEntry - nil, // 274: openshell.v1.SandboxTemplate.EnvironmentEntry - nil, // 275: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - nil, // 276: openshell.v1.PlatformEvent.MetadataEntry - nil, // 277: openshell.v1.CreateSandboxRequest.LabelsEntry - nil, // 278: openshell.v1.CreateSandboxRequest.AnnotationsEntry - nil, // 279: openshell.v1.SandboxResponse.ServiceUrlsEntry - nil, // 280: openshell.v1.ExecSandboxRequest.EnvironmentEntry - nil, // 281: openshell.v1.SandboxLogLine.FieldsEntry - nil, // 282: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry - nil, // 283: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - nil, // 284: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - nil, // 285: openshell.v1.ProviderProfile.AnnotationsEntry - nil, // 286: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - nil, // 287: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - nil, // 288: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - nil, // 289: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - nil, // 290: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - nil, // 291: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry - nil, // 292: openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - nil, // 293: openshell.v1.UpdateConfigRequest.AnnotationsEntry - nil, // 294: openshell.v1.UpdateConfigResponse.AnnotationsEntry - nil, // 295: openshell.v1.SandboxPolicyRevision.ProvenanceEntry - nil, // 296: openshell.v1.CreateWorkspaceRequest.LabelsEntry - (*timestamppb.Timestamp)(nil), // 297: google.protobuf.Timestamp - (*datamodelv1.ObjectMeta)(nil), // 298: openshell.datamodel.v1.ObjectMeta - (*sandboxv1.SandboxPolicy)(nil), // 299: openshell.sandbox.v1.SandboxPolicy - (*structpb.Struct)(nil), // 300: google.protobuf.Struct - (*durationpb.Duration)(nil), // 301: google.protobuf.Duration - (*datamodelv1.WorkspaceSelector)(nil), // 302: openshell.datamodel.v1.WorkspaceSelector - (*datamodelv1.Provider)(nil), // 303: openshell.datamodel.v1.Provider - (sandboxv1.PolicySource)(0), // 304: openshell.sandbox.v1.PolicySource - (*sandboxv1.NetworkEndpoint)(nil), // 305: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 306: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 307: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 308: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 309: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 310: openshell.sandbox.v1.L7Rule - (*sandboxv1.SandboxConfigSnapshot)(nil), // 311: openshell.sandbox.v1.SandboxConfigSnapshot - (*datamodelv1.Workspace)(nil), // 312: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 313: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 314: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 315: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 316: openshell.sandbox.v1.GetGatewayConfigResponse + (*SuspendSandboxRequest)(nil), // 72: openshell.v1.SuspendSandboxRequest + (*ResumeSandboxRequest)(nil), // 73: openshell.v1.ResumeSandboxRequest + (*SandboxResponse)(nil), // 74: openshell.v1.SandboxResponse + (*ListSandboxesResponse)(nil), // 75: openshell.v1.ListSandboxesResponse + (*ListSandboxProvidersResponse)(nil), // 76: openshell.v1.ListSandboxProvidersResponse + (*AttachSandboxProviderResponse)(nil), // 77: openshell.v1.AttachSandboxProviderResponse + (*DetachSandboxProviderResponse)(nil), // 78: openshell.v1.DetachSandboxProviderResponse + (*ProviderDesiredIdentity)(nil), // 79: openshell.v1.ProviderDesiredIdentity + (*ConfigSnapshotRevision)(nil), // 80: openshell.v1.ConfigSnapshotRevision + (*SandboxConfigRevision)(nil), // 81: openshell.v1.SandboxConfigRevision + (*ConfigUpdateOperation)(nil), // 82: openshell.v1.ConfigUpdateOperation + (*ProviderMutationReceipt)(nil), // 83: openshell.v1.ProviderMutationReceipt + (*ProviderReadinessObservation)(nil), // 84: openshell.v1.ProviderReadinessObservation + (*ProviderReadinessStatus)(nil), // 85: openshell.v1.ProviderReadinessStatus + (*GetSandboxProviderStatusRequest)(nil), // 86: openshell.v1.GetSandboxProviderStatusRequest + (*GetSandboxProviderStatusResponse)(nil), // 87: openshell.v1.GetSandboxProviderStatusResponse + (*ReportProviderReadinessRequest)(nil), // 88: openshell.v1.ReportProviderReadinessRequest + (*ReportProviderReadinessResponse)(nil), // 89: openshell.v1.ReportProviderReadinessResponse + (*DeleteSandboxResponse)(nil), // 90: openshell.v1.DeleteSandboxResponse + (*CreateSshSessionRequest)(nil), // 91: openshell.v1.CreateSshSessionRequest + (*CreateSshSessionResponse)(nil), // 92: openshell.v1.CreateSshSessionResponse + (*ExposeServiceRequest)(nil), // 93: openshell.v1.ExposeServiceRequest + (*GetServiceRequest)(nil), // 94: openshell.v1.GetServiceRequest + (*ListServicesRequest)(nil), // 95: openshell.v1.ListServicesRequest + (*ListServicesResponse)(nil), // 96: openshell.v1.ListServicesResponse + (*DeleteServiceRequest)(nil), // 97: openshell.v1.DeleteServiceRequest + (*DeleteServiceResponse)(nil), // 98: openshell.v1.DeleteServiceResponse + (*ServiceEndpoint)(nil), // 99: openshell.v1.ServiceEndpoint + (*ServiceEndpointResponse)(nil), // 100: openshell.v1.ServiceEndpointResponse + (*RevokeSshSessionRequest)(nil), // 101: openshell.v1.RevokeSshSessionRequest + (*RevokeSshSessionResponse)(nil), // 102: openshell.v1.RevokeSshSessionResponse + (*ExecSandboxRequest)(nil), // 103: openshell.v1.ExecSandboxRequest + (*ExecSandboxStdout)(nil), // 104: openshell.v1.ExecSandboxStdout + (*ExecSandboxStderr)(nil), // 105: openshell.v1.ExecSandboxStderr + (*ExecSandboxExit)(nil), // 106: openshell.v1.ExecSandboxExit + (*ExecSandboxEvent)(nil), // 107: openshell.v1.ExecSandboxEvent + (*TcpForwardInit)(nil), // 108: openshell.v1.TcpForwardInit + (*TcpForwardFrame)(nil), // 109: openshell.v1.TcpForwardFrame + (*ExecSandboxInput)(nil), // 110: openshell.v1.ExecSandboxInput + (*ExecSandboxWindowResize)(nil), // 111: openshell.v1.ExecSandboxWindowResize + (*SshSession)(nil), // 112: openshell.v1.SshSession + (*WatchSandboxRequest)(nil), // 113: openshell.v1.WatchSandboxRequest + (*SandboxStreamEvent)(nil), // 114: openshell.v1.SandboxStreamEvent + (*SandboxLogLine)(nil), // 115: openshell.v1.SandboxLogLine + (*SandboxStreamWarning)(nil), // 116: openshell.v1.SandboxStreamWarning + (*CreateProviderRequest)(nil), // 117: openshell.v1.CreateProviderRequest + (*GetProviderRequest)(nil), // 118: openshell.v1.GetProviderRequest + (*GetProviderCredentialsRequest)(nil), // 119: openshell.v1.GetProviderCredentialsRequest + (*ProviderCredentialValue)(nil), // 120: openshell.v1.ProviderCredentialValue + (*GetProviderCredentialsResponse)(nil), // 121: openshell.v1.GetProviderCredentialsResponse + (*ListProvidersRequest)(nil), // 122: openshell.v1.ListProvidersRequest + (*UpdateProviderRequest)(nil), // 123: openshell.v1.UpdateProviderRequest + (*DeleteProviderRequest)(nil), // 124: openshell.v1.DeleteProviderRequest + (*ProviderResponse)(nil), // 125: openshell.v1.ProviderResponse + (*ListProvidersResponse)(nil), // 126: openshell.v1.ListProvidersResponse + (*ListProviderProfilesRequest)(nil), // 127: openshell.v1.ListProviderProfilesRequest + (*GetProviderProfileRequest)(nil), // 128: openshell.v1.GetProviderProfileRequest + (*ProviderProfileImportItem)(nil), // 129: openshell.v1.ProviderProfileImportItem + (*ProviderProfileDiagnostic)(nil), // 130: openshell.v1.ProviderProfileDiagnostic + (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 131: openshell.v1.ProviderCredentialTokenGrantAudienceOverride + (*ProviderCredentialTokenGrantSubjectToken)(nil), // 132: openshell.v1.ProviderCredentialTokenGrantSubjectToken + (*ProviderCredentialTokenGrant)(nil), // 133: openshell.v1.ProviderCredentialTokenGrant + (*ProviderProfileCredential)(nil), // 134: openshell.v1.ProviderProfileCredential + (*ProviderCredentialRefreshMaterial)(nil), // 135: openshell.v1.ProviderCredentialRefreshMaterial + (*ProviderCredentialRefreshOutput)(nil), // 136: openshell.v1.ProviderCredentialRefreshOutput + (*ProviderCredentialRefresh)(nil), // 137: openshell.v1.ProviderCredentialRefresh + (*ProviderCredentialRefreshStatus)(nil), // 138: openshell.v1.ProviderCredentialRefreshStatus + (*ProviderProfileDiscovery)(nil), // 139: openshell.v1.ProviderProfileDiscovery + (*GetProviderRefreshStatusRequest)(nil), // 140: openshell.v1.GetProviderRefreshStatusRequest + (*GetProviderRefreshStatusResponse)(nil), // 141: openshell.v1.GetProviderRefreshStatusResponse + (*ConfigureProviderRefreshRequest)(nil), // 142: openshell.v1.ConfigureProviderRefreshRequest + (*ConfigureProviderRefreshResponse)(nil), // 143: openshell.v1.ConfigureProviderRefreshResponse + (*RotateProviderCredentialRequest)(nil), // 144: openshell.v1.RotateProviderCredentialRequest + (*RotateProviderCredentialResponse)(nil), // 145: openshell.v1.RotateProviderCredentialResponse + (*DeleteProviderRefreshRequest)(nil), // 146: openshell.v1.DeleteProviderRefreshRequest + (*DeleteProviderRefreshResponse)(nil), // 147: openshell.v1.DeleteProviderRefreshResponse + (*ProviderProfile)(nil), // 148: openshell.v1.ProviderProfile + (*ProviderProfileFile)(nil), // 149: openshell.v1.ProviderProfileFile + (*ProviderProfileResponse)(nil), // 150: openshell.v1.ProviderProfileResponse + (*ListProviderProfilesResponse)(nil), // 151: openshell.v1.ListProviderProfilesResponse + (*ImportProviderProfilesRequest)(nil), // 152: openshell.v1.ImportProviderProfilesRequest + (*ImportProviderProfilesResponse)(nil), // 153: openshell.v1.ImportProviderProfilesResponse + (*UpdateProviderProfilesRequest)(nil), // 154: openshell.v1.UpdateProviderProfilesRequest + (*UpdateProviderProfilesResponse)(nil), // 155: openshell.v1.UpdateProviderProfilesResponse + (*LintProviderProfilesRequest)(nil), // 156: openshell.v1.LintProviderProfilesRequest + (*LintProviderProfilesResponse)(nil), // 157: openshell.v1.LintProviderProfilesResponse + (*DeleteProviderResponse)(nil), // 158: openshell.v1.DeleteProviderResponse + (*DeleteProviderProfileRequest)(nil), // 159: openshell.v1.DeleteProviderProfileRequest + (*DeleteProviderProfileResponse)(nil), // 160: openshell.v1.DeleteProviderProfileResponse + (*GetSandboxProviderEnvironmentRequest)(nil), // 161: openshell.v1.GetSandboxProviderEnvironmentRequest + (*StaticCredentialEndpointBinding)(nil), // 162: openshell.v1.StaticCredentialEndpointBinding + (*StaticCredentialBinding)(nil), // 163: openshell.v1.StaticCredentialBinding + (*GetSandboxProviderEnvironmentResponse)(nil), // 164: openshell.v1.GetSandboxProviderEnvironmentResponse + (*ProviderEnvironmentValue)(nil), // 165: openshell.v1.ProviderEnvironmentValue + (*ProviderEnvironmentSnapshot)(nil), // 166: openshell.v1.ProviderEnvironmentSnapshot + (*ExchangeProviderSubjectTokenRequest)(nil), // 167: openshell.v1.ExchangeProviderSubjectTokenRequest + (*ExchangeProviderSubjectTokenResponse)(nil), // 168: openshell.v1.ExchangeProviderSubjectTokenResponse + (*UpdateConfigRequest)(nil), // 169: openshell.v1.UpdateConfigRequest + (*PolicyMergeOperation)(nil), // 170: openshell.v1.PolicyMergeOperation + (*AddNetworkRule)(nil), // 171: openshell.v1.AddNetworkRule + (*RemoveNetworkEndpoint)(nil), // 172: openshell.v1.RemoveNetworkEndpoint + (*RemoveNetworkRule)(nil), // 173: openshell.v1.RemoveNetworkRule + (*L7RuleTarget)(nil), // 174: openshell.v1.L7RuleTarget + (*AddDenyRules)(nil), // 175: openshell.v1.AddDenyRules + (*AddAllowRules)(nil), // 176: openshell.v1.AddAllowRules + (*RemoveNetworkBinary)(nil), // 177: openshell.v1.RemoveNetworkBinary + (*UpdateConfigResponse)(nil), // 178: openshell.v1.UpdateConfigResponse + (*GetSandboxPolicyStatusRequest)(nil), // 179: openshell.v1.GetSandboxPolicyStatusRequest + (*GetSandboxPolicyStatusResponse)(nil), // 180: openshell.v1.GetSandboxPolicyStatusResponse + (*ListSandboxPoliciesRequest)(nil), // 181: openshell.v1.ListSandboxPoliciesRequest + (*ListSandboxPoliciesResponse)(nil), // 182: openshell.v1.ListSandboxPoliciesResponse + (*ReportPolicyStatusRequest)(nil), // 183: openshell.v1.ReportPolicyStatusRequest + (*ReportPolicyStatusResponse)(nil), // 184: openshell.v1.ReportPolicyStatusResponse + (*SandboxConfigurationAdmission)(nil), // 185: openshell.v1.SandboxConfigurationAdmission + (*ReportSandboxConfigurationRequest)(nil), // 186: openshell.v1.ReportSandboxConfigurationRequest + (*ReportSandboxConfigurationResponse)(nil), // 187: openshell.v1.ReportSandboxConfigurationResponse + (*SandboxPolicyRevision)(nil), // 188: openshell.v1.SandboxPolicyRevision + (*GetSandboxLogsRequest)(nil), // 189: openshell.v1.GetSandboxLogsRequest + (*PushSandboxLogsRequest)(nil), // 190: openshell.v1.PushSandboxLogsRequest + (*PushSandboxLogsResponse)(nil), // 191: openshell.v1.PushSandboxLogsResponse + (*GetSandboxLogsResponse)(nil), // 192: openshell.v1.GetSandboxLogsResponse + (*SupervisorMessage)(nil), // 193: openshell.v1.SupervisorMessage + (*GatewayMessage)(nil), // 194: openshell.v1.GatewayMessage + (*SupervisorHello)(nil), // 195: openshell.v1.SupervisorHello + (*SessionAccepted)(nil), // 196: openshell.v1.SessionAccepted + (*ConfigUpdate)(nil), // 197: openshell.v1.ConfigUpdate + (*ConfigApplyFailure)(nil), // 198: openshell.v1.ConfigApplyFailure + (*ConfigUpdateResult)(nil), // 199: openshell.v1.ConfigUpdateResult + (*PolicyLoadResult)(nil), // 200: openshell.v1.PolicyLoadResult + (*SessionRejected)(nil), // 201: openshell.v1.SessionRejected + (*SessionRedirect)(nil), // 202: openshell.v1.SessionRedirect + (*SupervisorHeartbeat)(nil), // 203: openshell.v1.SupervisorHeartbeat + (*GatewayHeartbeat)(nil), // 204: openshell.v1.GatewayHeartbeat + (*ReportMainProcessExitRequest)(nil), // 205: openshell.v1.ReportMainProcessExitRequest + (*ReportMainProcessExitResponse)(nil), // 206: openshell.v1.ReportMainProcessExitResponse + (*FinalizeMainProcessExitRequest)(nil), // 207: openshell.v1.FinalizeMainProcessExitRequest + (*FinalizeMainProcessExitResponse)(nil), // 208: openshell.v1.FinalizeMainProcessExitResponse + (*RelayOpen)(nil), // 209: openshell.v1.RelayOpen + (*SshRelayTarget)(nil), // 210: openshell.v1.SshRelayTarget + (*TcpRelayTarget)(nil), // 211: openshell.v1.TcpRelayTarget + (*RelayInit)(nil), // 212: openshell.v1.RelayInit + (*RelayFrame)(nil), // 213: openshell.v1.RelayFrame + (*PeerRelayInit)(nil), // 214: openshell.v1.PeerRelayInit + (*PeerRelayFrame)(nil), // 215: openshell.v1.PeerRelayFrame + (*PeerConfigSandboxTarget)(nil), // 216: openshell.v1.PeerConfigSandboxTarget + (*PeerConfigProviderTarget)(nil), // 217: openshell.v1.PeerConfigProviderTarget + (*PeerNotifyConfigUpdateRequest)(nil), // 218: openshell.v1.PeerNotifyConfigUpdateRequest + (*PeerNotifyConfigUpdateResponse)(nil), // 219: openshell.v1.PeerNotifyConfigUpdateResponse + (*RelayOpenResult)(nil), // 220: openshell.v1.RelayOpenResult + (*RelayClose)(nil), // 221: openshell.v1.RelayClose + (*L7RequestSample)(nil), // 222: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 223: openshell.v1.DenialSummary + (*DenialGroupCount)(nil), // 224: openshell.v1.DenialGroupCount + (*NetworkActivitySummary)(nil), // 225: openshell.v1.NetworkActivitySummary + (*PolicyChunk)(nil), // 226: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 227: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 228: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 229: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 230: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 231: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 232: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 233: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 234: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 235: openshell.v1.RejectDraftChunkResponse + (*DraftChunkApproval)(nil), // 236: openshell.v1.DraftChunkApproval + (*ApproveAllDraftChunksRequest)(nil), // 237: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 238: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 239: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 240: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 241: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 242: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 243: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 244: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 245: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 246: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 247: openshell.v1.GetDraftHistoryResponse + (*CreateWorkspaceRequest)(nil), // 248: openshell.v1.CreateWorkspaceRequest + (*CreateWorkspaceResponse)(nil), // 249: openshell.v1.CreateWorkspaceResponse + (*GetWorkspaceRequest)(nil), // 250: openshell.v1.GetWorkspaceRequest + (*GetWorkspaceResponse)(nil), // 251: openshell.v1.GetWorkspaceResponse + (*ListWorkspacesRequest)(nil), // 252: openshell.v1.ListWorkspacesRequest + (*ListWorkspacesResponse)(nil), // 253: openshell.v1.ListWorkspacesResponse + (*DeleteWorkspaceRequest)(nil), // 254: openshell.v1.DeleteWorkspaceRequest + (*DeleteWorkspaceResponse)(nil), // 255: openshell.v1.DeleteWorkspaceResponse + (*WorkspaceMember)(nil), // 256: openshell.v1.WorkspaceMember + (*AddWorkspaceMemberRequest)(nil), // 257: openshell.v1.AddWorkspaceMemberRequest + (*AddWorkspaceMemberResponse)(nil), // 258: openshell.v1.AddWorkspaceMemberResponse + (*RemoveWorkspaceMemberRequest)(nil), // 259: openshell.v1.RemoveWorkspaceMemberRequest + (*RemoveWorkspaceMemberResponse)(nil), // 260: openshell.v1.RemoveWorkspaceMemberResponse + (*ListWorkspaceMembersRequest)(nil), // 261: openshell.v1.ListWorkspaceMembersRequest + (*ListWorkspaceMembersResponse)(nil), // 262: openshell.v1.ListWorkspaceMembersResponse + (*ExtensionServiceCredential)(nil), // 263: openshell.v1.ExtensionServiceCredential + (*EndpointObservation)(nil), // 264: openshell.v1.EndpointObservation + (*ReportEndpointStatusRequest)(nil), // 265: openshell.v1.ReportEndpointStatusRequest + (*TokenGrantStatus)(nil), // 266: openshell.v1.TokenGrantStatus + (*TokenGrantFailureObservation)(nil), // 267: openshell.v1.TokenGrantFailureObservation + (*ReportEndpointStatusResponse)(nil), // 268: openshell.v1.ReportEndpointStatusResponse + (*EndpointStatus)(nil), // 269: openshell.v1.EndpointStatus + (*SandboxProvisioning)(nil), // 270: openshell.v1.SandboxProvisioning + (*SandboxServiceExposure)(nil), // 271: openshell.v1.SandboxServiceExposure + (*EndpointFailure)(nil), // 272: openshell.v1.EndpointFailure + nil, // 273: openshell.v1.SandboxSpec.EnvironmentEntry + nil, // 274: openshell.v1.SandboxTemplate.LabelsEntry + nil, // 275: openshell.v1.SandboxTemplate.AnnotationsEntry + nil, // 276: openshell.v1.SandboxTemplate.EnvironmentEntry + nil, // 277: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + nil, // 278: openshell.v1.PlatformEvent.MetadataEntry + nil, // 279: openshell.v1.CreateSandboxRequest.LabelsEntry + nil, // 280: openshell.v1.CreateSandboxRequest.AnnotationsEntry + nil, // 281: openshell.v1.SandboxResponse.ServiceUrlsEntry + nil, // 282: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 283: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 284: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry + nil, // 285: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + nil, // 286: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + nil, // 287: openshell.v1.ProviderProfile.AnnotationsEntry + nil, // 288: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + nil, // 289: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + nil, // 290: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + nil, // 291: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + nil, // 292: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + nil, // 293: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + nil, // 294: openshell.v1.ProviderEnvironmentSnapshot.FilesEntry + nil, // 295: openshell.v1.UpdateConfigRequest.AnnotationsEntry + nil, // 296: openshell.v1.UpdateConfigResponse.AnnotationsEntry + nil, // 297: openshell.v1.SandboxPolicyRevision.ProvenanceEntry + nil, // 298: openshell.v1.CreateWorkspaceRequest.LabelsEntry + (*timestamppb.Timestamp)(nil), // 299: google.protobuf.Timestamp + (*datamodelv1.ObjectMeta)(nil), // 300: openshell.datamodel.v1.ObjectMeta + (*sandboxv1.SandboxPolicy)(nil), // 301: openshell.sandbox.v1.SandboxPolicy + (*structpb.Struct)(nil), // 302: google.protobuf.Struct + (*durationpb.Duration)(nil), // 303: google.protobuf.Duration + (*datamodelv1.WorkspaceSelector)(nil), // 304: openshell.datamodel.v1.WorkspaceSelector + (*datamodelv1.Provider)(nil), // 305: openshell.datamodel.v1.Provider + (sandboxv1.PolicySource)(0), // 306: openshell.sandbox.v1.PolicySource + (*sandboxv1.NetworkEndpoint)(nil), // 307: openshell.sandbox.v1.NetworkEndpoint + (*sandboxv1.NetworkBinary)(nil), // 308: openshell.sandbox.v1.NetworkBinary + (*sandboxv1.SettingValue)(nil), // 309: openshell.sandbox.v1.SettingValue + (*sandboxv1.NetworkPolicyRule)(nil), // 310: openshell.sandbox.v1.NetworkPolicyRule + (*sandboxv1.L7DenyRule)(nil), // 311: openshell.sandbox.v1.L7DenyRule + (*sandboxv1.L7Rule)(nil), // 312: openshell.sandbox.v1.L7Rule + (*sandboxv1.SandboxConfigSnapshot)(nil), // 313: openshell.sandbox.v1.SandboxConfigSnapshot + (*datamodelv1.Workspace)(nil), // 314: openshell.datamodel.v1.Workspace + (*sandboxv1.GetSandboxConfigRequest)(nil), // 315: openshell.sandbox.v1.GetSandboxConfigRequest + (*sandboxv1.GetGatewayConfigRequest)(nil), // 316: openshell.sandbox.v1.GetGatewayConfigRequest + (*sandboxv1.GetSandboxConfigResponse)(nil), // 317: openshell.sandbox.v1.GetSandboxConfigResponse + (*sandboxv1.GetGatewayConfigResponse)(nil), // 318: openshell.sandbox.v1.GetGatewayConfigResponse } var file_openshell_proto_depIdxs = []int32{ - 297, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 297, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 261, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential - 297, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp + 299, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 299, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 263, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential + 299, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp 14, // 4: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus 14, // 5: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus 33, // 6: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo @@ -21536,524 +21678,530 @@ var file_openshell_proto_depIdxs = []int32{ 36, // 11: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities 37, // 12: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities 38, // 13: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities - 298, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 300, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 40, // 15: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec 51, // 16: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus 50, // 17: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance - 271, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry + 273, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry 43, // 19: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate - 299, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 301, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy 41, // 21: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements 17, // 22: openshell.v1.SandboxSpec.restart_policy:type_name -> openshell.v1.SandboxRestartPolicy 42, // 23: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements - 272, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry - 273, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry - 274, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry - 300, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct - 300, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct - 298, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 274, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry + 275, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry + 276, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry + 302, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 302, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct + 300, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 45, // 30: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec 46, // 31: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig - 300, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct + 302, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct 48, // 33: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel - 275, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + 277, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry 47, // 35: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources 42, // 36: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements 49, // 37: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup - 301, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 303, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration 52, // 39: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition 1, // 40: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 267, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus - 183, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 268, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning - 297, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp - 297, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp - 265, // 46: openshell.v1.SandboxStatus.last_token_grant_failure:type_name -> openshell.v1.TokenGrantFailureObservation - 297, // 47: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp - 297, // 48: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp - 276, // 49: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 302, // 50: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 269, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus + 185, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 270, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning + 299, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp + 299, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp + 267, // 46: openshell.v1.SandboxStatus.last_token_grant_failure:type_name -> openshell.v1.TokenGrantFailureObservation + 299, // 47: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp + 299, // 48: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp + 278, // 49: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 304, // 50: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 40, // 51: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 277, // 52: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 278, // 53: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 269, // 54: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure - 302, // 55: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 52: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 280, // 53: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 271, // 54: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure + 304, // 55: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 44, // 56: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 302, // 57: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 58: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 59: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 57: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 58: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 59: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 44, // 60: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate 44, // 61: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate 18, // 62: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 302, // 63: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 297, // 64: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp - 302, // 65: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 66: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 67: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 68: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 69: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 70: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 71: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 72: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 39, // 73: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 279, // 74: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry - 39, // 75: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 303, // 76: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 39, // 77: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 81, // 78: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 39, // 79: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 81, // 80: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 79, // 81: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision - 77, // 82: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity - 304, // 83: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource - 5, // 84: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent - 78, // 85: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision - 7, // 86: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState - 6, // 87: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 297, // 88: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp - 297, // 89: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp - 297, // 90: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp - 2, // 91: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind - 77, // 92: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity - 297, // 93: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp - 4, // 94: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason - 81, // 95: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 3, // 96: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState - 4, // 97: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason - 82, // 98: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation - 297, // 99: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp - 297, // 100: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp - 80, // 101: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation - 302, // 102: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 83, // 103: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus - 82, // 104: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation - 301, // 105: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration - 301, // 106: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration - 18, // 107: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 302, // 108: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 297, // 109: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp - 302, // 110: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 20, // 111: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 302, // 112: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 113: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 98, // 114: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 302, // 115: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 116: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 298, // 117: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 20, // 118: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 97, // 119: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint - 18, // 120: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 302, // 121: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 280, // 122: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 301, // 123: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration - 102, // 124: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout - 103, // 125: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr - 104, // 126: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 208, // 127: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 209, // 128: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget - 106, // 129: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit - 101, // 130: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest - 109, // 131: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 298, // 132: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 297, // 133: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp - 302, // 134: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 297, // 135: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp - 39, // 136: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox - 113, // 137: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine - 53, // 138: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent - 114, // 139: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 225, // 140: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 297, // 141: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp - 281, // 142: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 302, // 143: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 303, // 144: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 302, // 145: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 146: openshell.v1.GetProviderCredentialsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 301, // 147: openshell.v1.GetProviderCredentialsRequest.minimum_remaining_lifetime:type_name -> google.protobuf.Duration - 297, // 148: openshell.v1.ProviderCredentialValue.expiration_time:type_name -> google.protobuf.Timestamp - 282, // 149: openshell.v1.GetProviderCredentialsResponse.credentials:type_name -> openshell.v1.GetProviderCredentialsResponse.CredentialsEntry - 302, // 150: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 151: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 303, // 152: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 283, // 153: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - 302, // 154: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 303, // 155: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider - 81, // 156: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt - 303, // 157: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 302, // 158: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 159: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 146, // 160: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 301, // 161: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration - 129, // 162: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride - 8, // 163: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType - 130, // 164: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken - 135, // 165: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh - 131, // 166: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant - 9, // 167: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 301, // 168: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration - 301, // 169: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration - 133, // 170: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial - 134, // 171: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput - 9, // 172: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 297, // 173: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp - 297, // 174: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp - 297, // 175: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp - 16, // 176: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 297, // 177: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp - 302, // 178: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 136, // 179: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 302, // 180: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 9, // 181: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 284, // 182: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 297, // 183: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp - 136, // 184: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 302, // 185: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 136, // 186: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 302, // 187: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 188: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 10, // 189: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory - 132, // 190: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 305, // 191: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 306, // 192: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 137, // 193: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 285, // 194: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 147, // 195: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile - 146, // 196: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 146, // 197: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 302, // 198: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 127, // 199: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 128, // 200: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 146, // 201: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 302, // 202: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 127, // 203: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 128, // 204: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 146, // 205: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 302, // 206: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 127, // 207: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 128, // 208: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 18, // 209: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 302, // 210: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 211: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 160, // 212: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 286, // 213: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 287, // 214: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - 288, // 215: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 289, // 216: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 4, // 217: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 290, // 218: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - 11, // 219: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification - 161, // 220: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding - 297, // 221: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp - 163, // 222: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue - 291, // 223: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry - 4, // 224: openshell.v1.ProviderEnvironmentSnapshot.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 292, // 225: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry - 301, // 226: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration - 302, // 227: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 299, // 228: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 307, // 229: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 168, // 230: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 293, // 231: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 169, // 232: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 170, // 233: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 171, // 234: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 173, // 235: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 174, // 236: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 175, // 237: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 308, // 238: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 306, // 239: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 309, // 240: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 172, // 241: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget - 310, // 242: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 172, // 243: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget - 294, // 244: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 302, // 245: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 186, // 246: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 302, // 247: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 186, // 248: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 13, // 249: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 12, // 250: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState - 183, // 251: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 13, // 252: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 297, // 253: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp - 297, // 254: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp - 299, // 255: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 295, // 256: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 302, // 257: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 297, // 258: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp - 113, // 259: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 113, // 260: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 193, // 261: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 201, // 262: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 218, // 263: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 219, // 264: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 197, // 265: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult - 194, // 266: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 199, // 267: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 202, // 268: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 207, // 269: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 219, // 270: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 200, // 271: openshell.v1.GatewayMessage.session_redirect:type_name -> openshell.v1.SessionRedirect - 195, // 272: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate - 195, // 273: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigUpdate - 301, // 274: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration - 311, // 275: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot - 164, // 276: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot - 6, // 277: openshell.v1.ConfigUpdateResult.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 196, // 278: openshell.v1.ConfigUpdateResult.failure:type_name -> openshell.v1.ConfigApplyFailure - 183, // 279: openshell.v1.ConfigUpdateResult.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 198, // 280: openshell.v1.ConfigUpdateResult.policy_load:type_name -> openshell.v1.PolicyLoadResult - 208, // 281: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 209, // 282: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 210, // 283: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 207, // 284: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen - 212, // 285: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit - 214, // 286: openshell.v1.PeerNotifyConfigUpdateRequest.sandbox:type_name -> openshell.v1.PeerConfigSandboxTarget - 215, // 287: openshell.v1.PeerNotifyConfigUpdateRequest.provider:type_name -> openshell.v1.PeerConfigProviderTarget - 297, // 288: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp - 297, // 289: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp - 220, // 290: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 222, // 291: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 308, // 292: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 297, // 293: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp - 297, // 294: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp - 297, // 295: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp - 297, // 296: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp - 299, // 297: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 299, // 298: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 302, // 299: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 221, // 300: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 224, // 301: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 223, // 302: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 302, // 303: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 224, // 304: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 297, // 305: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp - 302, // 306: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 307: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 308: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 234, // 309: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval - 302, // 310: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 308, // 311: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 302, // 312: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 313: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 302, // 314: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 297, // 315: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp - 244, // 316: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 296, // 317: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 312, // 318: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 312, // 319: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 312, // 320: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 18, // 321: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 298, // 322: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 15, // 323: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 302, // 324: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 15, // 325: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 254, // 326: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 302, // 327: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 18, // 328: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 302, // 329: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 254, // 330: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 297, // 331: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp - 19, // 332: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult - 270, // 333: openshell.v1.EndpointObservation.failure:type_name -> openshell.v1.EndpointFailure - 262, // 334: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation - 264, // 335: openshell.v1.ReportEndpointStatusRequest.token_grant_status:type_name -> openshell.v1.TokenGrantStatus - 265, // 336: openshell.v1.TokenGrantStatus.last_failure:type_name -> openshell.v1.TokenGrantFailureObservation - 270, // 337: openshell.v1.TokenGrantFailureObservation.failure:type_name -> openshell.v1.EndpointFailure - 19, // 338: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult - 297, // 339: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp - 270, // 340: openshell.v1.EndpointStatus.last_failure:type_name -> openshell.v1.EndpointFailure - 297, // 341: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp - 297, // 342: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp - 297, // 343: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp - 297, // 344: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp - 297, // 345: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp - 297, // 346: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp - 297, // 347: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp - 297, // 348: openshell.v1.SandboxProvisioning.preparation_deadline:type_name -> google.protobuf.Timestamp - 297, // 349: openshell.v1.SandboxProvisioning.admission_start_time:type_name -> google.protobuf.Timestamp - 20, // 350: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode - 21, // 351: openshell.v1.EndpointFailure.domain:type_name -> openshell.v1.EndpointFailureDomain - 16, // 352: openshell.v1.EndpointFailure.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 118, // 353: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry.value:type_name -> openshell.v1.ProviderCredentialValue - 297, // 354: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 297, // 355: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 132, // 356: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 161, // 357: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 132, // 358: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 26, // 359: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 28, // 360: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 30, // 361: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 54, // 362: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 62, // 363: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest - 64, // 364: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 65, // 365: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 55, // 366: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 56, // 367: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 57, // 368: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 58, // 369: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 66, // 370: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 67, // 371: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 68, // 372: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 84, // 373: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 69, // 374: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 70, // 375: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 71, // 376: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 89, // 377: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 91, // 378: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 92, // 379: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 93, // 380: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 95, // 381: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 99, // 382: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 101, // 383: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 107, // 384: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 108, // 385: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 115, // 386: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 116, // 387: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 117, // 388: openshell.v1.OpenShell.GetProviderCredentials:input_type -> openshell.v1.GetProviderCredentialsRequest - 120, // 389: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 125, // 390: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 126, // 391: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 150, // 392: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 152, // 393: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 154, // 394: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 121, // 395: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 138, // 396: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 140, // 397: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 142, // 398: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 144, // 399: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 122, // 400: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 157, // 401: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 313, // 402: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 314, // 403: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 167, // 404: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 177, // 405: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 179, // 406: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 181, // 407: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 263, // 408: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 86, // 409: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 184, // 410: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest - 159, // 411: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 165, // 412: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest - 187, // 413: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 188, // 414: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 191, // 415: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 203, // 416: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest - 205, // 417: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest - 211, // 418: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 213, // 419: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame - 86, // 420: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 263, // 421: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 84, // 422: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 216, // 423: openshell.v1.OpenShell.PeerNotifyConfigUpdate:input_type -> openshell.v1.PeerNotifyConfigUpdateRequest - 111, // 424: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 226, // 425: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 228, // 426: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 230, // 427: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 232, // 428: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 235, // 429: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 237, // 430: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 239, // 431: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 241, // 432: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 243, // 433: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 22, // 434: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 24, // 435: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 246, // 436: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 248, // 437: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 250, // 438: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 252, // 439: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 255, // 440: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 257, // 441: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 259, // 442: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 27, // 443: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 29, // 444: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 31, // 445: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 72, // 446: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 63, // 447: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse - 72, // 448: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 73, // 449: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 59, // 450: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 59, // 451: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 60, // 452: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 61, // 453: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 74, // 454: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 75, // 455: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 76, // 456: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 85, // 457: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 88, // 458: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 72, // 459: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 72, // 460: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 90, // 461: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 98, // 462: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 98, // 463: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 94, // 464: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 96, // 465: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 100, // 466: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 105, // 467: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 107, // 468: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 105, // 469: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 123, // 470: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 123, // 471: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 119, // 472: openshell.v1.OpenShell.GetProviderCredentials:output_type -> openshell.v1.GetProviderCredentialsResponse - 124, // 473: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 149, // 474: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 148, // 475: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 151, // 476: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 153, // 477: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 155, // 478: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 123, // 479: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 139, // 480: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 141, // 481: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 143, // 482: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 145, // 483: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 156, // 484: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 158, // 485: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 315, // 486: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 316, // 487: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 176, // 488: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 178, // 489: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 180, // 490: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 182, // 491: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 266, // 492: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 87, // 493: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 185, // 494: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse - 162, // 495: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 166, // 496: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse - 190, // 497: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 189, // 498: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 192, // 499: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 204, // 500: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse - 206, // 501: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse - 211, // 502: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 213, // 503: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame - 87, // 504: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 266, // 505: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 85, // 506: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 217, // 507: openshell.v1.OpenShell.PeerNotifyConfigUpdate:output_type -> openshell.v1.PeerNotifyConfigUpdateResponse - 112, // 508: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 227, // 509: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 229, // 510: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 231, // 511: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 233, // 512: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 236, // 513: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 238, // 514: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 240, // 515: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 242, // 516: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 245, // 517: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 23, // 518: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 25, // 519: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 247, // 520: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 249, // 521: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 251, // 522: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 253, // 523: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 256, // 524: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 258, // 525: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 260, // 526: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 443, // [443:527] is the sub-list for method output_type - 359, // [359:443] is the sub-list for method input_type - 359, // [359:359] is the sub-list for extension type_name - 359, // [359:359] is the sub-list for extension extendee - 0, // [0:359] is the sub-list for field type_name + 304, // 63: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 299, // 64: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp + 304, // 65: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 66: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 67: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 68: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 69: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 70: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 71: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 72: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 73: openshell.v1.SuspendSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 74: openshell.v1.ResumeSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 39, // 75: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox + 281, // 76: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry + 39, // 77: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox + 305, // 78: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 39, // 79: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 83, // 80: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 39, // 81: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 83, // 82: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 81, // 83: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision + 79, // 84: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity + 306, // 85: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 5, // 86: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent + 80, // 87: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision + 7, // 88: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState + 6, // 89: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome + 299, // 90: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp + 299, // 91: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp + 299, // 92: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp + 2, // 93: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind + 79, // 94: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity + 299, // 95: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp + 4, // 96: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason + 83, // 97: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 3, // 98: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState + 4, // 99: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason + 84, // 100: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation + 299, // 101: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp + 299, // 102: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp + 82, // 103: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation + 304, // 104: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 85, // 105: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus + 84, // 106: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation + 303, // 107: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration + 303, // 108: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration + 18, // 109: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 304, // 110: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 299, // 111: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp + 304, // 112: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 20, // 113: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 304, // 114: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 115: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 100, // 116: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse + 304, // 117: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 118: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 300, // 119: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 20, // 120: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 99, // 121: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint + 18, // 122: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 304, // 123: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 282, // 124: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 303, // 125: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration + 104, // 126: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout + 105, // 127: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr + 106, // 128: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit + 210, // 129: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget + 211, // 130: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget + 108, // 131: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit + 103, // 132: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest + 111, // 133: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize + 300, // 134: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 299, // 135: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp + 304, // 136: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 299, // 137: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp + 39, // 138: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox + 115, // 139: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine + 53, // 140: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent + 116, // 141: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning + 227, // 142: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 299, // 143: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp + 283, // 144: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 304, // 145: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 146: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 304, // 147: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 148: openshell.v1.GetProviderCredentialsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 303, // 149: openshell.v1.GetProviderCredentialsRequest.minimum_remaining_lifetime:type_name -> google.protobuf.Duration + 299, // 150: openshell.v1.ProviderCredentialValue.expiration_time:type_name -> google.protobuf.Timestamp + 284, // 151: openshell.v1.GetProviderCredentialsResponse.credentials:type_name -> openshell.v1.GetProviderCredentialsResponse.CredentialsEntry + 304, // 152: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 153: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 154: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 285, // 155: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + 304, // 156: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 305, // 157: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 83, // 158: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt + 305, // 159: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 304, // 160: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 161: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 148, // 162: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile + 303, // 163: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration + 131, // 164: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride + 8, // 165: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType + 132, // 166: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken + 137, // 167: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh + 133, // 168: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant + 9, // 169: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 303, // 170: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration + 303, // 171: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration + 135, // 172: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial + 136, // 173: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput + 9, // 174: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 299, // 175: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp + 299, // 176: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp + 299, // 177: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp + 16, // 178: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 299, // 179: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp + 304, // 180: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 138, // 181: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 304, // 182: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 9, // 183: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 286, // 184: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 299, // 185: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp + 138, // 186: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 304, // 187: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 138, // 188: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 304, // 189: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 190: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 10, // 191: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory + 134, // 192: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential + 307, // 193: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 308, // 194: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 139, // 195: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery + 287, // 196: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 149, // 197: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile + 148, // 198: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile + 148, // 199: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 304, // 200: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 129, // 201: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 130, // 202: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 148, // 203: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 304, // 204: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 129, // 205: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem + 130, // 206: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 148, // 207: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile + 304, // 208: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 129, // 209: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 130, // 210: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 18, // 211: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 304, // 212: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 213: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 162, // 214: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding + 288, // 215: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 289, // 216: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + 290, // 217: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 291, // 218: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 4, // 219: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason + 292, // 220: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + 11, // 221: openshell.v1.ProviderEnvironmentValue.classification:type_name -> openshell.v1.ProviderEnvironmentValueClassification + 163, // 222: openshell.v1.ProviderEnvironmentValue.static_credential_binding:type_name -> openshell.v1.StaticCredentialBinding + 299, // 223: openshell.v1.ProviderEnvironmentValue.expiration_time:type_name -> google.protobuf.Timestamp + 165, // 224: openshell.v1.ProviderEnvironmentSnapshot.values:type_name -> openshell.v1.ProviderEnvironmentValue + 293, // 225: openshell.v1.ProviderEnvironmentSnapshot.dynamic_credentials:type_name -> openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry + 4, // 226: openshell.v1.ProviderEnvironmentSnapshot.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason + 294, // 227: openshell.v1.ProviderEnvironmentSnapshot.files:type_name -> openshell.v1.ProviderEnvironmentSnapshot.FilesEntry + 303, // 228: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration + 304, // 229: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 301, // 230: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 309, // 231: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 170, // 232: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation + 295, // 233: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 171, // 234: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule + 172, // 235: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint + 173, // 236: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule + 175, // 237: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules + 176, // 238: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules + 177, // 239: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary + 310, // 240: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 308, // 241: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 311, // 242: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 174, // 243: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget + 312, // 244: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 174, // 245: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget + 296, // 246: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 304, // 247: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 188, // 248: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 304, // 249: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 188, // 250: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 13, // 251: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 12, // 252: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState + 185, // 253: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 13, // 254: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 299, // 255: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp + 299, // 256: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp + 301, // 257: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 297, // 258: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 304, // 259: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 299, // 260: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp + 115, // 261: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 115, // 262: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 195, // 263: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello + 203, // 264: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat + 220, // 265: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 221, // 266: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 199, // 267: openshell.v1.SupervisorMessage.config_update_result:type_name -> openshell.v1.ConfigUpdateResult + 196, // 268: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted + 201, // 269: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected + 204, // 270: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat + 209, // 271: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen + 221, // 272: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 202, // 273: openshell.v1.GatewayMessage.session_redirect:type_name -> openshell.v1.SessionRedirect + 197, // 274: openshell.v1.GatewayMessage.config_update:type_name -> openshell.v1.ConfigUpdate + 197, // 275: openshell.v1.SessionAccepted.bootstrap:type_name -> openshell.v1.ConfigUpdate + 303, // 276: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration + 313, // 277: openshell.v1.ConfigUpdate.sandbox_config:type_name -> openshell.sandbox.v1.SandboxConfigSnapshot + 166, // 278: openshell.v1.ConfigUpdate.provider_environment:type_name -> openshell.v1.ProviderEnvironmentSnapshot + 6, // 279: openshell.v1.ConfigUpdateResult.outcome:type_name -> openshell.v1.ConfigApplyOutcome + 198, // 280: openshell.v1.ConfigUpdateResult.failure:type_name -> openshell.v1.ConfigApplyFailure + 185, // 281: openshell.v1.ConfigUpdateResult.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 200, // 282: openshell.v1.ConfigUpdateResult.policy_load:type_name -> openshell.v1.PolicyLoadResult + 210, // 283: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget + 211, // 284: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget + 212, // 285: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit + 209, // 286: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen + 214, // 287: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit + 216, // 288: openshell.v1.PeerNotifyConfigUpdateRequest.sandbox:type_name -> openshell.v1.PeerConfigSandboxTarget + 217, // 289: openshell.v1.PeerNotifyConfigUpdateRequest.provider:type_name -> openshell.v1.PeerConfigProviderTarget + 299, // 290: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp + 299, // 291: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp + 222, // 292: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 224, // 293: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 310, // 294: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 299, // 295: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp + 299, // 296: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp + 299, // 297: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp + 299, // 298: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp + 301, // 299: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 301, // 300: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 304, // 301: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 223, // 302: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 226, // 303: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 225, // 304: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 304, // 305: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 226, // 306: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 299, // 307: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp + 304, // 308: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 309: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 310: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 236, // 311: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval + 304, // 312: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 310, // 313: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 304, // 314: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 315: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 304, // 316: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 299, // 317: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp + 246, // 318: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 298, // 319: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 314, // 320: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 314, // 321: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 314, // 322: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 18, // 323: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 300, // 324: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 15, // 325: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 304, // 326: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 15, // 327: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 256, // 328: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 304, // 329: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 18, // 330: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 304, // 331: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 256, // 332: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 299, // 333: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp + 19, // 334: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult + 272, // 335: openshell.v1.EndpointObservation.failure:type_name -> openshell.v1.EndpointFailure + 264, // 336: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation + 266, // 337: openshell.v1.ReportEndpointStatusRequest.token_grant_status:type_name -> openshell.v1.TokenGrantStatus + 267, // 338: openshell.v1.TokenGrantStatus.last_failure:type_name -> openshell.v1.TokenGrantFailureObservation + 272, // 339: openshell.v1.TokenGrantFailureObservation.failure:type_name -> openshell.v1.EndpointFailure + 19, // 340: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult + 299, // 341: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp + 272, // 342: openshell.v1.EndpointStatus.last_failure:type_name -> openshell.v1.EndpointFailure + 299, // 343: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp + 299, // 344: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp + 299, // 345: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp + 299, // 346: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp + 299, // 347: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp + 299, // 348: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp + 299, // 349: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp + 299, // 350: openshell.v1.SandboxProvisioning.preparation_deadline:type_name -> google.protobuf.Timestamp + 299, // 351: openshell.v1.SandboxProvisioning.admission_start_time:type_name -> google.protobuf.Timestamp + 20, // 352: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 21, // 353: openshell.v1.EndpointFailure.domain:type_name -> openshell.v1.EndpointFailureDomain + 16, // 354: openshell.v1.EndpointFailure.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 120, // 355: openshell.v1.GetProviderCredentialsResponse.CredentialsEntry.value:type_name -> openshell.v1.ProviderCredentialValue + 299, // 356: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 299, // 357: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 134, // 358: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 163, // 359: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 134, // 360: openshell.v1.ProviderEnvironmentSnapshot.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 26, // 361: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 28, // 362: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 30, // 363: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 54, // 364: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 62, // 365: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest + 64, // 366: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 65, // 367: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 55, // 368: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 56, // 369: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 57, // 370: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 58, // 371: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 66, // 372: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 67, // 373: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 68, // 374: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 86, // 375: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 69, // 376: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 70, // 377: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 71, // 378: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 72, // 379: openshell.v1.OpenShell.SuspendSandbox:input_type -> openshell.v1.SuspendSandboxRequest + 73, // 380: openshell.v1.OpenShell.ResumeSandbox:input_type -> openshell.v1.ResumeSandboxRequest + 91, // 381: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 93, // 382: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 94, // 383: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 95, // 384: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 97, // 385: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 101, // 386: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 103, // 387: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 109, // 388: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 110, // 389: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 117, // 390: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 118, // 391: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 119, // 392: openshell.v1.OpenShell.GetProviderCredentials:input_type -> openshell.v1.GetProviderCredentialsRequest + 122, // 393: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 127, // 394: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 128, // 395: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 152, // 396: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 154, // 397: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 156, // 398: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 123, // 399: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 140, // 400: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 142, // 401: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 144, // 402: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 146, // 403: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 124, // 404: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 159, // 405: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 315, // 406: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 316, // 407: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 169, // 408: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 179, // 409: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 181, // 410: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 183, // 411: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 265, // 412: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 88, // 413: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 186, // 414: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest + 161, // 415: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 167, // 416: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest + 189, // 417: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 190, // 418: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 193, // 419: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 205, // 420: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest + 207, // 421: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest + 213, // 422: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 215, // 423: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame + 88, // 424: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 265, // 425: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 86, // 426: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 218, // 427: openshell.v1.OpenShell.PeerNotifyConfigUpdate:input_type -> openshell.v1.PeerNotifyConfigUpdateRequest + 113, // 428: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 228, // 429: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 230, // 430: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 232, // 431: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 234, // 432: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 237, // 433: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 239, // 434: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 241, // 435: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 243, // 436: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 245, // 437: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 22, // 438: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 24, // 439: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 248, // 440: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 250, // 441: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 252, // 442: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 254, // 443: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 257, // 444: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 259, // 445: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 261, // 446: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 27, // 447: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 29, // 448: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 31, // 449: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 74, // 450: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 63, // 451: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse + 74, // 452: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 75, // 453: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 59, // 454: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 59, // 455: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 60, // 456: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 61, // 457: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 76, // 458: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 77, // 459: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 78, // 460: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 87, // 461: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 90, // 462: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 74, // 463: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 74, // 464: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 74, // 465: openshell.v1.OpenShell.SuspendSandbox:output_type -> openshell.v1.SandboxResponse + 74, // 466: openshell.v1.OpenShell.ResumeSandbox:output_type -> openshell.v1.SandboxResponse + 92, // 467: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 100, // 468: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 100, // 469: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 96, // 470: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 98, // 471: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 102, // 472: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 107, // 473: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 109, // 474: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 107, // 475: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 125, // 476: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 125, // 477: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 121, // 478: openshell.v1.OpenShell.GetProviderCredentials:output_type -> openshell.v1.GetProviderCredentialsResponse + 126, // 479: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 151, // 480: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 150, // 481: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 153, // 482: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 155, // 483: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 157, // 484: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 125, // 485: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 141, // 486: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 143, // 487: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 145, // 488: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 147, // 489: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 158, // 490: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 160, // 491: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 317, // 492: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 318, // 493: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 178, // 494: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 180, // 495: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 182, // 496: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 184, // 497: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 268, // 498: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 89, // 499: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 187, // 500: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse + 164, // 501: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 168, // 502: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse + 192, // 503: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 191, // 504: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 194, // 505: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 206, // 506: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse + 208, // 507: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse + 213, // 508: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 215, // 509: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame + 89, // 510: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 268, // 511: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 87, // 512: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 219, // 513: openshell.v1.OpenShell.PeerNotifyConfigUpdate:output_type -> openshell.v1.PeerNotifyConfigUpdateResponse + 114, // 514: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 229, // 515: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 231, // 516: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 233, // 517: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 235, // 518: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 238, // 519: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 240, // 520: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 242, // 521: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 244, // 522: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 247, // 523: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 23, // 524: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 25, // 525: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 249, // 526: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 251, // 527: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 253, // 528: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 255, // 529: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 258, // 530: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 260, // 531: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 262, // 532: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 447, // [447:533] is the sub-list for method output_type + 361, // [361:447] is the sub-list for method input_type + 361, // [361:361] is the sub-list for extension type_name + 361, // [361:361] is the sub-list for extension extendee + 0, // [0:361] is the sub-list for field type_name } func init() { file_openshell_proto_init() } @@ -22064,37 +22212,37 @@ func file_openshell_proto_init() { file_openshell_proto_msgTypes[20].OneofWrappers = []any{} file_openshell_proto_msgTypes[21].OneofWrappers = []any{} file_openshell_proto_msgTypes[29].OneofWrappers = []any{} - file_openshell_proto_msgTypes[56].OneofWrappers = []any{ + file_openshell_proto_msgTypes[58].OneofWrappers = []any{ (*ConfigSnapshotRevision_SandboxConfig)(nil), (*ConfigSnapshotRevision_ProviderEnvironment)(nil), (*ConfigSnapshotRevision_ProviderTarget)(nil), } - file_openshell_proto_msgTypes[83].OneofWrappers = []any{ + file_openshell_proto_msgTypes[85].OneofWrappers = []any{ (*ExecSandboxEvent_Stdout)(nil), (*ExecSandboxEvent_Stderr)(nil), (*ExecSandboxEvent_Exit)(nil), } - file_openshell_proto_msgTypes[84].OneofWrappers = []any{ + file_openshell_proto_msgTypes[86].OneofWrappers = []any{ (*TcpForwardInit_Ssh)(nil), (*TcpForwardInit_Tcp)(nil), } - file_openshell_proto_msgTypes[85].OneofWrappers = []any{ + file_openshell_proto_msgTypes[87].OneofWrappers = []any{ (*TcpForwardFrame_Init)(nil), (*TcpForwardFrame_Data)(nil), } - file_openshell_proto_msgTypes[86].OneofWrappers = []any{ + file_openshell_proto_msgTypes[88].OneofWrappers = []any{ (*ExecSandboxInput_Start)(nil), (*ExecSandboxInput_Stdin)(nil), (*ExecSandboxInput_Resize)(nil), } - file_openshell_proto_msgTypes[90].OneofWrappers = []any{ + file_openshell_proto_msgTypes[92].OneofWrappers = []any{ (*SandboxStreamEvent_Sandbox)(nil), (*SandboxStreamEvent_Log)(nil), (*SandboxStreamEvent_Event)(nil), (*SandboxStreamEvent_Warning)(nil), (*SandboxStreamEvent_DraftPolicyUpdate)(nil), } - file_openshell_proto_msgTypes[146].OneofWrappers = []any{ + file_openshell_proto_msgTypes[148].OneofWrappers = []any{ (*PolicyMergeOperation_AddRule)(nil), (*PolicyMergeOperation_RemoveEndpoint)(nil), (*PolicyMergeOperation_RemoveRule)(nil), @@ -22102,15 +22250,15 @@ func file_openshell_proto_init() { (*PolicyMergeOperation_AddAllowRules)(nil), (*PolicyMergeOperation_RemoveBinary)(nil), } - file_openshell_proto_msgTypes[150].OneofWrappers = []any{} - file_openshell_proto_msgTypes[169].OneofWrappers = []any{ + file_openshell_proto_msgTypes[152].OneofWrappers = []any{} + file_openshell_proto_msgTypes[171].OneofWrappers = []any{ (*SupervisorMessage_Hello)(nil), (*SupervisorMessage_Heartbeat)(nil), (*SupervisorMessage_RelayOpenResult)(nil), (*SupervisorMessage_RelayClose)(nil), (*SupervisorMessage_ConfigUpdateResult)(nil), } - file_openshell_proto_msgTypes[170].OneofWrappers = []any{ + file_openshell_proto_msgTypes[172].OneofWrappers = []any{ (*GatewayMessage_SessionAccepted)(nil), (*GatewayMessage_SessionRejected)(nil), (*GatewayMessage_Heartbeat)(nil), @@ -22119,32 +22267,32 @@ func file_openshell_proto_init() { (*GatewayMessage_SessionRedirect)(nil), (*GatewayMessage_ConfigUpdate)(nil), } - file_openshell_proto_msgTypes[185].OneofWrappers = []any{ + file_openshell_proto_msgTypes[187].OneofWrappers = []any{ (*RelayOpen_Ssh)(nil), (*RelayOpen_Tcp)(nil), } - file_openshell_proto_msgTypes[189].OneofWrappers = []any{ + file_openshell_proto_msgTypes[191].OneofWrappers = []any{ (*RelayFrame_Init)(nil), (*RelayFrame_Data)(nil), } - file_openshell_proto_msgTypes[191].OneofWrappers = []any{ + file_openshell_proto_msgTypes[193].OneofWrappers = []any{ (*PeerRelayFrame_Init)(nil), (*PeerRelayFrame_Data)(nil), } - file_openshell_proto_msgTypes[194].OneofWrappers = []any{ + file_openshell_proto_msgTypes[196].OneofWrappers = []any{ (*PeerNotifyConfigUpdateRequest_Sandbox)(nil), (*PeerNotifyConfigUpdateRequest_Workspace)(nil), (*PeerNotifyConfigUpdateRequest_AllConnected)(nil), (*PeerNotifyConfigUpdateRequest_Provider)(nil), } - file_openshell_proto_msgTypes[248].OneofWrappers = []any{} + file_openshell_proto_msgTypes[250].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_openshell_proto_rawDesc), len(file_openshell_proto_rawDesc)), NumEnums: 22, - NumMessages: 275, + NumMessages: 277, 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 57f17c466b..2f13a80383 100644 --- a/sdk/go/proto/openshellv1/openshell_grpc.pb.go +++ b/sdk/go/proto/openshellv1/openshell_grpc.pb.go @@ -41,6 +41,8 @@ const ( OpenShell_DeleteSandbox_FullMethodName = "/openshell.v1.OpenShell/DeleteSandbox" OpenShell_StopSandbox_FullMethodName = "/openshell.v1.OpenShell/StopSandbox" OpenShell_StartSandbox_FullMethodName = "/openshell.v1.OpenShell/StartSandbox" + OpenShell_SuspendSandbox_FullMethodName = "/openshell.v1.OpenShell/SuspendSandbox" + OpenShell_ResumeSandbox_FullMethodName = "/openshell.v1.OpenShell/ResumeSandbox" OpenShell_CreateSshSession_FullMethodName = "/openshell.v1.OpenShell/CreateSshSession" OpenShell_ExposeService_FullMethodName = "/openshell.v1.OpenShell/ExposeService" OpenShell_GetService_FullMethodName = "/openshell.v1.OpenShell/GetService" @@ -165,6 +167,12 @@ type OpenShellClient interface { StopSandbox(ctx context.Context, in *StopSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) // Start a previously stopped sandbox. StartSandbox(ctx context.Context, in *StartSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) + // Freeze a ready sandbox and retain its memory state for a later resume. + // Requires a compute driver and isolation backend that support state + // retention. + SuspendSandbox(ctx context.Context, in *SuspendSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) + // Restore a suspended sandbox in a new runtime generation. + ResumeSandbox(ctx context.Context, in *ResumeSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) // Create a short-lived SSH session for a sandbox. CreateSshSession(ctx context.Context, in *CreateSshSessionRequest, opts ...grpc.CallOption) (*CreateSshSessionResponse, error) // Create or update a sandbox HTTP service endpoint for local routing. @@ -539,6 +547,26 @@ func (c *openShellClient) StartSandbox(ctx context.Context, in *StartSandboxRequ return out, nil } +func (c *openShellClient) SuspendSandbox(ctx context.Context, in *SuspendSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SandboxResponse) + err := c.cc.Invoke(ctx, OpenShell_SuspendSandbox_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) ResumeSandbox(ctx context.Context, in *ResumeSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SandboxResponse) + err := c.cc.Invoke(ctx, OpenShell_ResumeSandbox_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *openShellClient) CreateSshSession(ctx context.Context, in *CreateSshSessionRequest, opts ...grpc.CallOption) (*CreateSshSessionResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateSshSessionResponse) @@ -1291,6 +1319,12 @@ type OpenShellServer interface { StopSandbox(context.Context, *StopSandboxRequest) (*SandboxResponse, error) // Start a previously stopped sandbox. StartSandbox(context.Context, *StartSandboxRequest) (*SandboxResponse, error) + // Freeze a ready sandbox and retain its memory state for a later resume. + // Requires a compute driver and isolation backend that support state + // retention. + SuspendSandbox(context.Context, *SuspendSandboxRequest) (*SandboxResponse, error) + // Restore a suspended sandbox in a new runtime generation. + ResumeSandbox(context.Context, *ResumeSandboxRequest) (*SandboxResponse, error) // Create a short-lived SSH session for a sandbox. CreateSshSession(context.Context, *CreateSshSessionRequest) (*CreateSshSessionResponse, error) // Create or update a sandbox HTTP service endpoint for local routing. @@ -1539,6 +1573,12 @@ func (UnimplementedOpenShellServer) StopSandbox(context.Context, *StopSandboxReq func (UnimplementedOpenShellServer) StartSandbox(context.Context, *StartSandboxRequest) (*SandboxResponse, error) { return nil, status.Error(codes.Unimplemented, "method StartSandbox not implemented") } +func (UnimplementedOpenShellServer) SuspendSandbox(context.Context, *SuspendSandboxRequest) (*SandboxResponse, error) { + return nil, status.Error(codes.Unimplemented, "method SuspendSandbox not implemented") +} +func (UnimplementedOpenShellServer) ResumeSandbox(context.Context, *ResumeSandboxRequest) (*SandboxResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ResumeSandbox not implemented") +} func (UnimplementedOpenShellServer) CreateSshSession(context.Context, *CreateSshSessionRequest) (*CreateSshSessionResponse, error) { return nil, status.Error(codes.Unimplemented, "method CreateSshSession not implemented") } @@ -2082,6 +2122,42 @@ func _OpenShell_StartSandbox_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _OpenShell_SuspendSandbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SuspendSandboxRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).SuspendSandbox(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_SuspendSandbox_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).SuspendSandbox(ctx, req.(*SuspendSandboxRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_ResumeSandbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResumeSandboxRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).ResumeSandbox(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_ResumeSandbox_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).ResumeSandbox(ctx, req.(*ResumeSandboxRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _OpenShell_CreateSshSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CreateSshSessionRequest) if err := dec(in); err != nil { @@ -3269,6 +3345,14 @@ var OpenShell_ServiceDesc = grpc.ServiceDesc{ MethodName: "StartSandbox", Handler: _OpenShell_StartSandbox_Handler, }, + { + MethodName: "SuspendSandbox", + Handler: _OpenShell_SuspendSandbox_Handler, + }, + { + MethodName: "ResumeSandbox", + Handler: _OpenShell_ResumeSandbox_Handler, + }, { MethodName: "CreateSshSession", Handler: _OpenShell_CreateSshSession_Handler, diff --git a/sdk/typescript/src/client.test.ts b/sdk/typescript/src/client.test.ts index 84272562d1..86fdfa3972 100644 --- a/sdk/typescript/src/client.test.ts +++ b/sdk/typescript/src/client.test.ts @@ -1349,6 +1349,21 @@ describe('waits', () => { await expect(sandbox.waitReady('sb', 30)).rejects.toMatchObject({ code: 'connect' }); }); + it('waitReady rejects suspended sandboxes without waiting for timeout', async () => { + const sandbox = client({ + getSandbox: () => ({ + sandbox: { + metadata: { id: 'sb-id', name: 'sb' }, + status: { phase: SandboxPhase.SUSPENDED }, + }, + }), + }); + await expect(sandbox.waitReady('sb', 30)).rejects.toMatchObject({ + code: 'connect', + message: expect.stringContaining('suspended'), + }); + }); + it('waitReady rejects rather than hanging when get() never resolves', async () => { const sandbox = client({ // Only settles when the per-poll deadline signal aborts the call. diff --git a/sdk/typescript/src/client.ts b/sdk/typescript/src/client.ts index 74ade2297d..f82242d4a7 100644 --- a/sdk/typescript/src/client.ts +++ b/sdk/typescript/src/client.ts @@ -105,7 +105,9 @@ export type SandboxPhaseName = | 'stopping' | 'stopped' | 'starting' - | 'completed'; + | 'completed' + | 'suspending' + | 'suspended'; /** Restart behavior after the canonical main process exits. */ export type SandboxRestartPolicyName = 'never' | 'on-failure' | 'always'; @@ -577,6 +579,8 @@ export const PHASE_NAMES: Record = { [SandboxPhase.STOPPED]: 'stopped', [SandboxPhase.STARTING]: 'starting', [SandboxPhase.COMPLETED]: 'completed', + [SandboxPhase.SUSPENDING]: 'suspending', + [SandboxPhase.SUSPENDED]: 'suspended', }; export const STATUS_NAMES: Record = { [ServiceStatus.UNSPECIFIED]: 'unspecified', @@ -1337,6 +1341,9 @@ export class SandboxClient { if (ref.phase === 'ready' || ref.phase === 'completed') return ref; if (ref.phase === 'stopped') throw new SdkError('connect', `sandbox '${name}' stopped before becoming ready`); if (ref.phase === 'error') throw new SdkError('connect', `sandbox '${name}' entered error phase`); + if (ref.phase === 'suspending' || ref.phase === 'suspended') { + throw new SdkError('connect', `sandbox '${name}' is suspended; resume it before waiting for ready`); + } if (Date.now() >= deadline) throw new SdkError('connect', `timed out waiting for sandbox '${name}'`); await waitSleep(delay, deadline, signal); delay = Math.min(delay * 2, 2000); diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index 84e6d65a2c..f87e06fdff 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -536,6 +536,24 @@ for verification behavior and release compatibility. For an infrastructure `Error` on a backend that supports restarting stopped sandboxes, fix the reported cause, run `sandbox stop`, and wait for it to succeed before running `sandbox start`. This retains the sandbox and persistent workspace but cannot recover deleted resources or storage. For a provisioning timeout, wait for cleanup to finish, then run `sandbox start` directly. +### Suspend and resume sandboxes + +On a gateway whose compute driver and isolation backend support it, suspend +freezes a `Ready` sandbox and retains its memory state: + +```bash +openshell sandbox suspend [name] +openshell sandbox resume [name] +``` + +Suspend waits for `Suspended`, then stops background forwards. A rejected +suspend leaves forwards running. Resume restores the state in a new runtime +generation and waits for `Ready`. A gateway without +support rejects suspend with `FAILED_PRECONDITION`. Resume fails when retained +state cannot be restored; use `sandbox start` for an explicit clean boot. `sandbox start`, +`sandbox stop`, and `sandbox delete` on a suspended sandbox discard the +retained memory state. + --- ## Workflow 4: Policy Iteration Loop