From d64ffc52a85155c073f3e6befdbdfc5d6217f89d Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 19 Aug 2026 13:11:42 +0100 Subject: [PATCH 1/9] feat(server): add sandbox workload templates Signed-off-by: Gordon Sim --- crates/openshell-cli/src/main.rs | 378 ++ crates/openshell-cli/src/run.rs | 665 +++- .../tests/ensure_providers_integration.rs | 2 + crates/openshell-cli/tests/helpers/mod.rs | 89 + .../openshell-cli/tests/mtls_integration.rs | 2 + .../tests/provider_commands_integration.rs | 3 + .../sandbox_create_lifecycle_integration.rs | 375 +- .../sandbox_name_fallback_integration.rs | 2 + crates/openshell-core/src/metadata.rs | 48 +- crates/openshell-core/src/telemetry.rs | 2 + .../src/proto_json.rs | 1 + .../src/runtime.rs | 1 + crates/openshell-sdk/src/client.rs | 57 +- crates/openshell-sdk/src/lib.rs | 2 +- crates/openshell-sdk/src/raw.rs | 10 +- crates/openshell-sdk/src/types.rs | 13 + crates/openshell-sdk/tests/client_mock.rs | 29 + crates/openshell-server/src/compute/mod.rs | 8 +- crates/openshell-server/src/grpc/mod.rs | 78 +- crates/openshell-server/src/grpc/provider.rs | 2 + crates/openshell-server/src/grpc/sandbox.rs | 853 ++++- crates/openshell-server/src/grpc/workspace.rs | 73 +- .../openshell-server/src/persistence/tests.rs | 4 + crates/openshell-server/tests/common/mod.rs | 28 + .../tests/supervisor_relay_integration.rs | 28 + crates/openshell-tui/src/lib.rs | 1 + docs/sandboxes/manage-sandboxes.mdx | 48 + e2e/rust/Cargo.toml | 5 + e2e/rust/tests/sandbox_templates.rs | 173 + proto/openshell.proto | 145 +- python/openshell/sandbox.py | 65 +- python/openshell/sandbox_test.py | 89 + sdk/go/openshell/v1/client.go | 7 + sdk/go/openshell/v1/fake/fake.go | 7 + sdk/go/openshell/v1/fake/sandbox.go | 49 + sdk/go/openshell/v1/sandbox.go | 6 + sdk/go/openshell/v1/sandbox_client.go | 41 + sdk/go/proto/openshellv1/openshell.pb.go | 3250 +++++++++++------ sdk/go/proto/openshellv1/openshell_grpc.pb.go | 160 + sdk/typescript/src/client.test.ts | 40 + sdk/typescript/src/client.ts | 30 + sdk/typescript/src/index.ts | 1 + 42 files changed, 5551 insertions(+), 1319 deletions(-) create mode 100644 e2e/rust/tests/sandbox_templates.rs diff --git a/crates/openshell-cli/src/main.rs b/crates/openshell-cli/src/main.rs index fc7728c15d..6c51debc0e 100644 --- a/crates/openshell-cli/src/main.rs +++ b/crates/openshell-cli/src/main.rs @@ -1331,6 +1331,10 @@ enum SandboxCommands { #[arg(long, add = ArgValueCompleter::new(completers::complete_sandbox_names))] name: Option, + /// Create the sandbox from a named sandbox template. + #[arg(long, conflicts_with_all = ["from", "gpu", "cpu", "memory", "driver_config_json", "envs"])] + template: Option, + /// Sandbox source: a community sandbox name (e.g., `ollama`), a path /// to a Dockerfile or directory containing one, or a full container /// image reference (e.g., `myregistry.com/img:tag`). @@ -1654,6 +1658,10 @@ enum SandboxCommands { /// Manage providers attached to a sandbox. #[command(subcommand)] Provider(SandboxProviderCommands), + + /// Manage reusable sandbox workload templates. + #[command(subcommand)] + Template(SandboxTemplateCommands), } #[derive(Subcommand, Debug)] @@ -1691,6 +1699,108 @@ enum SandboxProviderCommands { }, } +#[derive(Subcommand, Debug)] +// `Create` carries several optional strings and repeated key-value flags. This +// enum is only used for clap parsing, so boxing fields would add friction +// without a meaningful runtime win. +#[allow(clippy::large_enum_variant)] +enum SandboxTemplateCommands { + /// Create a reusable sandbox workload template. + #[command(help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")] + Create { + /// Template name. + name: String, + + /// Container image for sandboxes created from this template. + /// When omitted, the gateway's default sandbox image is used at create time. + #[arg(long)] + image: Option, + + /// CPU limit for sandboxes created from this template (for example: 500m, 1, 2.5). + #[arg(long)] + cpu: Option, + + /// Memory limit for sandboxes created from this template (for example: 512Mi, 4Gi, 8G). + #[arg(long)] + memory: Option, + + /// Number of GPUs requested by this template. + #[arg(long, value_name = "COUNT", value_parser = clap::value_parser!(u32).range(1..))] + gpu: Option, + + /// Experimental driver-keyed JSON object for driver-specific sandbox settings. + #[arg(long, value_name = "JSON")] + driver_config_json: Option, + + /// Target startup readiness duration for this template (for example: 30s, 5m, 1h). + #[arg(long, value_name = "DURATION")] + ready_within: Option, + + /// Maximum startup burst associated with this template. + #[arg(long, value_name = "COUNT", value_parser = clap::value_parser!(u32).range(1..))] + max_burst: Option, + + /// Attach labels to the template (key=value format, repeatable). + #[arg(long = "label", value_name = "KEY=VALUE")] + labels: Vec, + + /// Attach annotations to the template (key=value format, repeatable). + #[arg(long = "annotation", value_name = "KEY=VALUE")] + annotations: Vec, + + /// Set a non-secret environment variable in sandboxes created from this template. + #[arg(long = "env", value_name = "KEY=VALUE")] + envs: Vec, + + /// Output format. + #[arg(short = 'o', long = "output", value_enum, default_value_t = OutputFormat::Table)] + output: OutputFormat, + }, + + /// Fetch a sandbox workload template by name. + #[command(help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")] + Get { + /// Template name. + name: String, + + /// Output format. + #[arg(short = 'o', long = "output", value_enum, default_value_t = OutputFormat::Table)] + output: OutputFormat, + }, + + /// List sandbox workload templates. + #[command(help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")] + List { + /// Maximum number of templates to return. + #[arg(long, default_value_t = 100)] + limit: u32, + + /// Offset into the template list. + #[arg(long, default_value_t = 0)] + offset: u32, + + /// Print only template names (one per line). + #[arg(long, conflicts_with = "output")] + names: bool, + + /// Output format. + #[arg(short = 'o', long = "output", value_enum, default_value_t = OutputFormat::Table, conflicts_with = "names")] + output: OutputFormat, + + /// List templates across all workspaces (overrides --workspace). + #[arg(long)] + all_workspaces: bool, + }, + + /// Delete sandbox workload templates. + #[command(help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")] + Delete { + /// Template names. + #[arg(required = true, num_args = 1.., value_name = "NAME")] + names: Vec, + }, +} + #[derive(Subcommand, Debug)] enum DraftCommands { /// Show network rules for a sandbox. @@ -2965,6 +3075,7 @@ async fn run_async() -> Result<()> { match command { SandboxCommands::Create { name, + template, from, upload, no_git_ignore, @@ -3057,6 +3168,7 @@ async fn run_async() -> Result<()> { &ctx.name, run::SandboxCreateConfig { name: name.as_deref(), + template: template.as_deref(), from: from.as_deref(), uploads: &upload_specs, keep, @@ -3276,6 +3388,83 @@ async fn run_async() -> Result<()> { .await?; } }, + SandboxCommands::Template(command) => match command { + SandboxTemplateCommands::Create { + name, + image, + cpu, + memory, + gpu, + driver_config_json, + ready_within, + max_burst, + labels, + annotations, + envs, + output, + } => { + let labels = run::parse_key_value_pairs(&labels, "--label")?; + let annotations = + run::parse_key_value_pairs(&annotations, "--annotation")?; + let environment = run::parse_env_pairs(&envs)?; + run::sandbox_template_create( + endpoint, + &name, + image.as_deref(), + cpu.as_deref(), + memory.as_deref(), + gpu, + driver_config_json.as_deref(), + ready_within.as_deref(), + max_burst, + labels, + annotations, + environment, + output.as_str(), + &cli.workspace, + &tls, + ) + .await?; + } + SandboxTemplateCommands::Get { name, output } => { + run::sandbox_template_get( + endpoint, + &name, + output.as_str(), + &cli.workspace, + &tls, + ) + .await?; + } + SandboxTemplateCommands::List { + limit, + offset, + names, + output, + all_workspaces, + } => { + run::sandbox_template_list( + endpoint, + limit, + offset, + names, + output.as_str(), + &cli.workspace, + all_workspaces, + &tls, + ) + .await?; + } + SandboxTemplateCommands::Delete { names } => { + run::sandbox_template_delete( + endpoint, + &names, + &cli.workspace, + &tls, + ) + .await?; + } + }, } } } @@ -5261,6 +5450,195 @@ mod tests { } } + #[test] + fn sandbox_create_template_flag_parses() { + let cli = Cli::try_parse_from([ + "openshell", + "sandbox", + "create", + "--template", + "gpu-kata", + "--provider", + "github", + ]) + .expect("sandbox create template flag should parse"); + + match cli.command { + Some(Commands::Sandbox { + command: + Some(SandboxCommands::Create { + template, + providers, + .. + }), + .. + }) => { + assert_eq!(template.as_deref(), Some("gpu-kata")); + assert_eq!(providers, vec!["github".to_string()]); + } + other => panic!("expected SandboxCommands::Create, got: {other:?}"), + } + } + + #[test] + fn sandbox_create_template_conflicts_with_inline_workload_flags() { + for (label, extra_args) in [ + ("--from", &["--from", "python:3.12"][..]), + ("--gpu", &["--gpu"][..]), + ("--cpu", &["--cpu", "1"][..]), + ("--memory", &["--memory", "2Gi"][..]), + ("--env", &["--env", "FOO=bar"][..]), + ( + "--driver-config-json", + &["--driver-config-json", r#"{"kubernetes":{}}"#][..], + ), + ] { + let args = ["openshell", "sandbox", "create", "--template", "base"] + .into_iter() + .chain(extra_args.iter().copied()); + let result = Cli::try_parse_from(args); + assert!(result.is_err(), "--template should conflict with {label}"); + } + } + + #[test] + fn sandbox_template_create_parses_workload_flags() { + let json = r#"{"kubernetes":{"pod":{"node_selector":{"pool":"gpu"}}}}"#; + let cli = Cli::try_parse_from([ + "openshell", + "sandbox", + "template", + "create", + "gpu-kata", + "--image", + "registry.example.com/agent:latest", + "--cpu", + "2", + "--memory", + "4Gi", + "--gpu", + "1", + "--driver-config-json", + json, + "--ready-within", + "5m", + "--max-burst", + "3", + "--label", + "team=runtime", + "--annotation", + "owner=platform", + "--env", + "FEATURE_FLAG=on", + "--output", + "json", + ]) + .expect("sandbox template create should parse"); + + match cli.command { + Some(Commands::Sandbox { + command: + Some(SandboxCommands::Template(SandboxTemplateCommands::Create { + name, + image, + cpu, + memory, + gpu, + driver_config_json, + ready_within, + max_burst, + labels, + annotations, + envs, + output, + })), + .. + }) => { + assert_eq!(name, "gpu-kata"); + assert_eq!(image.as_deref(), Some("registry.example.com/agent:latest")); + assert_eq!(cpu.as_deref(), Some("2")); + assert_eq!(memory.as_deref(), Some("4Gi")); + assert_eq!(gpu, Some(1)); + assert_eq!(driver_config_json.as_deref(), Some(json)); + assert_eq!(ready_within.as_deref(), Some("5m")); + assert_eq!(max_burst, Some(3)); + assert_eq!(labels, vec!["team=runtime".to_string()]); + assert_eq!(annotations, vec!["owner=platform".to_string()]); + assert_eq!(envs, vec!["FEATURE_FLAG=on".to_string()]); + assert!(matches!(output, OutputFormat::Json)); + } + other => panic!("expected SandboxTemplateCommands::Create, got: {other:?}"), + } + } + + #[test] + fn sandbox_template_list_parses_names_and_all_workspaces() { + let cli = Cli::try_parse_from([ + "openshell", + "sandbox", + "template", + "list", + "--names", + "--all-workspaces", + "--limit", + "25", + "--offset", + "5", + ]) + .expect("sandbox template list should parse"); + + match cli.command { + Some(Commands::Sandbox { + command: + Some(SandboxCommands::Template(SandboxTemplateCommands::List { + limit, + offset, + names, + all_workspaces, + .. + })), + .. + }) => { + assert_eq!(limit, 25); + assert_eq!(offset, 5); + assert!(names); + assert!(all_workspaces); + } + other => panic!("expected SandboxTemplateCommands::List, got: {other:?}"), + } + } + + #[test] + fn sandbox_template_list_names_conflicts_with_output() { + let result = Cli::try_parse_from([ + "openshell", + "sandbox", + "template", + "list", + "--names", + "--output", + "json", + ]); + assert!(result.is_err()); + } + + #[test] + fn sandbox_template_create_image_is_optional() { + let cli = Cli::try_parse_from(["openshell", "sandbox", "template", "create", "base"]) + .expect("sandbox template create without --image should parse"); + + match cli.command { + Some(Commands::Sandbox { + command: + Some(SandboxCommands::Template(SandboxTemplateCommands::Create { image, .. })), + .. + }) => { + assert_eq!(image, None); + } + other => panic!("expected SandboxTemplateCommands::Create, got: {other:?}"), + } + } + #[test] fn sandbox_create_gpu_parses_driver_default() { let cli = Cli::try_parse_from(["openshell", "sandbox", "create", "--gpu"]) diff --git a/crates/openshell-cli/src/run.rs b/crates/openshell-cli/src/run.rs index 47fc268080..1faede71dd 100644 --- a/crates/openshell-cli/src/run.rs +++ b/crates/openshell-cli/src/run.rs @@ -36,24 +36,27 @@ use openshell_core::proto::ProviderProfileCategory; use openshell_core::proto::{ ApproveAllDraftChunksRequest, ApproveDraftChunkRequest, AttachSandboxProviderRequest, ClearDraftChunksRequest, ConfigureProviderRefreshRequest, CreateProviderRequest, - CreateSandboxRequest, CreateSshSessionRequest, DeleteInferenceRouteRequest, - DeleteProviderProfileRequest, DeleteProviderRefreshRequest, DeleteProviderRequest, - DeleteSandboxRequest, DeleteServiceRequest, DetachSandboxProviderRequest, ExecSandboxRequest, - ExposeServiceRequest, GetCurrentUserRequest, GetDraftHistoryRequest, GetDraftPolicyRequest, - GetGatewayConfigRequest, GetInferenceRouteRequest, GetProviderProfileRequest, - GetProviderRefreshStatusRequest, GetProviderRequest, GetSandboxConfigRequest, - GetSandboxConfigResponse, GetSandboxLogsRequest, GetSandboxPolicyStatusRequest, - GetSandboxRequest, GetServiceRequest, GpuResourceRequirements, ImportProviderProfilesRequest, - LintProviderProfilesRequest, ListProviderProfilesRequest, ListProvidersRequest, - ListSandboxPoliciesRequest, ListSandboxProvidersRequest, ListSandboxesRequest, + CreateSandboxRequest, CreateSandboxTemplateRequest, CreateSshSessionRequest, + DeleteInferenceRouteRequest, DeleteProviderProfileRequest, DeleteProviderRefreshRequest, + DeleteProviderRequest, DeleteSandboxRequest, DeleteSandboxTemplateRequest, + DeleteServiceRequest, DetachSandboxProviderRequest, ExecSandboxRequest, ExposeServiceRequest, + GetCurrentUserRequest, GetDraftHistoryRequest, GetDraftPolicyRequest, GetGatewayConfigRequest, + GetInferenceRouteRequest, GetProviderProfileRequest, GetProviderRefreshStatusRequest, + GetProviderRequest, GetSandboxConfigRequest, GetSandboxConfigResponse, GetSandboxLogsRequest, + GetSandboxPolicyStatusRequest, GetSandboxRequest, GetSandboxTemplateRequest, GetServiceRequest, + GpuResourceRequirements, ImportProviderProfilesRequest, LintProviderProfilesRequest, + ListProviderProfilesRequest, ListProvidersRequest, ListSandboxPoliciesRequest, + ListSandboxProvidersRequest, ListSandboxTemplatesRequest, ListSandboxesRequest, ListServicesRequest, PolicySource, PolicyStatus, Provider, ProviderCredentialRefreshStatus, ProviderCredentialRefreshStrategy, ProviderProfile, ProviderProfileDiagnostic, ProviderProfileImportItem, RejectDraftChunkRequest, ResourceRequirements, RevokeSshSessionRequest, RotateProviderCredentialRequest, Sandbox, SandboxPhase, SandboxPolicy, - SandboxSpec, SandboxTemplate, ServiceEndpointResponse, SetInferenceRouteRequest, SettingScope, - StartSandboxRequest, StopSandboxRequest, TcpForwardFrame, TcpForwardInit, TcpRelayTarget, - UpdateConfigRequest, UpdateProviderProfilesRequest, UpdateProviderRequest, WatchSandboxRequest, - exec_sandbox_event, setting_value, tcp_forward_init, + SandboxResources, SandboxServiceLevel, SandboxSpec, SandboxStartup, SandboxTemplate, + SandboxWorkloadConfig, SandboxWorkloadTemplate, SandboxWorkloadTemplateSpec, + ServiceEndpointResponse, SetInferenceRouteRequest, SettingScope, StartSandboxRequest, + StopSandboxRequest, TcpForwardFrame, TcpForwardInit, TcpRelayTarget, UpdateConfigRequest, + UpdateProviderProfilesRequest, UpdateProviderRequest, WatchSandboxRequest, exec_sandbox_event, + setting_value, tcp_forward_init, }; use openshell_core::settings; use openshell_core::{ObjectId, ObjectName, ObjectWorkspace}; @@ -365,6 +368,7 @@ async fn finalize_sandbox_create_session( #[derive(Debug)] pub struct SandboxCreateConfig<'a> { pub name: Option<&'a str>, + pub template: Option<&'a str>, pub from: Option<&'a str>, pub uploads: &'a [(String, Option, bool)], pub keep: bool, @@ -389,6 +393,7 @@ impl Default for SandboxCreateConfig<'_> { fn default() -> Self { Self { name: None, + template: None, from: None, uploads: &[], keep: false, @@ -421,6 +426,7 @@ pub async fn sandbox_create( ) -> Result<()> { let SandboxCreateConfig { name, + template, from, uploads, keep, @@ -463,23 +469,42 @@ pub async fn sandbox_create( let effective_server = server.to_string(); let effective_tls = tls.clone(); + if template.is_some() + && (from.is_some() + || gpu_requirements.is_some() + || cpu.is_some() + || memory.is_some() + || driver_config_json.is_some() + || !environment.is_empty()) + { + return Err(miette::miette!( + "--template cannot be combined with inline workload flags" + )); + } + // Resolve the --from flag into a container image reference, building from - // a Dockerfile first if necessary. - let image: Option = match from { - Some(val) => { - let resolved = resolve_from(val)?; - match resolved { - ResolvedSource::Image(img) => Some(img), - ResolvedSource::Dockerfile { - dockerfile, - context, - } => { - let tag = build_from_dockerfile(&dockerfile, &context, gateway_name).await?; - Some(tag) + // a Dockerfile first if necessary. Template creates resolve workload shape + // on the gateway and skip local image handling. + let image: Option = if template.is_some() { + None + } else { + match from { + Some(val) => { + let resolved = resolve_from(val)?; + match resolved { + ResolvedSource::Image(img) => Some(img), + ResolvedSource::Dockerfile { + dockerfile, + context, + } => { + let tag = + build_from_dockerfile(&dockerfile, &context, gateway_name).await?; + Some(tag) + } } } + None => None, } - None => None, }; let inferred_provider = inferred_provider_type(command); let providers_v2_enabled = @@ -503,12 +528,21 @@ pub async fn sandbox_create( .await?; let policy = load_sandbox_policy(policy)?; - let resource_limits = build_sandbox_resource_limits(cpu, memory)?; - let driver_config = driver_config_json - .map(parse_driver_config_json) - .transpose()?; + let resource_limits = if template.is_none() { + build_sandbox_resource_limits(cpu, memory)? + } else { + None + }; + let driver_config = if template.is_none() { + driver_config_json + .map(parse_driver_config_json) + .transpose()? + } else { + None + }; - let template = if image.is_some() || resource_limits.is_some() || driver_config.is_some() { + let inline_template = if image.is_some() || resource_limits.is_some() || driver_config.is_some() + { Some(SandboxTemplate { image: image.unwrap_or_default(), resources: resource_limits, @@ -524,16 +558,21 @@ pub async fn sandbox_create( let request = CreateSandboxRequest { spec: Some(SandboxSpec { resource_requirements, - environment, + environment: if template.is_none() { + environment + } else { + HashMap::new() + }, policy, providers: configured_providers, - template, + template: inline_template, ..SandboxSpec::default() }), name: name.unwrap_or_default().to_string(), labels, annotations: HashMap::new(), workspace: workspace.to_string(), + workload_template_name: template.unwrap_or_default().to_string(), }; let response = match client.create_sandbox(request).await { @@ -2345,6 +2384,564 @@ fn format_provider_attachment_table(providers: &[Provider], color: bool) -> Stri output } +#[allow(clippy::too_many_arguments, clippy::implicit_hasher)] +pub async fn sandbox_template_create( + server: &str, + name: &str, + image: Option<&str>, + cpu: Option<&str>, + memory: Option<&str>, + gpu_count: Option, + driver_config_json: Option<&str>, + ready_within: Option<&str>, + max_burst: Option, + labels: HashMap, + annotations: HashMap, + environment: HashMap, + output: &str, + workspace: &str, + tls: &TlsOptions, +) -> Result<()> { + let resources = if cpu.is_some() || memory.is_some() || gpu_count.is_some() { + Some(SandboxResources { + cpu: cpu + .map(validate_cpu_quantity) + .transpose()? + .unwrap_or_default(), + memory: memory + .map(validate_memory_quantity) + .transpose()? + .unwrap_or_default(), + gpu_count, + }) + } else { + None + }; + let driver_config = driver_config_json + .map(parse_driver_config_json) + .transpose()?; + let desired_service_level = build_template_service_level(ready_within, max_burst)?; + + let mut client = grpc_client(server, tls).await?; + let response = client + .create_sandbox_template(CreateSandboxTemplateRequest { + template: Some(SandboxWorkloadTemplate { + metadata: Some(openshell_core::proto::datamodel::v1::ObjectMeta { + id: String::new(), + name: name.to_string(), + created_at_ms: 0, + labels, + resource_version: 0, + annotations, + workspace: String::new(), + deletion_timestamp_ms: 0, + }), + spec: Some(SandboxWorkloadTemplateSpec { + workload: Some(SandboxWorkloadConfig { + image: image.unwrap_or_default().to_string(), + environment, + resources, + }), + driver_config, + desired_service_level, + }), + }), + workspace: workspace.to_string(), + }) + .await + .into_diagnostic()?; + + let template = response + .into_inner() + .template + .ok_or_else(|| miette!("sandbox template missing from response"))?; + if crate::output::print_output_single(output, &template, sandbox_template_to_json)? { + return Ok(()); + } + println!( + "{} Created sandbox template {}", + "✓".green().bold(), + template.object_name().bold() + ); + Ok(()) +} + +fn build_template_service_level( + ready_within: Option<&str>, + max_burst: Option, +) -> Result> { + if ready_within.is_none() && max_burst.is_none() { + return Ok(None); + } + let ready_within = ready_within + .map(parse_duration_to_ms) + .transpose()? + .map(|ms| { + if ms <= 0 { + Err(miette!("--ready-within must be greater than zero")) + } else { + Ok(duration_ms_to_proto(ms)) + } + }) + .transpose()?; + Ok(Some(SandboxServiceLevel { + startup: Some(SandboxStartup { + ready_within, + max_burst: max_burst.unwrap_or_default(), + }), + })) +} + +fn duration_ms_to_proto(ms: i64) -> prost_types::Duration { + prost_types::Duration { + seconds: ms / 1_000, + nanos: i32::try_from((ms % 1_000) * 1_000_000) + .expect("duration millisecond remainder fits in protobuf nanos"), + } +} + +pub async fn sandbox_template_get( + server: &str, + name: &str, + output: &str, + workspace: &str, + tls: &TlsOptions, +) -> Result<()> { + let mut client = grpc_client(server, tls).await?; + let response = client + .get_sandbox_template(GetSandboxTemplateRequest { + name: name.to_string(), + workspace: workspace.to_string(), + }) + .await + .into_diagnostic()?; + let template = response + .into_inner() + .template + .ok_or_else(|| miette!("sandbox template missing from response"))?; + + if crate::output::print_output_single(output, &template, sandbox_template_to_json)? { + return Ok(()); + } + + print_sandbox_template_detail(&template); + Ok(()) +} + +#[allow(clippy::too_many_arguments)] +pub async fn sandbox_template_list( + server: &str, + limit: u32, + offset: u32, + names_only: bool, + output: &str, + workspace: &str, + all_workspaces: bool, + tls: &TlsOptions, +) -> Result<()> { + let mut client = grpc_client(server, tls).await?; + let response = client + .list_sandbox_templates(ListSandboxTemplatesRequest { + limit, + offset, + workspace: if all_workspaces { + String::new() + } else { + workspace.to_string() + }, + all_workspaces, + }) + .await + .into_diagnostic()?; + let templates = response.into_inner().templates; + + if crate::output::print_output_collection(output, &templates, sandbox_template_to_json)? { + return Ok(()); + } + + if templates.is_empty() { + if !names_only { + println!("No sandbox templates found."); + } + return Ok(()); + } + + if names_only { + for template in &templates { + if all_workspaces { + println!("{}/{}", template.object_workspace(), template.object_name()); + } else { + println!("{}", template.object_name()); + } + } + return Ok(()); + } + + print_sandbox_template_table(&templates, all_workspaces); + Ok(()) +} + +pub async fn sandbox_template_delete( + server: &str, + names: &[String], + workspace: &str, + tls: &TlsOptions, +) -> Result<()> { + let mut client = grpc_client(server, tls).await?; + for name in names { + let response = client + .delete_sandbox_template(DeleteSandboxTemplateRequest { + name: name.clone(), + workspace: workspace.to_string(), + }) + .await + .into_diagnostic()?; + if response.into_inner().deleted { + println!("{} Deleted sandbox template {name}", "✓".green().bold()); + } else { + println!("Sandbox template {name} not found."); + } + } + Ok(()) +} + +fn sandbox_template_to_json(template: &SandboxWorkloadTemplate) -> serde_json::Value { + let mut obj = serde_json::Map::new(); + obj.insert("id".to_string(), serde_json::json!(template.object_id())); + obj.insert( + "name".to_string(), + serde_json::json!(template.object_name()), + ); + obj.insert( + "workspace".to_string(), + serde_json::json!(template.object_workspace()), + ); + + if let Some(metadata) = &template.metadata { + if metadata.resource_version != 0 { + obj.insert( + "resource_version".to_string(), + serde_json::json!(metadata.resource_version), + ); + } + if metadata.created_at_ms != 0 { + obj.insert( + "created_at".to_string(), + serde_json::json!(format_epoch_ms(metadata.created_at_ms)), + ); + } + if !metadata.labels.is_empty() { + obj.insert("labels".to_string(), serde_json::json!(metadata.labels)); + } + } + + if let Some(spec) = &template.spec { + if let Some(workload) = &spec.workload { + obj.insert("image".to_string(), serde_json::json!(workload.image)); + if !workload.environment.is_empty() { + obj.insert( + "environment".to_string(), + serde_json::json!(workload.environment), + ); + } + if let Some(resources) = &workload.resources { + let mut resources_json = serde_json::Map::new(); + if !resources.cpu.is_empty() { + resources_json.insert("cpu".to_string(), serde_json::json!(resources.cpu)); + } + if !resources.memory.is_empty() { + resources_json + .insert("memory".to_string(), serde_json::json!(resources.memory)); + } + if let Some(gpu_count) = resources.gpu_count { + resources_json.insert("gpu_count".to_string(), serde_json::json!(gpu_count)); + } + if !resources_json.is_empty() { + obj.insert( + "resources".to_string(), + serde_json::Value::Object(resources_json), + ); + } + } + } + if let Some(driver_config) = &spec.driver_config { + obj.insert( + "driver_config".to_string(), + openshell_core::proto_struct::struct_to_json_value(driver_config), + ); + } + if let Some(service_level) = &spec.desired_service_level + && let Some(startup) = &service_level.startup + { + let mut startup_json = serde_json::Map::new(); + if let Some(ready_within) = &startup.ready_within { + startup_json.insert( + "ready_within_ms".to_string(), + serde_json::json!(duration_to_ms(ready_within)), + ); + } + if startup.max_burst != 0 { + startup_json.insert( + "max_burst".to_string(), + serde_json::json!(startup.max_burst), + ); + } + if !startup_json.is_empty() { + obj.insert( + "startup".to_string(), + serde_json::Value::Object(startup_json), + ); + } + } + } + + serde_json::Value::Object(obj) +} + +fn print_sandbox_template_detail(template: &SandboxWorkloadTemplate) { + println!("{}", "Sandbox template:".cyan().bold()); + println!(); + println!(" {} {}", "Name:".dimmed(), template.object_name()); + println!( + " {} {}", + "Workspace:".dimmed(), + template.object_workspace() + ); + if let Some(metadata) = &template.metadata { + println!(" {} {}", "Id:".dimmed(), metadata.id); + println!( + " {} {}", + "Resource version:".dimmed(), + metadata.resource_version + ); + if metadata.created_at_ms != 0 { + println!( + " {} {}", + "Created:".dimmed(), + format_epoch_ms(metadata.created_at_ms) + ); + } + let labels = labels_display(&metadata.labels); + println!( + " {} {}", + "Labels:".dimmed(), + non_empty_or(&labels, "") + ); + } + if let Some(spec) = &template.spec + && let Some(workload) = &spec.workload + { + println!( + " {} {}", + "Image:".dimmed(), + non_empty_or(&workload.image, "") + ); + println!( + " {} {}", + "Environment:".dimmed(), + workload.environment.len() + ); + if let Some(resources) = &workload.resources { + println!( + " {} {}", + "CPU:".dimmed(), + non_empty_or(&resources.cpu, "") + ); + println!( + " {} {}", + "Memory:".dimmed(), + non_empty_or(&resources.memory, "") + ); + println!( + " {} {}", + "GPU count:".dimmed(), + resources + .gpu_count + .map_or_else(|| "".to_string(), |count| count.to_string()) + ); + } + } + if let Some(startup) = template_startup(template) { + println!( + " {} {}", + "Ready within:".dimmed(), + startup + .ready_within + .as_ref() + .map_or_else(|| "".to_string(), duration_display) + ); + println!( + " {} {}", + "Max burst:".dimmed(), + if startup.max_burst == 0 { + "".to_string() + } else { + startup.max_burst.to_string() + } + ); + } +} + +fn print_sandbox_template_table(templates: &[SandboxWorkloadTemplate], show_workspace: bool) { + let name_width = templates + .iter() + .map(|template| template.object_name().len()) + .max() + .unwrap_or(4) + .max(4); + let workspace_width = if show_workspace { + templates + .iter() + .map(|template| template.object_workspace().len()) + .max() + .unwrap_or(9) + .max(9) + } else { + 0 + }; + let image_width = templates + .iter() + .map(|template| template_image(template).len()) + .max() + .unwrap_or(5) + .clamp(5, 48); + + if show_workspace { + println!( + "{: String { + template + .spec + .as_ref() + .and_then(|spec| spec.workload.as_ref()) + .map_or_else( + || "".to_string(), + |workload| non_empty_or(&workload.image, "").to_string(), + ) +} + +fn template_resources(template: &SandboxWorkloadTemplate) -> Option<&SandboxResources> { + template + .spec + .as_ref() + .and_then(|spec| spec.workload.as_ref()) + .and_then(|workload| workload.resources.as_ref()) +} + +fn template_startup(template: &SandboxWorkloadTemplate) -> Option<&SandboxStartup> { + template + .spec + .as_ref() + .and_then(|spec| spec.desired_service_level.as_ref()) + .and_then(|service_level| service_level.startup.as_ref()) +} + +fn duration_to_ms(duration: &prost_types::Duration) -> i64 { + duration.seconds.saturating_mul(1_000) + i64::from(duration.nanos / 1_000_000) +} + +fn duration_display(duration: &prost_types::Duration) -> String { + let total_ms = duration_to_ms(duration); + if total_ms % 3_600_000 == 0 { + format!("{}h", total_ms / 3_600_000) + } else if total_ms % 60_000 == 0 { + format!("{}m", total_ms / 60_000) + } else if total_ms % 1_000 == 0 { + format!("{}s", total_ms / 1_000) + } else { + format!("{total_ms}ms") + } +} + +fn labels_display(labels: &HashMap) -> String { + let mut pairs = labels + .iter() + .map(|(key, value)| format!("{key}={value}")) + .collect::>(); + pairs.sort(); + pairs.join(", ") +} + /// Delete a sandbox by name, or all sandboxes when `all` is true. pub async fn sandbox_delete( server: &str, diff --git a/crates/openshell-cli/tests/ensure_providers_integration.rs b/crates/openshell-cli/tests/ensure_providers_integration.rs index 3d628f2c10..4f98ac9353 100644 --- a/crates/openshell-cli/tests/ensure_providers_integration.rs +++ b/crates/openshell-cli/tests/ensure_providers_integration.rs @@ -139,6 +139,8 @@ impl OpenShell for TestOpenShell { Ok(Response::new(ListSandboxesResponse::default())) } + unimplemented_sandbox_template_rpcs!(); + async fn list_sandbox_providers( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/helpers/mod.rs b/crates/openshell-cli/tests/helpers/mod.rs index a58e750b91..c4e9b4b75a 100644 --- a/crates/openshell-cli/tests/helpers/mod.rs +++ b/crates/openshell-cli/tests/helpers/mod.rs @@ -8,6 +8,95 @@ //! mod helpers; //! ``` +#[macro_export] +macro_rules! unimplemented_sandbox_template_rpcs { + () => { + fn create_sandbox_template<'life0, 'async_trait>( + &'life0 self, + _request: tonic::Request, + ) -> std::pin::Pin< + Box< + dyn std::future::Future< + Output = Result< + tonic::Response, + tonic::Status, + >, + > + Send + + 'async_trait, + >, + > + where + 'life0: 'async_trait, + Self: 'async_trait, + { + Box::pin(async { Err(tonic::Status::unimplemented("unused")) }) + } + + fn get_sandbox_template<'life0, 'async_trait>( + &'life0 self, + _request: tonic::Request, + ) -> std::pin::Pin< + Box< + dyn std::future::Future< + Output = Result< + tonic::Response, + tonic::Status, + >, + > + Send + + 'async_trait, + >, + > + where + 'life0: 'async_trait, + Self: 'async_trait, + { + Box::pin(async { Err(tonic::Status::unimplemented("unused")) }) + } + + fn list_sandbox_templates<'life0, 'async_trait>( + &'life0 self, + _request: tonic::Request, + ) -> std::pin::Pin< + Box< + dyn std::future::Future< + Output = Result< + tonic::Response, + tonic::Status, + >, + > + Send + + 'async_trait, + >, + > + where + 'life0: 'async_trait, + Self: 'async_trait, + { + Box::pin(async { Err(tonic::Status::unimplemented("unused")) }) + } + + fn delete_sandbox_template<'life0, 'async_trait>( + &'life0 self, + _request: tonic::Request, + ) -> std::pin::Pin< + Box< + dyn std::future::Future< + Output = Result< + tonic::Response, + tonic::Status, + >, + > + Send + + 'async_trait, + >, + > + where + 'life0: 'async_trait, + Self: 'async_trait, + { + Box::pin(async { Err(tonic::Status::unimplemented("unused")) }) + } + }; +} + use rcgen::{ BasicConstraints, Certificate, CertificateParams, ExtendedKeyUsagePurpose, IsCa, KeyPair, }; diff --git a/crates/openshell-cli/tests/mtls_integration.rs b/crates/openshell-cli/tests/mtls_integration.rs index 60ffbd61f8..5b7d0fe703 100644 --- a/crates/openshell-cli/tests/mtls_integration.rs +++ b/crates/openshell-cli/tests/mtls_integration.rs @@ -98,6 +98,8 @@ impl OpenShell for TestOpenShell { )) } + unimplemented_sandbox_template_rpcs!(); + async fn list_sandbox_providers( &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 a87ff0a6d8..c76375a3c0 100644 --- a/crates/openshell-cli/tests/provider_commands_integration.rs +++ b/crates/openshell-cli/tests/provider_commands_integration.rs @@ -163,6 +163,7 @@ impl OpenShell for TestOpenShell { }), spec: None, status: None, + ..Sandbox::default() }), })) } @@ -174,6 +175,8 @@ impl OpenShell for TestOpenShell { Ok(Response::new(ListSandboxesResponse::default())) } + unimplemented_sandbox_template_rpcs!(); + async fn list_sandbox_providers( &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 102cde3714..0bed792b0d 100644 --- a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs +++ b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs @@ -14,20 +14,21 @@ use openshell_cli::tls::TlsOptions; use openshell_core::proto::open_shell_server::{OpenShell, OpenShellServer}; use openshell_core::proto::{ AttachSandboxProviderRequest, AttachSandboxProviderResponse, CreateProviderRequest, - CreateSandboxRequest, CreateSshSessionRequest, CreateSshSessionResponse, DeleteProviderRequest, - DeleteProviderResponse, DeleteSandboxRequest, DeleteSandboxResponse, - DetachSandboxProviderRequest, DetachSandboxProviderResponse, ExecSandboxEvent, - ExecSandboxInput, ExecSandboxRequest, GatewayMessage, GetGatewayConfigRequest, - GetGatewayConfigResponse, GetProviderRequest, GetSandboxConfigRequest, - GetSandboxConfigResponse, GetSandboxProviderEnvironmentRequest, - GetSandboxProviderEnvironmentResponse, GetSandboxRequest, GpuResourceRequirements, - HealthRequest, HealthResponse, ListProvidersRequest, ListProvidersResponse, - ListSandboxProvidersRequest, ListSandboxProvidersResponse, ListSandboxesRequest, - ListSandboxesResponse, PlatformEvent, ProviderResponse, RevokeSshSessionRequest, + CreateSandboxRequest, CreateSandboxTemplateRequest, CreateSshSessionRequest, + CreateSshSessionResponse, DeleteProviderRequest, DeleteProviderResponse, DeleteSandboxRequest, + DeleteSandboxResponse, DeleteSandboxTemplateRequest, DetachSandboxProviderRequest, + DetachSandboxProviderResponse, ExecSandboxEvent, ExecSandboxInput, ExecSandboxRequest, + GatewayMessage, GetGatewayConfigRequest, GetGatewayConfigResponse, GetProviderRequest, + GetSandboxConfigRequest, GetSandboxConfigResponse, GetSandboxProviderEnvironmentRequest, + GetSandboxProviderEnvironmentResponse, GetSandboxRequest, GetSandboxTemplateRequest, + GpuResourceRequirements, HealthRequest, HealthResponse, ListProvidersRequest, + ListProvidersResponse, ListSandboxProvidersRequest, ListSandboxProvidersResponse, + ListSandboxTemplatesRequest, ListSandboxTemplatesResponse, ListSandboxesRequest, + ListSandboxesResponse, PlatformEvent, Provider, ProviderResponse, RevokeSshSessionRequest, RevokeSshSessionResponse, Sandbox, SandboxCondition, SandboxLogLine, SandboxPhase, - SandboxResponse, SandboxStatus, SandboxStreamEvent, ServiceStatus, SettingValue, - SupervisorMessage, UpdateProviderRequest, WatchSandboxRequest, sandbox_stream_event, - setting_value, + SandboxResponse, SandboxStatus, SandboxStreamEvent, SandboxTemplateResponse, + SandboxWorkloadTemplate, ServiceStatus, SettingValue, SupervisorMessage, UpdateProviderRequest, + WatchSandboxRequest, sandbox_stream_event, setting_value, }; use std::collections::HashMap; use std::fs; @@ -51,6 +52,11 @@ struct SandboxState { vm_log_churn_before_ready: Arc, global_settings: Arc>>, gateway_config_requests: Arc, + providers: Arc>>, + template_create_requests: Arc>>, + template_get_requests: Arc>>, + template_list_requests: Arc>>, + template_delete_requests: Arc>>, } #[derive(Clone, Default)] @@ -161,6 +167,95 @@ impl OpenShell for TestOpenShell { Ok(Response::new(ListSandboxesResponse::default())) } + async fn create_sandbox_template( + &self, + request: tonic::Request, + ) -> Result, Status> { + let request = request.into_inner(); + let mut template = request.template.clone().unwrap_or_default(); + let name = template + .metadata + .as_ref() + .map_or_else(|| "template".to_string(), |metadata| metadata.name.clone()); + template.metadata = Some(openshell_core::proto::datamodel::v1::ObjectMeta { + id: format!("template-{name}"), + name, + created_at_ms: 0, + labels: template + .metadata + .as_ref() + .map(|metadata| metadata.labels.clone()) + .unwrap_or_default(), + resource_version: 1, + annotations: HashMap::new(), + workspace: request.workspace.clone(), + deletion_timestamp_ms: 0, + }); + self.state + .template_create_requests + .lock() + .await + .push(request); + Ok(Response::new(SandboxTemplateResponse { + template: Some(template), + })) + } + + async fn get_sandbox_template( + &self, + request: tonic::Request, + ) -> Result, Status> { + let request = request.into_inner(); + self.state + .template_get_requests + .lock() + .await + .push(request.clone()); + Ok(Response::new(SandboxTemplateResponse { + template: Some(SandboxWorkloadTemplate { + metadata: Some(openshell_core::proto::datamodel::v1::ObjectMeta { + id: format!("template-{}", request.name), + name: request.name, + created_at_ms: 0, + labels: HashMap::new(), + resource_version: 1, + annotations: HashMap::new(), + workspace: request.workspace, + deletion_timestamp_ms: 0, + }), + spec: None, + }), + })) + } + + async fn list_sandbox_templates( + &self, + request: tonic::Request, + ) -> Result, Status> { + self.state + .template_list_requests + .lock() + .await + .push(request.into_inner()); + Ok(Response::new(ListSandboxTemplatesResponse { + templates: Vec::new(), + })) + } + + async fn delete_sandbox_template( + &self, + request: tonic::Request, + ) -> Result, Status> { + self.state + .template_delete_requests + .lock() + .await + .push(request.into_inner()); + Ok(Response::new( + openshell_core::proto::DeleteSandboxTemplateResponse { deleted: true }, + )) + } + async fn list_sandbox_providers( &self, _request: tonic::Request, @@ -294,7 +389,9 @@ impl OpenShell for TestOpenShell { &self, _request: tonic::Request, ) -> Result, Status> { - Ok(Response::new(ListProvidersResponse::default())) + Ok(Response::new(ListProvidersResponse { + providers: self.state.providers.lock().await.clone(), + })) } async fn list_provider_profiles( @@ -1128,6 +1225,36 @@ async fn create_requests(server: &TestServer) -> Vec { server.openshell.state.create_requests.lock().await.clone() } +async fn template_create_requests(server: &TestServer) -> Vec { + server + .openshell + .state + .template_create_requests + .lock() + .await + .clone() +} + +async fn template_list_requests(server: &TestServer) -> Vec { + server + .openshell + .state + .template_list_requests + .lock() + .await + .clone() +} + +async fn template_delete_requests(server: &TestServer) -> Vec { + server + .openshell + .state + .template_delete_requests + .lock() + .await + .clone() +} + async fn enable_providers_v2(server: &TestServer) { server.openshell.state.global_settings.lock().await.insert( openshell_core::settings::PROVIDERS_V2_ENABLED_KEY.to_string(), @@ -1137,6 +1264,33 @@ async fn enable_providers_v2(server: &TestServer) { ); } +async fn add_provider(server: &TestServer, name: &str, provider_type: &str) { + server + .openshell + .state + .providers + .lock() + .await + .push(Provider { + metadata: Some(openshell_core::proto::datamodel::v1::ObjectMeta { + id: format!("provider-{name}"), + name: name.to_string(), + created_at_ms: 0, + labels: HashMap::new(), + resource_version: 0, + annotations: HashMap::new(), + workspace: "default".to_string(), + deletion_timestamp_ms: 0, + }), + r#type: provider_type.to_string(), + credentials: HashMap::new(), + config: HashMap::new(), + credential_expires_at_ms: HashMap::new(), + profile_workspace: "default".to_string(), + credential_handles: HashMap::new(), + }); +} + fn test_tls(server: &TestServer) -> TlsOptions { server.tls.with_gateway_name("openshell") } @@ -1354,6 +1508,199 @@ async fn sandbox_create_sends_driver_config_json() { ); } +#[tokio::test] +async fn sandbox_create_with_template_sends_workload_template_name() { + let server = run_server().await; + add_provider(&server, "github", "github").await; + let fake_ssh_dir = tempfile::tempdir().unwrap(); + let xdg_dir = tempfile::tempdir().unwrap(); + let _env = test_env(&fake_ssh_dir, &xdg_dir); + let tls = test_tls(&server); + install_fake_ssh(&fake_ssh_dir); + + run::sandbox_create( + &server.endpoint, + "openshell", + run::SandboxCreateConfig { + name: Some("from-template"), + template: Some("gpu-kata"), + providers: &["github".to_string()], + command: &["echo".into(), "OK".into()], + ..test_config() + }, + "default", + &tls, + ) + .await + .expect("sandbox create should succeed"); + + let requests = create_requests(&server).await; + let request = requests.first().expect("create request should be recorded"); + assert_eq!(request.workload_template_name, "gpu-kata"); + let spec = request + .spec + .as_ref() + .expect("governance spec should be sent"); + assert_eq!(spec.providers, vec!["github".to_string()]); + assert!(spec.template.is_none()); + assert!(spec.environment.is_empty()); + assert!(spec.resource_requirements.is_none()); +} + +#[tokio::test] +async fn sandbox_template_create_sends_workload_template_resource() { + let server = run_server().await; + let fake_ssh_dir = tempfile::tempdir().unwrap(); + let xdg_dir = tempfile::tempdir().unwrap(); + let _env = test_env(&fake_ssh_dir, &xdg_dir); + let tls = test_tls(&server); + + run::sandbox_template_create( + &server.endpoint, + "gpu-kata", + Some("registry.example.com/agent:latest"), + Some("2"), + Some("4Gi"), + Some(1), + Some(r#"{"kubernetes":{"pod":{"node_selector":{"pool":"gpu"}}}}"#), + Some("5m"), + Some(3), + HashMap::from([("team".to_string(), "runtime".to_string())]), + HashMap::from([("owner".to_string(), "platform".to_string())]), + HashMap::from([("FEATURE_FLAG".to_string(), "on".to_string())]), + "table", + "default", + &tls, + ) + .await + .expect("template create should succeed"); + + let requests = template_create_requests(&server).await; + let request = requests + .first() + .expect("template create request should be recorded"); + assert_eq!(request.workspace, "default"); + let template = request.template.as_ref().expect("template should be sent"); + let metadata = template.metadata.as_ref().expect("metadata should be sent"); + assert_eq!(metadata.name, "gpu-kata"); + assert_eq!(metadata.labels.get("team"), Some(&"runtime".to_string())); + assert_eq!( + metadata.annotations.get("owner"), + Some(&"platform".to_string()) + ); + + let spec = template.spec.as_ref().expect("spec should be sent"); + let workload = spec.workload.as_ref().expect("workload should be sent"); + assert_eq!(workload.image, "registry.example.com/agent:latest"); + assert_eq!( + workload.environment.get("FEATURE_FLAG"), + Some(&"on".to_string()) + ); + let resources = workload + .resources + .as_ref() + .expect("resources should be sent"); + assert_eq!(resources.cpu, "2"); + assert_eq!(resources.memory, "4Gi"); + assert_eq!(resources.gpu_count, Some(1)); + assert!(spec.driver_config.is_some()); + let startup = spec + .desired_service_level + .as_ref() + .and_then(|service_level| service_level.startup.as_ref()) + .expect("startup service level should be sent"); + assert_eq!(startup.max_burst, 3); + assert_eq!( + startup + .ready_within + .as_ref() + .map(|duration| duration.seconds), + Some(300) + ); +} + +#[tokio::test] +async fn sandbox_template_list_and_delete_send_workspace_requests() { + let server = run_server().await; + let fake_ssh_dir = tempfile::tempdir().unwrap(); + let xdg_dir = tempfile::tempdir().unwrap(); + let _env = test_env(&fake_ssh_dir, &xdg_dir); + let tls = test_tls(&server); + + run::sandbox_template_list( + &server.endpoint, + 25, + 5, + false, + "table", + "default", + false, + &tls, + ) + .await + .expect("template list should succeed"); + run::sandbox_template_delete(&server.endpoint, &["gpu-kata".to_string()], "default", &tls) + .await + .expect("template delete should succeed"); + + let list_requests = template_list_requests(&server).await; + let list_request = list_requests + .first() + .expect("template list request should be recorded"); + assert_eq!(list_request.limit, 25); + assert_eq!(list_request.offset, 5); + assert_eq!(list_request.workspace, "default"); + assert!(!list_request.all_workspaces); + + let delete_requests = template_delete_requests(&server).await; + let delete_request = delete_requests + .first() + .expect("template delete request should be recorded"); + assert_eq!(delete_request.name, "gpu-kata"); + assert_eq!(delete_request.workspace, "default"); +} + +#[tokio::test] +async fn sandbox_template_create_allows_omitted_image() { + let server = run_server().await; + let fake_ssh_dir = tempfile::tempdir().unwrap(); + let xdg_dir = tempfile::tempdir().unwrap(); + let _env = test_env(&fake_ssh_dir, &xdg_dir); + let tls = test_tls(&server); + + run::sandbox_template_create( + &server.endpoint, + "base", + None, + None, + None, + None, + None, + None, + None, + HashMap::new(), + HashMap::new(), + HashMap::new(), + "table", + "default", + &tls, + ) + .await + .expect("template create without image should succeed"); + + let requests = template_create_requests(&server).await; + let request = requests + .first() + .expect("template create request should be recorded"); + let workload = request + .template + .as_ref() + .and_then(|template| template.spec.as_ref()) + .and_then(|spec| spec.workload.as_ref()) + .expect("workload should be sent"); + assert_eq!(workload.image, ""); +} + #[tokio::test] async fn sandbox_create_sends_gpu_default_request() { let server = run_server().await; diff --git a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs index 41b93bab82..9701a79ded 100644 --- a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs +++ b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs @@ -123,6 +123,8 @@ impl OpenShell for TestOpenShell { Ok(Response::new(ListSandboxesResponse::default())) } + unimplemented_sandbox_template_rpcs!(); + async fn list_sandbox_providers( &self, _request: tonic::Request, diff --git a/crates/openshell-core/src/metadata.rs b/crates/openshell-core/src/metadata.rs index 8794c11d5d..f885812c4e 100644 --- a/crates/openshell-core/src/metadata.rs +++ b/crates/openshell-core/src/metadata.rs @@ -6,8 +6,9 @@ //! These traits provide uniform access to `ObjectMeta` fields across all resource types. use crate::proto::{ - InferenceRoute, ObjectForTest, Provider, Sandbox, SandboxStatus, ServiceEndpoint, SshSession, - StoredProviderCredentialRefreshState, StoredProviderProfile, Workspace, WorkspaceMember, + InferenceRoute, ObjectForTest, Provider, Sandbox, SandboxStatus, SandboxWorkloadTemplate, + ServiceEndpoint, SshSession, StoredProviderCredentialRefreshState, StoredProviderProfile, + Workspace, WorkspaceMember, }; use std::collections::HashMap; @@ -104,6 +105,49 @@ impl Sandbox { } } +// Implementations for SandboxWorkloadTemplate +impl ObjectId for SandboxWorkloadTemplate { + fn object_id(&self) -> &str { + self.metadata.as_ref().map_or("", |m| m.id.as_str()) + } +} + +impl ObjectName for SandboxWorkloadTemplate { + fn object_name(&self) -> &str { + self.metadata.as_ref().map_or("", |m| m.name.as_str()) + } +} + +impl ObjectLabels for SandboxWorkloadTemplate { + fn object_labels(&self) -> Option> { + self.metadata.as_ref().map(|m| m.labels.clone()) + } +} + +impl SetResourceVersion for SandboxWorkloadTemplate { + fn set_resource_version(&mut self, version: u64) { + if let Some(meta) = self.metadata.as_mut() { + meta.resource_version = version; + } + } +} + +impl GetResourceVersion for SandboxWorkloadTemplate { + fn get_resource_version(&self) -> u64 { + self.metadata.as_ref().map_or(0, |m| m.resource_version) + } +} + +impl ObjectWorkspace for SandboxWorkloadTemplate { + fn object_workspace(&self) -> &str { + self.metadata.as_ref().map_or("", |m| m.workspace.as_str()) + } + + fn requires_workspace() -> bool { + true + } +} + // Implementations for Workspace impl ObjectId for Workspace { fn object_id(&self) -> &str { diff --git a/crates/openshell-core/src/telemetry.rs b/crates/openshell-core/src/telemetry.rs index b2c9b79152..c37dac4e64 100644 --- a/crates/openshell-core/src/telemetry.rs +++ b/crates/openshell-core/src/telemetry.rs @@ -145,6 +145,7 @@ impl PolicyDecisionOperation { pub enum SandboxTemplateSource { Default, Image, + WorkloadTemplate, Undefined, } @@ -154,6 +155,7 @@ impl SandboxTemplateSource { match self { Self::Default => "default", Self::Image => "image", + Self::WorkloadTemplate => "workload_template", Self::Undefined => "undefined", } } diff --git a/crates/openshell-gateway-interceptors/src/proto_json.rs b/crates/openshell-gateway-interceptors/src/proto_json.rs index f6aecbcf67..98f5d77aa0 100644 --- a/crates/openshell-gateway-interceptors/src/proto_json.rs +++ b/crates/openshell-gateway-interceptors/src/proto_json.rs @@ -316,6 +316,7 @@ mod tests { labels: HashMap::from([("team".to_string(), "agent".to_string())]), annotations: HashMap::new(), workspace: String::new(), + workload_template_name: String::new(), }; let bytes = request.encode_to_vec(); let json = codec diff --git a/crates/openshell-gateway-interceptors/src/runtime.rs b/crates/openshell-gateway-interceptors/src/runtime.rs index 4e7f5ba613..6487ae15e2 100644 --- a/crates/openshell-gateway-interceptors/src/runtime.rs +++ b/crates/openshell-gateway-interceptors/src/runtime.rs @@ -1075,6 +1075,7 @@ mod tests { labels: HashMap::new(), annotations: HashMap::new(), workspace: String::new(), + workload_template_name: String::new(), }; let bytes = request.encode_to_vec(); diff --git a/crates/openshell-sdk/src/client.rs b/crates/openshell-sdk/src/client.rs index c67e91e219..5e907eb73f 100644 --- a/crates/openshell-sdk/src/client.rs +++ b/crates/openshell-sdk/src/client.rs @@ -16,7 +16,7 @@ use crate::refresh::{RefreshedToken, TokenSource}; use crate::transport; use crate::types::{ ExecOptions, ExecResult, Health, ListOptions, SandboxPhase, SandboxRef, SandboxSpec, - WorkspaceRef, + SandboxTemplateCreateSpec, WorkspaceRef, }; use futures::StreamExt; use openshell_core::proto; @@ -163,6 +163,21 @@ impl OpenShellClient { sandbox_from_response(response.sandbox) } + /// Create a new sandbox from a workspace-scoped workload template name. + pub async fn create_sandbox_from_template( + &self, + spec: SandboxTemplateCreateSpec, + ) -> Result { + let request = create_sandbox_from_template_request(spec); + let response = self + .unary(|mut grpc| { + let request = request.clone(); + async move { grpc.create_sandbox(request).await } + }) + .await?; + sandbox_from_response(response.sandbox) + } + /// Fetch a sandbox by name. pub async fn get_sandbox(&self, name: &str) -> Result { let response = self @@ -562,6 +577,23 @@ impl WorkspaceScopedClient { sandbox_from_response(response.sandbox) } + /// Create a new sandbox from a template in this workspace. + pub async fn create_sandbox_from_template( + &self, + spec: SandboxTemplateCreateSpec, + ) -> Result { + let mut request = create_sandbox_from_template_request(spec); + request.workspace = self.workspace.clone(); + let response = self + .client + .unary(|mut grpc| { + let request = request.clone(); + async move { grpc.create_sandbox(request).await } + }) + .await?; + sandbox_from_response(response.sandbox) + } + /// Fetch a sandbox by name in this workspace. pub async fn get_sandbox(&self, name: &str) -> Result { let response = self @@ -819,6 +851,29 @@ fn create_sandbox_request(spec: SandboxSpec) -> proto::CreateSandboxRequest { labels, annotations: HashMap::new(), workspace: String::new(), + workload_template_name: String::new(), + } +} + +fn create_sandbox_from_template_request( + spec: SandboxTemplateCreateSpec, +) -> proto::CreateSandboxRequest { + let SandboxTemplateCreateSpec { + name, + template_name, + labels, + providers, + } = spec; + proto::CreateSandboxRequest { + spec: Some(proto::SandboxSpec { + providers, + ..proto::SandboxSpec::default() + }), + name: name.unwrap_or_default(), + labels, + annotations: HashMap::new(), + workspace: String::new(), + workload_template_name: template_name, } } diff --git a/crates/openshell-sdk/src/lib.rs b/crates/openshell-sdk/src/lib.rs index dbf2524a2a..72258e708b 100644 --- a/crates/openshell-sdk/src/lib.rs +++ b/crates/openshell-sdk/src/lib.rs @@ -47,5 +47,5 @@ pub use error::SdkError; pub use refresh::{Refresh, RefreshError, RefreshedToken, TokenSource}; pub use types::{ ExecOptions, ExecResult, Health, ListOptions, SandboxPhase, SandboxRef, SandboxSpec, - ServiceStatus, WorkspaceRef, + SandboxTemplateCreateSpec, ServiceStatus, WorkspaceRef, }; diff --git a/crates/openshell-sdk/src/raw.rs b/crates/openshell-sdk/src/raw.rs index e974b19259..903913e3d6 100644 --- a/crates/openshell-sdk/src/raw.rs +++ b/crates/openshell-sdk/src/raw.rs @@ -22,10 +22,12 @@ pub use openshell_core::proto; pub use openshell_core::proto::inference_client::InferenceClient; pub use openshell_core::proto::open_shell_client::OpenShellClient as GrpcClient; pub use openshell_core::proto::{ - CreateSandboxRequest, CreateWorkspaceRequest, DeleteSandboxRequest, DeleteWorkspaceRequest, - ExecSandboxRequest, GetSandboxRequest, GetWorkspaceRequest, HealthRequest, - ListProvidersRequest, ListSandboxesRequest, ListWorkspacesRequest, Sandbox, - SandboxPhase as ProtoSandboxPhase, SandboxSpec as ProtoSandboxSpec, SandboxTemplate, + CreateSandboxRequest, CreateSandboxTemplateRequest, CreateWorkspaceRequest, + DeleteSandboxRequest, DeleteSandboxTemplateRequest, DeleteWorkspaceRequest, ExecSandboxRequest, + GetSandboxRequest, GetSandboxTemplateRequest, GetWorkspaceRequest, HealthRequest, + ListProvidersRequest, ListSandboxTemplatesRequest, ListSandboxesRequest, ListWorkspacesRequest, + Sandbox, SandboxPhase as ProtoSandboxPhase, SandboxSpec as ProtoSandboxSpec, SandboxTemplate, + SandboxTemplateResponse, SandboxWorkloadTemplate, SandboxWorkloadTemplateSpec, ServiceStatus as ProtoServiceStatus, StartSandboxRequest, StopSandboxRequest, Workspace, }; diff --git a/crates/openshell-sdk/src/types.rs b/crates/openshell-sdk/src/types.rs index 6f179499c9..297f031987 100644 --- a/crates/openshell-sdk/src/types.rs +++ b/crates/openshell-sdk/src/types.rs @@ -111,6 +111,19 @@ pub struct SandboxSpec { pub gpu: bool, } +/// Caller intent for creating a sandbox from a named workload template. +#[derive(Clone, Debug, Default)] +pub struct SandboxTemplateCreateSpec { + /// Optional user-supplied sandbox name. When empty the server generates one. + pub name: Option, + /// Workspace-scoped template name to resolve at creation time. + pub template_name: String, + /// Labels attached to the sandbox. + pub labels: HashMap, + /// Provider names to attach. + pub providers: Vec, +} + /// Reference to a sandbox owned by the gateway. #[derive(Clone, Debug)] #[non_exhaustive] diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index 09e91330ce..cb923648fb 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -77,6 +77,7 @@ fn sandbox_with_phase_ws( phase: phase.into(), ..Default::default() }), + ..proto::Sandbox::default() } } @@ -163,6 +164,34 @@ impl OpenShell for TestOpenShell { })) } + async fn create_sandbox_template( + &self, + _: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn get_sandbox_template( + &self, + _: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn list_sandbox_templates( + &self, + _: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn delete_sandbox_template( + &self, + _: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + async fn stop_sandbox( &self, request: tonic::Request, diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index e09b63de09..c7dc63cd07 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -46,7 +46,7 @@ use openshell_core::proto::compute::v1::{ }; use openshell_core::proto::{ PlatformEvent, Sandbox, SandboxCondition, SandboxPhase, SandboxSpec, SandboxStatus, - SandboxTemplate, ServiceEndpoint, SshSession, + SandboxTemplate, SandboxWorkloadTemplate, ServiceEndpoint, SshSession, }; use openshell_core::{ObjectLabels, ObjectWorkspace}; #[cfg(not(target_os = "windows"))] @@ -3445,6 +3445,12 @@ impl ObjectType for Sandbox { } } +impl ObjectType for SandboxWorkloadTemplate { + fn object_type() -> &'static str { + "sandbox_workload_template" + } +} + fn compute_error_from_status(status: Status) -> ComputeError { match status.code() { Code::AlreadyExists => ComputeError::AlreadyExists, diff --git a/crates/openshell-server/src/grpc/mod.rs b/crates/openshell-server/src/grpc/mod.rs index 2c52acbe12..f82143313b 100644 --- a/crates/openshell-server/src/grpc/mod.rs +++ b/crates/openshell-server/src/grpc/mod.rs @@ -17,27 +17,29 @@ use openshell_core::proto::{ AttachSandboxProviderRequest, AttachSandboxProviderResponse, ClearDraftChunksRequest, ClearDraftChunksResponse, ComputeDriverCapabilities, ComputeDriverInfo, ConfigureProviderRefreshRequest, ConfigureProviderRefreshResponse, CreateProviderRequest, - CreateSandboxRequest, CreateSshSessionRequest, CreateSshSessionResponse, - CreateWorkspaceRequest, CreateWorkspaceResponse, DeleteProviderProfileRequest, - DeleteProviderProfileResponse, DeleteProviderRefreshRequest, DeleteProviderRefreshResponse, - DeleteProviderRequest, DeleteProviderResponse, DeleteSandboxRequest, DeleteSandboxResponse, - DeleteServiceRequest, DeleteServiceResponse, DeleteWorkspaceRequest, DeleteWorkspaceResponse, - DetachSandboxProviderRequest, DetachSandboxProviderResponse, EditDraftChunkRequest, - EditDraftChunkResponse, ExecSandboxEvent, ExecSandboxInput, ExecSandboxRequest, - ExposeServiceRequest, GatewayMessage, GetCurrentUserRequest, GetCurrentUserResponse, - GetDraftHistoryRequest, GetDraftHistoryResponse, GetDraftPolicyRequest, GetDraftPolicyResponse, - GetGatewayConfigRequest, GetGatewayConfigResponse, GetGatewayInfoRequest, - GetGatewayInfoResponse, GetProviderProfileRequest, GetProviderRefreshStatusRequest, - GetProviderRefreshStatusResponse, GetProviderRequest, GetSandboxConfigRequest, - GetSandboxConfigResponse, GetSandboxLogsRequest, GetSandboxLogsResponse, - GetSandboxPolicyStatusRequest, GetSandboxPolicyStatusResponse, + CreateSandboxRequest, CreateSandboxTemplateRequest, CreateSshSessionRequest, + CreateSshSessionResponse, CreateWorkspaceRequest, CreateWorkspaceResponse, + DeleteProviderProfileRequest, DeleteProviderProfileResponse, DeleteProviderRefreshRequest, + DeleteProviderRefreshResponse, DeleteProviderRequest, DeleteProviderResponse, + DeleteSandboxRequest, DeleteSandboxResponse, DeleteSandboxTemplateRequest, + DeleteSandboxTemplateResponse, DeleteServiceRequest, DeleteServiceResponse, + DeleteWorkspaceRequest, DeleteWorkspaceResponse, DetachSandboxProviderRequest, + DetachSandboxProviderResponse, EditDraftChunkRequest, EditDraftChunkResponse, ExecSandboxEvent, + ExecSandboxInput, ExecSandboxRequest, ExposeServiceRequest, GatewayMessage, + GetCurrentUserRequest, GetCurrentUserResponse, GetDraftHistoryRequest, GetDraftHistoryResponse, + GetDraftPolicyRequest, GetDraftPolicyResponse, GetGatewayConfigRequest, + GetGatewayConfigResponse, GetGatewayInfoRequest, GetGatewayInfoResponse, + GetProviderProfileRequest, GetProviderRefreshStatusRequest, GetProviderRefreshStatusResponse, + GetProviderRequest, GetSandboxConfigRequest, GetSandboxConfigResponse, GetSandboxLogsRequest, + GetSandboxLogsResponse, GetSandboxPolicyStatusRequest, GetSandboxPolicyStatusResponse, GetSandboxProviderEnvironmentRequest, GetSandboxProviderEnvironmentResponse, GetSandboxRequest, - GetServiceRequest, GetWorkspaceRequest, GetWorkspaceResponse, HealthRequest, HealthResponse, - ImportProviderProfilesRequest, ImportProviderProfilesResponse, IssueSandboxTokenRequest, - IssueSandboxTokenResponse, LintProviderProfilesRequest, LintProviderProfilesResponse, - ListProviderProfilesRequest, ListProviderProfilesResponse, ListProvidersRequest, - ListProvidersResponse, ListSandboxPoliciesRequest, ListSandboxPoliciesResponse, - ListSandboxProvidersRequest, ListSandboxProvidersResponse, ListSandboxesRequest, + GetSandboxTemplateRequest, GetServiceRequest, GetWorkspaceRequest, GetWorkspaceResponse, + HealthRequest, HealthResponse, ImportProviderProfilesRequest, ImportProviderProfilesResponse, + IssueSandboxTokenRequest, IssueSandboxTokenResponse, LintProviderProfilesRequest, + LintProviderProfilesResponse, ListProviderProfilesRequest, ListProviderProfilesResponse, + ListProvidersRequest, ListProvidersResponse, ListSandboxPoliciesRequest, + ListSandboxPoliciesResponse, ListSandboxProvidersRequest, ListSandboxProvidersResponse, + ListSandboxTemplatesRequest, ListSandboxTemplatesResponse, ListSandboxesRequest, ListSandboxesResponse, ListServicesRequest, ListServicesResponse, ListWorkspaceMembersRequest, ListWorkspaceMembersResponse, ListWorkspacesRequest, ListWorkspacesResponse, ProviderProfileResponse, ProviderResponse, PushSandboxLogsRequest, PushSandboxLogsResponse, @@ -45,10 +47,10 @@ use openshell_core::proto::{ RejectDraftChunkResponse, RelayFrame, RemoveWorkspaceMemberRequest, RemoveWorkspaceMemberResponse, ReportPolicyStatusRequest, ReportPolicyStatusResponse, RevokeSshSessionRequest, RevokeSshSessionResponse, RotateProviderCredentialRequest, - RotateProviderCredentialResponse, SandboxResponse, ServiceEndpointResponse, ServiceStatus, - StartSandboxRequest, StopSandboxRequest, SubmitPolicyAnalysisRequest, - SubmitPolicyAnalysisResponse, SupervisorMessage, TcpForwardFrame, UndoDraftChunkRequest, - UndoDraftChunkResponse, UpdateConfigRequest, UpdateConfigResponse, + RotateProviderCredentialResponse, SandboxResponse, SandboxTemplateResponse, + ServiceEndpointResponse, ServiceStatus, StartSandboxRequest, StopSandboxRequest, + SubmitPolicyAnalysisRequest, SubmitPolicyAnalysisResponse, SupervisorMessage, TcpForwardFrame, + UndoDraftChunkRequest, UndoDraftChunkResponse, UpdateConfigRequest, UpdateConfigResponse, UpdateProviderProfilesRequest, UpdateProviderProfilesResponse, UpdateProviderRequest, WatchSandboxRequest, open_shell_server::OpenShell, }; @@ -296,6 +298,34 @@ impl OpenShell for OpenShellService { sandbox::handle_list_sandboxes(&self.state, request).await } + async fn create_sandbox_template( + &self, + request: Request, + ) -> Result, Status> { + sandbox::handle_create_sandbox_template(&self.state, request).await + } + + async fn get_sandbox_template( + &self, + request: Request, + ) -> Result, Status> { + sandbox::handle_get_sandbox_template(&self.state, request).await + } + + async fn list_sandbox_templates( + &self, + request: Request, + ) -> Result, Status> { + sandbox::handle_list_sandbox_templates(&self.state, request).await + } + + async fn delete_sandbox_template( + &self, + request: Request, + ) -> Result, Status> { + sandbox::handle_delete_sandbox_template(&self.state, request).await + } + async fn list_sandbox_providers( &self, request: Request, diff --git a/crates/openshell-server/src/grpc/provider.rs b/crates/openshell-server/src/grpc/provider.rs index 25bfbb045d..aac715909e 100644 --- a/crates/openshell-server/src/grpc/provider.rs +++ b/crates/openshell-server/src/grpc/provider.rs @@ -10037,6 +10037,7 @@ mod tests { ..SandboxSpec::default() }), status: None, + ..Sandbox::default() }; sandbox.set_phase(SandboxPhase::Ready as i32); store.put_message(&sandbox).await.unwrap(); @@ -10073,6 +10074,7 @@ mod tests { }), spec: Some(SandboxSpec::default()), status: None, + ..Sandbox::default() }; sandbox.set_phase(SandboxPhase::Ready as i32); store.put_message(&sandbox).await.unwrap(); diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index d5dd4e04e4..420b85e6f0 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -16,24 +16,30 @@ use crate::auth::workspace_authz::{ use crate::persistence::{ObjectLabels, ObjectType, WriteCondition, generate_name}; use futures::future; use openshell_core::net::set_tcp_nodelay_best_effort; +use openshell_core::proto::datamodel::v1::ObjectMeta; use openshell_core::proto::{ AttachSandboxProviderRequest, AttachSandboxProviderResponse, CreateSandboxRequest, - CreateSshSessionRequest, CreateSshSessionResponse, DeleteSandboxRequest, DeleteSandboxResponse, - DetachSandboxProviderRequest, DetachSandboxProviderResponse, ExecSandboxEvent, ExecSandboxExit, - ExecSandboxInput, ExecSandboxRequest, ExecSandboxStderr, ExecSandboxStdout, GetSandboxRequest, - ListSandboxProvidersRequest, ListSandboxProvidersResponse, ListSandboxesRequest, - ListSandboxesResponse, Provider, RevokeSshSessionRequest, RevokeSshSessionResponse, - SandboxResponse, SandboxStreamEvent, SshRelayTarget, StartSandboxRequest, StopSandboxRequest, - TcpForwardFrame, TcpForwardInit, TcpRelayTarget, WatchSandboxRequest, relay_open, - tcp_forward_init, + CreateSandboxTemplateRequest, CreateSshSessionRequest, CreateSshSessionResponse, + DeleteSandboxRequest, DeleteSandboxResponse, DeleteSandboxTemplateRequest, + DeleteSandboxTemplateResponse, DetachSandboxProviderRequest, DetachSandboxProviderResponse, + ExecSandboxEvent, ExecSandboxExit, ExecSandboxInput, ExecSandboxRequest, ExecSandboxStderr, + ExecSandboxStdout, GetSandboxRequest, GetSandboxTemplateRequest, GpuResourceRequirements, + ListSandboxProvidersRequest, ListSandboxProvidersResponse, ListSandboxTemplatesRequest, + ListSandboxTemplatesResponse, ListSandboxesRequest, ListSandboxesResponse, Provider, + ResourceRequirements, RevokeSshSessionRequest, RevokeSshSessionResponse, SandboxResources, + SandboxResponse, SandboxSpec, SandboxStreamEvent, SandboxTemplateResponse, + SandboxWorkloadTemplate, SandboxWorkloadTemplateProvenance, SshRelayTarget, + StartSandboxRequest, StopSandboxRequest, TcpForwardFrame, TcpForwardInit, TcpRelayTarget, + WatchSandboxRequest, relay_open, tcp_forward_init, }; use openshell_core::proto::{Sandbox, SandboxPhase, SandboxTemplate, SshSession}; use openshell_core::telemetry::{ LifecycleOperation, LifecycleResource, SandboxTemplateSource, TelemetryComputeDriver, TelemetryOutcome, }; -use openshell_core::{ObjectId, ObjectName, ObjectWorkspace}; +use openshell_core::{GetResourceVersion, ObjectId, ObjectName, ObjectWorkspace}; use prost::Message; +use prost_types::{Struct, Value, value::Kind}; use std::collections::HashMap; use std::net::IpAddr; use std::pin::Pin; @@ -53,7 +59,7 @@ use super::provider::{ get_provider_record, is_valid_env_key, validate_provider_environment_keys_unique, }; use super::validation::{ - level_matches, normalize_process_identity_for_driver, source_matches, + level_matches, normalize_process_identity_for_driver, source_matches, validate_dns1123_label, validate_exec_request_fields, validate_no_reserved_provider_policy_keys, validate_policy_safety, validate_sandbox_spec, }; @@ -159,30 +165,69 @@ pub(super) async fn handle_create_sandbox( ) -> Result, Status> { let create_request = request.get_ref().clone(); let result = handle_create_sandbox_inner(state, request).await; + let created_sandbox = result + .as_ref() + .ok() + .and_then(|response| response.get_ref().sandbox.as_ref()); emit_sandbox_create_telemetry( state, &create_request, + created_sandbox, TelemetryOutcome::from_success(result.is_ok()), ); result } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct SandboxCreateTelemetryAttrs { + requested_gpu: bool, + provider_count: u64, + has_custom_policy: bool, + template_source: SandboxTemplateSource, +} + fn emit_sandbox_create_telemetry( state: &Arc, request: &CreateSandboxRequest, + created_sandbox: Option<&Sandbox>, outcome: TelemetryOutcome, ) { let compute_driver = telemetry_compute_driver(state.compute.driver_kind()); + let attrs = sandbox_create_telemetry_attrs(request, created_sandbox); + openshell_core::telemetry::emit_sandbox_create( + outcome, + attrs.requested_gpu, + attrs.provider_count, + attrs.has_custom_policy, + attrs.template_source, + compute_driver, + ); +} + +fn sandbox_create_telemetry_attrs( + request: &CreateSandboxRequest, + created_sandbox: Option<&Sandbox>, +) -> SandboxCreateTelemetryAttrs { + if !request.workload_template_name.trim().is_empty() { + let spec = created_sandbox + .and_then(|sandbox| sandbox.spec.as_ref()) + .or(request.spec.as_ref()); + return SandboxCreateTelemetryAttrs { + requested_gpu: spec.is_some_and(|spec| { + openshell_core::gpu::sandbox_gpu_requested(spec.resource_requirements.as_ref()) + }), + provider_count: spec.map_or(0, |spec| spec.providers.len() as u64), + has_custom_policy: spec.is_some_and(|spec| spec.policy.is_some()), + template_source: SandboxTemplateSource::WorkloadTemplate, + }; + } let Some(spec) = request.spec.as_ref() else { - openshell_core::telemetry::emit_sandbox_create( - outcome, - false, - 0, - false, - SandboxTemplateSource::Undefined, - compute_driver, - ); - return; + return SandboxCreateTelemetryAttrs { + requested_gpu: false, + provider_count: 0, + has_custom_policy: false, + template_source: SandboxTemplateSource::Undefined, + }; }; let template_source = if spec .template @@ -195,14 +240,12 @@ fn emit_sandbox_create_telemetry( }; let gpu_requested = openshell_core::gpu::sandbox_gpu_requested(spec.resource_requirements.as_ref()); - openshell_core::telemetry::emit_sandbox_create( - outcome, - gpu_requested, - spec.providers.len() as u64, - spec.policy.is_some(), + SandboxCreateTelemetryAttrs { + requested_gpu: gpu_requested, + provider_count: spec.providers.len() as u64, + has_custom_policy: spec.policy.is_some(), template_source, - compute_driver, - ); + } } fn telemetry_compute_driver( @@ -217,12 +260,7 @@ async fn handle_create_sandbox_inner( ) -> Result, Status> { let principal = super::extract_principal(&request)?; let request = request.into_inner(); - let spec = request - .spec - .ok_or_else(|| Status::invalid_argument("spec is required"))?; - - // Validate field sizes before any I/O (fail fast on oversized payloads). - validate_sandbox_spec(&request.name, &spec)?; + let workload_template_name = request.workload_template_name.trim().to_string(); // Validate labels (keys and values must meet Kubernetes requirements). for (key, value) in &request.labels { @@ -243,6 +281,34 @@ async fn handle_create_sandbox_inner( .await? .ensure_active()?; + let (mut spec, created_from_workload_template) = if workload_template_name.is_empty() { + let spec = request + .spec + .ok_or_else(|| Status::invalid_argument("spec is required"))?; + (spec, None) + } else { + validate_dns1123_label(&workload_template_name, "workload_template_name")?; + let governance_spec = request.spec.unwrap_or_default(); + validate_template_create_governance_spec(&governance_spec)?; + let template = state + .store + .get_message_by_name::(&workspace, &workload_template_name) + .await + .map_err(|e| Status::internal(format!("fetch sandbox template failed: {e}")))? + .ok_or_else(|| Status::not_found("sandbox template not found"))?; + let provenance = SandboxWorkloadTemplateProvenance { + name: template.object_name().to_string(), + resource_version: template.get_resource_version().to_string(), + }; + let mut resolved = sandbox_spec_from_workload_template(&template)?; + resolved.policy = governance_spec.policy; + resolved.providers = governance_spec.providers; + (resolved, Some(provenance)) + }; + + // Validate field sizes before any create-side effects. + validate_sandbox_spec(&request.name, &spec)?; + let _sandbox_sync_guard = if spec.providers.is_empty() { None } else { @@ -262,9 +328,8 @@ async fn handle_create_sandbox_inner( .await?; // Ensure the template always carries the resolved image. - let mut spec = spec; let template = spec.template.get_or_insert_with(SandboxTemplate::default); - if template.image.is_empty() { + if template.image.trim().is_empty() { template.image = state.compute.default_image().to_string(); } @@ -295,7 +360,7 @@ async fn handle_create_sandbox_inner( let now_ms = current_time_ms(); let mut sandbox = Sandbox { - metadata: Some(openshell_core::proto::datamodel::v1::ObjectMeta { + metadata: Some(ObjectMeta { id: id.clone(), name: name.clone(), created_at_ms: now_ms, @@ -307,6 +372,7 @@ async fn handle_create_sandbox_inner( }), spec: Some(spec), status: None, + created_from_workload_template, }; sandbox.set_phase(SandboxPhase::Provisioning as i32); @@ -365,6 +431,96 @@ async fn handle_create_sandbox_inner( })) } +fn validate_template_create_governance_spec(spec: &SandboxSpec) -> Result<(), Status> { + if !spec.log_level.is_empty() { + return Err(Status::invalid_argument( + "spec.log_level cannot be set when workload_template_name is set", + )); + } + if !spec.environment.is_empty() { + return Err(Status::invalid_argument( + "spec.environment cannot be set when workload_template_name is set", + )); + } + if spec.template.is_some() { + return Err(Status::invalid_argument( + "spec.template cannot be set when workload_template_name is set", + )); + } + if spec.resource_requirements.is_some() { + return Err(Status::invalid_argument( + "spec.resource_requirements cannot be set when workload_template_name is set", + )); + } + Ok(()) +} + +fn sandbox_spec_from_workload_template( + template: &SandboxWorkloadTemplate, +) -> Result { + let spec = template + .spec + .as_ref() + .ok_or_else(|| Status::invalid_argument("sandbox template spec is required"))?; + let workload = spec + .workload + .as_ref() + .ok_or_else(|| Status::invalid_argument("sandbox template workload is required"))?; + let resources = workload.resources.as_ref(); + Ok(SandboxSpec { + environment: workload.environment.clone(), + template: Some(SandboxTemplate { + image: workload.image.clone(), + resources: resources.and_then(template_resource_struct), + driver_config: spec.driver_config.clone(), + ..SandboxTemplate::default() + }), + resource_requirements: resources.and_then(|resources| { + resources + .gpu_count + .is_some() + .then_some(ResourceRequirements { + gpu: Some(GpuResourceRequirements { + count: resources.gpu_count, + }), + }) + }), + ..SandboxSpec::default() + }) +} + +fn template_resource_struct(resources: &SandboxResources) -> Option { + let mut limits = std::collections::BTreeMap::new(); + if !resources.cpu.is_empty() { + limits.insert( + "cpu".to_string(), + Value { + kind: Some(Kind::StringValue(resources.cpu.clone())), + }, + ); + } + if !resources.memory.is_empty() { + limits.insert( + "memory".to_string(), + Value { + kind: Some(Kind::StringValue(resources.memory.clone())), + }, + ); + } + if limits.is_empty() { + None + } else { + let mut fields = std::collections::BTreeMap::new(); + fields.insert( + "limits".to_string(), + Value { + kind: Some(Kind::StructValue(Struct { fields: limits })), + }, + ); + Some(Struct { fields }) + } +} + pub(super) async fn handle_get_sandbox( state: &Arc, request: Request, @@ -465,6 +621,209 @@ pub(super) async fn handle_list_sandboxes( Ok(Response::new(ListSandboxesResponse { sandboxes })) } +pub(super) async fn handle_create_sandbox_template( + state: &Arc, + request: Request, +) -> Result, Status> { + let principal = super::extract_principal(&request)?; + let req = request.into_inner(); + let template = req + .template + .ok_or_else(|| Status::invalid_argument("template is required"))?; + let metadata = template.metadata.clone().unwrap_or_default(); + let request_workspace = if req.workspace.is_empty() { + metadata.workspace.as_str() + } else { + req.workspace.as_str() + }; + let authz = authorize_workspace( + &state.store, + &state.admin_role, + &principal, + request_workspace, + MinWorkspaceRole::Admin, + ) + .await?; + let workspace = super::workspace::resolve_workspace(state.store.as_ref(), &authz.workspace) + .await? + .ensure_active()?; + if !metadata.workspace.is_empty() && metadata.workspace != workspace { + return Err(Status::invalid_argument( + "template.metadata.workspace must match request workspace", + )); + } + if metadata.name.is_empty() { + return Err(Status::invalid_argument( + "template.metadata.name is required", + )); + } + + let mut resolved = template; + resolved.metadata = Some(ObjectMeta { + id: uuid::Uuid::new_v4().to_string(), + name: metadata.name, + created_at_ms: current_time_ms(), + labels: metadata.labels, + resource_version: 0, + annotations: metadata.annotations, + workspace: workspace.clone(), + deletion_timestamp_ms: 0, + }); + validate_sandbox_workload_template(&resolved)?; + + let labels_map = resolved.object_labels(); + let labels_json = if labels_map.as_ref().is_none_or(HashMap::is_empty) { + None + } else { + Some( + serde_json::to_string(&labels_map) + .map_err(|e| Status::internal(format!("failed to serialize labels: {e}")))?, + ) + }; + let write = state + .store + .put_if( + SandboxWorkloadTemplate::object_type(), + resolved.object_id(), + resolved.object_name(), + &workspace, + &resolved.encode_to_vec(), + labels_json.as_deref(), + WriteCondition::MustCreate, + ) + .await; + let write = match write { + Ok(write) => write, + Err(crate::persistence::PersistenceError::UniqueViolation { .. }) => { + return Err(Status::already_exists("sandbox template already exists")); + } + Err(err) => { + return Err(Status::internal(format!( + "persist sandbox template failed: {err}" + ))); + } + }; + if let Some(metadata) = resolved.metadata.as_mut() { + metadata.resource_version = write.resource_version; + } + + Ok(Response::new(SandboxTemplateResponse { + template: Some(resolved), + })) +} + +pub(super) async fn handle_get_sandbox_template( + state: &Arc, + request: Request, +) -> Result, Status> { + let principal = super::extract_principal(&request)?; + let req = request.into_inner(); + if req.name.is_empty() { + return Err(Status::invalid_argument("name is required")); + } + let authz = authorize_workspace( + &state.store, + &state.admin_role, + &principal, + &req.workspace, + MinWorkspaceRole::User, + ) + .await?; + let workspace = super::workspace::resolve_workspace(state.store.as_ref(), &authz.workspace) + .await? + .name; + let template = state + .store + .get_message_by_name::(&workspace, &req.name) + .await + .map_err(|e| Status::internal(format!("fetch sandbox template failed: {e}")))? + .ok_or_else(|| Status::not_found("sandbox template not found"))?; + Ok(Response::new(SandboxTemplateResponse { + template: Some(template), + })) +} + +pub(super) async fn handle_list_sandbox_templates( + state: &Arc, + request: Request, +) -> Result, Status> { + let principal = super::extract_principal(&request)?; + let request = request.into_inner(); + if request.all_workspaces && !request.workspace.is_empty() { + return Err(Status::invalid_argument( + "all_workspaces and workspace are mutually exclusive", + )); + } + let limit = clamp_limit(request.limit, 100, MAX_PAGE_SIZE); + let templates = if request.all_workspaces { + require_platform_admin(&state.admin_role, &principal)?; + state + .store + .list_all_messages::(limit, request.offset) + .await + .map_err(|e| Status::internal(format!("list sandbox templates failed: {e}")))? + } else { + let authz = authorize_workspace( + &state.store, + &state.admin_role, + &principal, + &request.workspace, + MinWorkspaceRole::User, + ) + .await?; + let workspace = super::workspace::resolve_workspace(state.store.as_ref(), &authz.workspace) + .await? + .name; + state + .store + .list_messages::(&workspace, limit, request.offset) + .await + .map_err(|e| Status::internal(format!("list sandbox templates failed: {e}")))? + }; + Ok(Response::new(ListSandboxTemplatesResponse { templates })) +} + +pub(super) async fn handle_delete_sandbox_template( + state: &Arc, + request: Request, +) -> Result, Status> { + let principal = super::extract_principal(&request)?; + let req = request.into_inner(); + if req.name.is_empty() { + return Err(Status::invalid_argument("name is required")); + } + let authz = authorize_workspace( + &state.store, + &state.admin_role, + &principal, + &req.workspace, + MinWorkspaceRole::Admin, + ) + .await?; + let workspace = super::workspace::resolve_workspace(state.store.as_ref(), &authz.workspace) + .await? + .name; + let deleted = state + .store + .delete_by_name( + SandboxWorkloadTemplate::object_type(), + &workspace, + &req.name, + ) + .await + .map_err(|e| Status::internal(format!("delete sandbox template failed: {e}")))?; + Ok(Response::new(DeleteSandboxTemplateResponse { deleted })) +} + +fn validate_sandbox_workload_template(template: &SandboxWorkloadTemplate) -> Result<(), Status> { + super::validation::validate_object_metadata(template.metadata.as_ref(), "sandbox_template")?; + let name = template.object_name().to_string(); + validate_dns1123_label(&name, "template.metadata.name")?; + let spec = sandbox_spec_from_workload_template(template)?; + validate_sandbox_spec(&name, &spec)?; + Ok(()) +} + pub(super) async fn handle_list_sandbox_providers( state: &Arc, request: Request, @@ -1704,7 +2063,7 @@ pub(super) async fn handle_create_ssh_session( 0 }; let session = SshSession { - metadata: Some(openshell_core::proto::datamodel::v1::ObjectMeta { + metadata: Some(ObjectMeta { id: token.clone(), name: generate_name(), created_at_ms: now_ms, @@ -2440,6 +2799,66 @@ mod tests { ); } + #[test] + fn sandbox_create_telemetry_uses_resolved_template_gpu_request() { + let request = CreateSandboxRequest { + spec: Some(SandboxSpec { + providers: vec!["github".to_string()], + policy: Some(openshell_core::proto::SandboxPolicy::default()), + ..SandboxSpec::default() + }), + workload_template_name: "gpu-kata".to_string(), + ..CreateSandboxRequest::default() + }; + let created = Sandbox { + spec: Some(SandboxSpec { + providers: vec!["github".to_string()], + policy: Some(openshell_core::proto::SandboxPolicy::default()), + resource_requirements: Some(ResourceRequirements { + gpu: Some(GpuResourceRequirements { count: Some(1) }), + }), + ..SandboxSpec::default() + }), + created_from_workload_template: Some(SandboxWorkloadTemplateProvenance { + name: "gpu-kata".to_string(), + resource_version: "7".to_string(), + }), + ..Sandbox::default() + }; + + assert_eq!( + sandbox_create_telemetry_attrs(&request, Some(&created)), + SandboxCreateTelemetryAttrs { + requested_gpu: true, + provider_count: 1, + has_custom_policy: true, + template_source: SandboxTemplateSource::WorkloadTemplate, + } + ); + } + + #[test] + fn sandbox_create_telemetry_falls_back_to_request_for_unresolved_template() { + let request = CreateSandboxRequest { + spec: Some(SandboxSpec { + providers: vec!["github".to_string()], + ..SandboxSpec::default() + }), + workload_template_name: "missing-template".to_string(), + ..CreateSandboxRequest::default() + }; + + assert_eq!( + sandbox_create_telemetry_attrs(&request, None), + SandboxCreateTelemetryAttrs { + requested_gpu: false, + provider_count: 1, + has_custom_policy: false, + template_source: SandboxTemplateSource::WorkloadTemplate, + } + ); + } + #[test] fn shell_escape_safe_chars_pass_through() { assert_eq!(shell_escape("ls").unwrap(), "ls"); @@ -2749,7 +3168,7 @@ mod tests { workspace: "default".to_string(), deletion_timestamp_ms: 0, }), - spec: Some(openshell_core::proto::SandboxSpec { + spec: Some(SandboxSpec { log_level: "debug".to_string(), policy: Some(openshell_core::proto::SandboxPolicy::default()), providers, @@ -2762,6 +3181,41 @@ mod tests { sandbox } + fn test_workload_template(name: &str) -> SandboxWorkloadTemplate { + SandboxWorkloadTemplate { + metadata: Some(ObjectMeta { + id: String::new(), + name: name.to_string(), + created_at_ms: 0, + labels: HashMap::from([("team".to_string(), "runtime".to_string())]), + resource_version: 0, + annotations: HashMap::new(), + workspace: String::new(), + deletion_timestamp_ms: 0, + }), + spec: Some(openshell_core::proto::SandboxWorkloadTemplateSpec { + workload: Some(openshell_core::proto::SandboxWorkloadConfig { + image: "registry.example.com/agent:latest".to_string(), + environment: HashMap::from([("FEATURE_FLAG".to_string(), "on".to_string())]), + resources: Some(SandboxResources { + cpu: "2".to_string(), + memory: "4Gi".to_string(), + gpu_count: Some(1), + }), + }), + driver_config: None, + desired_service_level: None, + }), + } + } + + fn proto_string_value(value: &Value) -> Option<&str> { + match value.kind.as_ref() { + Some(Kind::StringValue(value)) => Some(value.as_str()), + _ => None, + } + } + #[tokio::test] #[ignore = "flaky under concurrent test execution"] async fn watch_producer_releases_request_span_when_client_disconnects() { @@ -3277,13 +3731,14 @@ mod tests { &state, authed_request(CreateSandboxRequest { name: "collision".to_string(), - spec: Some(openshell_core::proto::SandboxSpec { + spec: Some(SandboxSpec { providers: vec!["provider-a".to_string(), "provider-b".to_string()], ..Default::default() }), labels: HashMap::new(), annotations: HashMap::new(), workspace: String::new(), + workload_template_name: String::new(), }), ) .await @@ -3311,13 +3766,14 @@ mod tests { &state, authed_request(CreateSandboxRequest { name: "reserved-policy-key".to_string(), - spec: Some(openshell_core::proto::SandboxSpec { + spec: Some(SandboxSpec { policy: Some(policy), ..Default::default() }), labels: HashMap::new(), annotations: HashMap::new(), workspace: String::new(), + workload_template_name: String::new(), }), ) .await @@ -3338,10 +3794,11 @@ mod tests { &state, authed_request(CreateSandboxRequest { name: "annotated".to_string(), - spec: Some(openshell_core::proto::SandboxSpec::default()), + spec: Some(SandboxSpec::default()), labels: HashMap::new(), annotations: HashMap::from([(annotation_key.clone(), annotation_value.clone())]), workspace: String::new(), + workload_template_name: String::new(), }), ) .await @@ -3395,13 +3852,14 @@ mod tests { &state, authed_request(CreateSandboxRequest { name: "partial-id".to_string(), - spec: Some(openshell_core::proto::SandboxSpec { + spec: Some(SandboxSpec { policy: Some(policy), ..Default::default() }), labels: HashMap::new(), annotations: HashMap::new(), workspace: String::new(), + workload_template_name: String::new(), }), ) .await @@ -3460,13 +3918,14 @@ mod tests { &state, authed_request(CreateSandboxRequest { name: "kube-partial-id".to_string(), - spec: Some(openshell_core::proto::SandboxSpec { + spec: Some(SandboxSpec { policy: Some(policy), ..Default::default() }), labels: HashMap::new(), annotations: HashMap::new(), workspace: String::new(), + workload_template_name: String::new(), }), ) .await @@ -3493,10 +3952,11 @@ mod tests { &state, authed_request(CreateSandboxRequest { name: "bad-label".to_string(), - spec: Some(openshell_core::proto::SandboxSpec::default()), + spec: Some(SandboxSpec::default()), labels: HashMap::from([("team".to_string(), "x".repeat(512))]), annotations: HashMap::new(), workspace: String::new(), + workload_template_name: String::new(), }), ) .await @@ -3522,13 +3982,14 @@ mod tests { &task_state, authed_request(CreateSandboxRequest { name: "guarded-create".to_string(), - spec: Some(openshell_core::proto::SandboxSpec { + spec: Some(SandboxSpec { providers: vec!["work-github".to_string()], ..Default::default() }), labels: HashMap::new(), annotations: HashMap::new(), workspace: String::new(), + workload_template_name: String::new(), }), ) .await @@ -3553,6 +4014,308 @@ mod tests { ); } + #[tokio::test] + async fn sandbox_template_handlers_create_get_list_and_delete_workspace_resource() { + let state = test_server_state().await; + + let created = handle_create_sandbox_template( + &state, + authed_request(CreateSandboxTemplateRequest { + template: Some(test_workload_template("gpu-kata")), + workspace: "default".to_string(), + }), + ) + .await + .expect("template create should succeed") + .into_inner() + .template + .expect("template response"); + + let metadata = created.metadata.as_ref().expect("metadata"); + assert_eq!(metadata.name, "gpu-kata"); + assert_eq!(metadata.workspace, "default"); + assert!(!metadata.id.is_empty()); + assert_ne!(metadata.resource_version, 0); + + let fetched = handle_get_sandbox_template( + &state, + authed_request(GetSandboxTemplateRequest { + name: "gpu-kata".to_string(), + workspace: "default".to_string(), + }), + ) + .await + .expect("template get should succeed") + .into_inner() + .template + .expect("fetched template"); + assert_eq!(fetched.object_name(), "gpu-kata"); + assert_eq!(fetched.object_workspace(), "default"); + + let listed = handle_list_sandbox_templates( + &state, + authed_request(ListSandboxTemplatesRequest { + limit: 100, + offset: 0, + workspace: "default".to_string(), + all_workspaces: false, + }), + ) + .await + .expect("template list should succeed") + .into_inner() + .templates; + assert_eq!(listed.len(), 1); + assert_eq!(listed[0].object_name(), "gpu-kata"); + + let deleted = handle_delete_sandbox_template( + &state, + authed_request(DeleteSandboxTemplateRequest { + name: "gpu-kata".to_string(), + workspace: "default".to_string(), + }), + ) + .await + .expect("template delete should succeed") + .into_inner(); + assert!(deleted.deleted); + + let missing = handle_get_sandbox_template( + &state, + authed_request(GetSandboxTemplateRequest { + name: "gpu-kata".to_string(), + workspace: "default".to_string(), + }), + ) + .await + .expect_err("deleted template should not be fetchable"); + assert_eq!(missing.code(), tonic::Code::NotFound); + } + + #[tokio::test] + async fn sandbox_template_create_rejects_whitespace_name() { + let state = test_server_state().await; + + let err = handle_create_sandbox_template( + &state, + authed_request(CreateSandboxTemplateRequest { + template: Some(test_workload_template(" gpu-kata ")), + workspace: "default".to_string(), + }), + ) + .await + .expect_err("template names must be canonical DNS-1123 labels"); + + assert_eq!(err.code(), tonic::Code::InvalidArgument); + assert!(err.message().contains("template.metadata.name")); + + let listed = handle_list_sandbox_templates( + &state, + authed_request(ListSandboxTemplatesRequest { + limit: 100, + offset: 0, + workspace: "default".to_string(), + all_workspaces: false, + }), + ) + .await + .expect("template list should succeed") + .into_inner() + .templates; + assert!(listed.is_empty()); + } + + #[tokio::test] + async fn create_sandbox_from_workload_template_resolves_workload_and_preserves_governance() { + let state = test_server_state().await; + state + .store + .put_message(&test_provider("work-github", "github")) + .await + .unwrap(); + handle_create_sandbox_template( + &state, + authed_request(CreateSandboxTemplateRequest { + template: Some(test_workload_template("gpu-kata")), + workspace: "default".to_string(), + }), + ) + .await + .expect("template create should succeed"); + + let mut policy = openshell_core::proto::SandboxPolicy { + version: 1, + ..Default::default() + }; + policy.network_policies.insert( + "example".to_string(), + openshell_core::proto::NetworkPolicyRule { + name: "example".to_string(), + ..Default::default() + }, + ); + + let created = handle_create_sandbox( + &state, + authed_request(CreateSandboxRequest { + name: "from-template".to_string(), + spec: Some(SandboxSpec { + providers: vec!["work-github".to_string()], + policy: Some(policy), + ..Default::default() + }), + labels: HashMap::new(), + annotations: HashMap::new(), + workspace: "default".to_string(), + workload_template_name: "gpu-kata".to_string(), + }), + ) + .await + .expect("sandbox create from template should succeed") + .into_inner() + .sandbox + .expect("created sandbox"); + + let provenance = created + .created_from_workload_template + .expect("template provenance"); + assert_eq!(provenance.name, "gpu-kata"); + assert!(!provenance.resource_version.is_empty()); + + let spec = created.spec.expect("resolved sandbox spec"); + assert_eq!(spec.providers, vec!["work-github".to_string()]); + assert!(spec.policy.is_some()); + assert_eq!( + spec.environment.get("FEATURE_FLAG"), + Some(&"on".to_string()) + ); + + let template = spec.template.expect("resolved inline template"); + assert_eq!(template.image, "registry.example.com/agent:latest"); + let limits = template + .resources + .as_ref() + .and_then(|resources| resources.fields.get("limits")) + .and_then(|limits| limits.kind.as_ref()) + .and_then(|kind| match kind { + Kind::StructValue(value) => Some(&value.fields), + _ => None, + }) + .expect("resource limits"); + assert_eq!(limits.get("cpu").and_then(proto_string_value), Some("2")); + assert_eq!( + limits.get("memory").and_then(proto_string_value), + Some("4Gi") + ); + assert_eq!( + spec.resource_requirements + .and_then(|requirements| requirements.gpu) + .and_then(|gpu| gpu.count), + Some(1) + ); + } + + #[tokio::test] + async fn create_sandbox_from_workload_template_defaults_whitespace_image() { + let state = test_server_state().await; + let mut template = test_workload_template("default-image"); + template + .spec + .as_mut() + .and_then(|spec| spec.workload.as_mut()) + .expect("test template workload") + .image = " ".to_string(); + handle_create_sandbox_template( + &state, + authed_request(CreateSandboxTemplateRequest { + template: Some(template), + workspace: "default".to_string(), + }), + ) + .await + .expect("template create should succeed"); + + let created = handle_create_sandbox( + &state, + authed_request(CreateSandboxRequest { + name: "from-template".to_string(), + spec: Some(SandboxSpec::default()), + labels: HashMap::new(), + annotations: HashMap::new(), + workspace: "default".to_string(), + workload_template_name: "default-image".to_string(), + }), + ) + .await + .expect("sandbox create from template should succeed") + .into_inner() + .sandbox + .expect("created sandbox"); + + let image = created + .spec + .and_then(|spec| spec.template) + .map(|template| template.image) + .expect("resolved template image"); + assert_eq!(image, state.compute.default_image()); + } + + #[tokio::test] + async fn create_sandbox_from_workload_template_rejects_inline_workload_overrides() { + let state = test_server_state().await; + handle_create_sandbox_template( + &state, + authed_request(CreateSandboxTemplateRequest { + template: Some(test_workload_template("gpu-kata")), + workspace: "default".to_string(), + }), + ) + .await + .expect("template create should succeed"); + + let err = handle_create_sandbox( + &state, + authed_request(CreateSandboxRequest { + name: "bad-template-create".to_string(), + spec: Some(SandboxSpec { + environment: HashMap::from([("INLINE".to_string(), "blocked".to_string())]), + ..Default::default() + }), + labels: HashMap::new(), + annotations: HashMap::new(), + workspace: "default".to_string(), + workload_template_name: "gpu-kata".to_string(), + }), + ) + .await + .expect_err("inline workload overrides should be rejected"); + + assert_eq!(err.code(), tonic::Code::InvalidArgument); + assert!(err.message().contains("spec.environment")); + } + + #[tokio::test] + async fn create_sandbox_from_workload_template_rejects_malformed_template_name() { + let state = test_server_state().await; + + let err = handle_create_sandbox( + &state, + authed_request(CreateSandboxRequest { + name: "bad-template-create".to_string(), + spec: Some(SandboxSpec::default()), + labels: HashMap::new(), + annotations: HashMap::new(), + workspace: "default".to_string(), + workload_template_name: "Invalid_Template_Name".to_string(), + }), + ) + .await + .expect_err("malformed template name should be rejected before lookup"); + + assert_eq!(err.code(), tonic::Code::InvalidArgument); + assert!(err.message().contains("workload_template_name")); + } + #[tokio::test] async fn attach_sandbox_provider_rejects_credential_key_collisions() { let state = test_server_state().await; @@ -4421,7 +5184,7 @@ mod tests { &state, non_member_request(CreateSandboxRequest { workspace: "no-such-ws".into(), - spec: Some(openshell_core::proto::SandboxSpec::default()), + spec: Some(SandboxSpec::default()), ..Default::default() }), ) diff --git a/crates/openshell-server/src/grpc/workspace.rs b/crates/openshell-server/src/grpc/workspace.rs index d83ffab0e8..7446938156 100644 --- a/crates/openshell-server/src/grpc/workspace.rs +++ b/crates/openshell-server/src/grpc/workspace.rs @@ -14,9 +14,9 @@ use openshell_core::proto::{ CreateWorkspaceResponse, DeleteWorkspaceRequest, DeleteWorkspaceResponse, GetWorkspaceRequest, GetWorkspaceResponse, InferenceRoute, ListWorkspaceMembersRequest, ListWorkspaceMembersResponse, ListWorkspacesRequest, ListWorkspacesResponse, Provider, - RemoveWorkspaceMemberRequest, RemoveWorkspaceMemberResponse, Sandbox, ServiceEndpoint, - SshSession, StoredProviderCredentialRefreshState, StoredProviderProfile, Workspace, - WorkspaceMember, WorkspaceRole, + RemoveWorkspaceMemberRequest, RemoveWorkspaceMemberResponse, Sandbox, SandboxWorkloadTemplate, + ServiceEndpoint, SshSession, StoredProviderCredentialRefreshState, StoredProviderProfile, + Workspace, WorkspaceMember, WorkspaceRole, }; use prost::Message; use tonic::{Request, Response, Status}; @@ -375,6 +375,7 @@ pub(super) async fn handle_delete_workspace( let mut blocking = Vec::new(); for (object_type, label) in [ (Sandbox::object_type(), "sandbox"), + (SandboxWorkloadTemplate::object_type(), "sandbox template"), (Provider::object_type(), "provider"), (StoredProviderProfile::object_type(), "provider profile"), (ServiceEndpoint::object_type(), "service"), @@ -819,6 +820,72 @@ mod tests { assert!(resp.deleted); } + #[tokio::test] + async fn delete_workspace_blocked_by_sandbox_template() { + let state = test_server_state().await; + + handle_create_workspace( + &state, + Request::new(CreateWorkspaceRequest { + name: "templated".to_string(), + labels: HashMap::new(), + }), + ) + .await + .unwrap(); + + let template = SandboxWorkloadTemplate { + metadata: Some(ObjectMeta { + id: "template-1".to_string(), + name: "gpu-kata".to_string(), + created_at_ms: 1_000_000, + labels: HashMap::new(), + annotations: HashMap::new(), + resource_version: 0, + workspace: "templated".to_string(), + deletion_timestamp_ms: 0, + }), + spec: None, + }; + state.store.put_message(&template).await.unwrap(); + + let err = handle_delete_workspace( + &state, + Request::new(DeleteWorkspaceRequest { + name: "templated".to_string(), + }), + ) + .await + .unwrap_err(); + assert_eq!(err.code(), Code::FailedPrecondition); + assert!( + err.message().contains("sandbox template"), + "error should name sandbox templates as blocking resources: {}", + err.message() + ); + + state + .store + .delete_by_name( + SandboxWorkloadTemplate::object_type(), + "templated", + "gpu-kata", + ) + .await + .unwrap(); + + let resp = handle_delete_workspace( + &state, + Request::new(DeleteWorkspaceRequest { + name: "templated".to_string(), + }), + ) + .await + .unwrap() + .into_inner(); + assert!(resp.deleted); + } + #[tokio::test] async fn delete_workspace_blocked_by_ssh_session() { let state = test_server_state().await; diff --git a/crates/openshell-server/src/persistence/tests.rs b/crates/openshell-server/src/persistence/tests.rs index 8802ac8d10..14e6d48f3a 100644 --- a/crates/openshell-server/src/persistence/tests.rs +++ b/crates/openshell-server/src/persistence/tests.rs @@ -1709,6 +1709,7 @@ async fn cas_update_message_cas_succeeds() { }), spec: None, status: None, + ..Sandbox::default() }; store.put_message(&sandbox).await.unwrap(); @@ -1751,6 +1752,7 @@ async fn cas_update_message_cas_conflicts_on_concurrent_updates() { }), spec: None, status: None, + ..Sandbox::default() }; store.put_message(&sandbox).await.unwrap(); @@ -1821,6 +1823,7 @@ async fn cas_update_message_cas_rejects_workspace_change() { }), spec: None, status: None, + ..Sandbox::default() }; store.put_message(&sandbox).await.unwrap(); @@ -1863,6 +1866,7 @@ async fn cas_update_message_cas_rejects_name_change() { }), spec: None, status: None, + ..Sandbox::default() }; store.put_message(&sandbox).await.unwrap(); diff --git a/crates/openshell-server/tests/common/mod.rs b/crates/openshell-server/tests/common/mod.rs index a2df4755f0..a4f63d4cbf 100644 --- a/crates/openshell-server/tests/common/mod.rs +++ b/crates/openshell-server/tests/common/mod.rs @@ -83,6 +83,34 @@ impl OpenShell for TestOpenShell { Ok(Response::new(SandboxResponse::default())) } + async fn create_sandbox_template( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn get_sandbox_template( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn list_sandbox_templates( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn delete_sandbox_template( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + async fn stop_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 86c7354647..ed555142c7 100644 --- a/crates/openshell-server/tests/supervisor_relay_integration.rs +++ b/crates/openshell-server/tests/supervisor_relay_integration.rs @@ -68,6 +68,34 @@ impl OpenShell for RelayGateway { // ------ unused stubs ------ + async fn create_sandbox_template( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn get_sandbox_template( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn list_sandbox_templates( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + + async fn delete_sandbox_template( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("unused")) + } + type ConnectSupervisorStream = ReceiverStream>; async fn connect_supervisor( &self, diff --git a/crates/openshell-tui/src/lib.rs b/crates/openshell-tui/src/lib.rs index 1f610015b4..adfc95e071 100644 --- a/crates/openshell-tui/src/lib.rs +++ b/crates/openshell-tui/src/lib.rs @@ -1407,6 +1407,7 @@ fn spawn_create_sandbox(app: &mut App, tx: mpsc::UnboundedSender) { labels: HashMap::new(), annotations: HashMap::new(), workspace: workspace.clone(), + workload_template_name: String::new(), }; let sandbox_name = diff --git a/docs/sandboxes/manage-sandboxes.mdx b/docs/sandboxes/manage-sandboxes.mdx index abd95d130a..6ce68189fc 100644 --- a/docs/sandboxes/manage-sandboxes.mdx +++ b/docs/sandboxes/manage-sandboxes.mdx @@ -128,6 +128,54 @@ Local directories and Dockerfiles require a local gateway because the CLI builds through the local Docker daemon. Use a registry image reference for remote gateways. +## Reuse Workload Templates + +Sandbox workload templates let workspace admins define reusable runtime shapes for a workspace. A template stores the image, environment, resource requests, and driver-specific configuration that sandboxes should inherit. When you create a sandbox from a template, the create request can still attach providers, labels, and policy, but the workload comes from the named template. + +Create a template: + +```shell +openshell sandbox template create gpu-kata \ + --image registry.example.com/agent:latest \ + --cpu 2 \ + --memory 4Gi \ + --gpu 1 \ + --label team=runtime \ + --env FEATURE_FLAG=on +``` + +Add driver-specific settings when the active compute driver needs them: + +```shell +openshell sandbox template create gpu-kata \ + --image registry.example.com/agent:latest \ + --driver-config-json '{"kubernetes":{"pod":{"runtime_class_name":"kata-containers","node_selector":{"pool":"gpu"}}}}' +``` + +If you omit `--image`, the gateway applies its default sandbox image when a sandbox is created from the template. Use this when the template should only define resource, environment, or driver settings. + +Create a sandbox from a template: + +```shell +openshell sandbox create --template gpu-kata --provider github -- claude +``` + +The `--template` flag cannot be combined with inline workload flags such as `--from`, `--cpu`, `--memory`, `--gpu`, `--env`, or `--driver-config-json`. Put those values on the template instead. Create-time policy and provider attachments remain part of the sandbox request, so each sandbox can keep its own access boundary. + +Inspect and manage templates: + +```shell +openshell sandbox template list +openshell sandbox template get gpu-kata +openshell sandbox template delete gpu-kata +``` + +Use `--all-workspaces` with `sandbox template list` when you need an admin view across workspaces: + +```shell +openshell sandbox template list --all-workspaces +``` + ## Base Sandbox Container The `base` sandbox container is the default runtime image for standard OpenShell sandboxes unless the gateway overrides its default sandbox image. It is published as `ghcr.io/nvidia/openshell-community/sandboxes/base:latest` and maintained in the [OpenShell Community](https://github.com/NVIDIA/OpenShell-Community/tree/main/sandboxes/base) repository. diff --git a/e2e/rust/Cargo.toml b/e2e/rust/Cargo.toml index 0b8b56f3e5..8fb7adacc8 100644 --- a/e2e/rust/Cargo.toml +++ b/e2e/rust/Cargo.toml @@ -151,6 +151,11 @@ name = "workspace_lifecycle" path = "tests/workspace_lifecycle.rs" required-features = ["e2e"] +[[test]] +name = "sandbox_templates" +path = "tests/sandbox_templates.rs" +required-features = ["e2e"] + [[test]] name = "proxy_egress_pipeline" path = "tests/proxy_egress_pipeline.rs" diff --git a/e2e/rust/tests/sandbox_templates.rs b/e2e/rust/tests/sandbox_templates.rs new file mode 100644 index 0000000000..2b9bd11760 --- /dev/null +++ b/e2e/rust/tests/sandbox_templates.rs @@ -0,0 +1,173 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![cfg(feature = "e2e")] + +//! E2E coverage for reusable sandbox workload templates. + +use std::process::Stdio; +use std::time::{SystemTime, UNIX_EPOCH}; + +use openshell_e2e::harness::binary::{openshell_bin, openshell_cmd}; +use openshell_e2e::harness::output::strip_ansi; +use openshell_e2e::harness::sandbox::SandboxGuard; +use serde_json::Value; + +struct CliResult { + output: String, + success: bool, +} + +struct TemplateGuard { + name: String, +} + +impl TemplateGuard { + fn new(name: String) -> Self { + Self { name } + } + + async fn cleanup(mut self) { + delete_template(&self.name).await; + self.name.clear(); + } +} + +impl Drop for TemplateGuard { + fn drop(&mut self) { + if self.name.is_empty() { + return; + } + let bin = openshell_bin(); + let _ = std::process::Command::new(&bin) + .args(["sandbox", "template", "delete", &self.name]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status(); + } +} + +async fn run_cli(args: &[&str]) -> CliResult { + let mut cmd = openshell_cmd(); + cmd.args(args).stdout(Stdio::piped()).stderr(Stdio::piped()); + + let output = cmd.output().await.expect("spawn openshell command"); + let stdout = String::from_utf8_lossy(&output.stdout).to_string(); + let stderr = String::from_utf8_lossy(&output.stderr).to_string(); + let combined = format!("{stdout}{stderr}"); + + CliResult { + output: strip_ansi(&combined), + success: output.status.success(), + } +} + +async fn delete_template(name: &str) { + let mut cmd = openshell_cmd(); + cmd.args(["sandbox", "template", "delete", name]) + .stdout(Stdio::null()) + .stderr(Stdio::null()); + let _ = cmd.status().await; +} + +fn unique_name(prefix: &str) -> String { + let millis = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system clock before epoch") + .as_millis(); + let suffix = millis % 1_000_000; + format!("{prefix}-{suffix:06}") +} + +#[tokio::test] +async fn sandbox_create_from_template_uses_reusable_workload() { + let template_name = unique_name("tmpl"); + let sandbox_name = unique_name("sb-tmpl"); + let template = TemplateGuard::new(template_name.clone()); + + let create_template = run_cli(&[ + "sandbox", + "template", + "create", + &template_name, + "--cpu", + "500m", + "--memory", + "512Mi", + "--label", + "e2e=sandbox-template", + "--env", + "FEATURE_FLAG=on", + ]) + .await; + assert!( + create_template.success, + "sandbox template create failed:\n{}", + create_template.output + ); + + let get_template = run_cli(&[ + "sandbox", + "template", + "get", + &template_name, + "--output", + "json", + ]) + .await; + assert!( + get_template.success, + "sandbox template get failed:\n{}", + get_template.output + ); + let template_json: Value = + serde_json::from_str(&get_template.output).expect("template JSON output"); + assert_eq!(template_json["name"].as_str(), Some(template_name.as_str())); + assert_eq!( + template_json["labels"]["e2e"].as_str(), + Some("sandbox-template") + ); + assert_eq!( + template_json["environment"]["FEATURE_FLAG"].as_str(), + Some("on") + ); + assert_eq!(template_json["resources"]["cpu"].as_str(), Some("500m")); + assert_eq!(template_json["resources"]["memory"].as_str(), Some("512Mi")); + + let list_templates = run_cli(&["sandbox", "template", "list", "--names"]).await; + assert!( + list_templates.success, + "sandbox template list failed:\n{}", + list_templates.output + ); + assert!( + list_templates + .output + .lines() + .any(|line| line.trim() == template_name), + "template list should include {template_name}:\n{}", + list_templates.output + ); + + let mut sandbox = SandboxGuard::create(&[ + "--name", + &sandbox_name, + "--template", + &template_name, + "--", + "sh", + "-lc", + "test \"$FEATURE_FLAG\" = on && echo template-env-ok", + ]) + .await + .expect("sandbox create from template should succeed"); + + assert!( + sandbox.create_output.contains("template-env-ok"), + "sandbox should inherit template environment:\n{}", + sandbox.create_output + ); + + sandbox.cleanup().await; + template.cleanup().await; +} diff --git a/proto/openshell.proto b/proto/openshell.proto index 4dd290090d..ad4a41b9ff 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -6,6 +6,7 @@ syntax = "proto3"; package openshell.v1; import "datamodel.proto"; +import "google/protobuf/duration.proto"; import "google/protobuf/struct.proto"; import "options.proto"; import "sandbox.proto"; @@ -69,6 +70,46 @@ service OpenShell { }; } + // Create a reusable sandbox workload template. + rpc CreateSandboxTemplate(CreateSandboxTemplateRequest) + returns (SandboxTemplateResponse) { + option (openshell.options.v1.authorization) = { + auth_mode: "bearer" + scope: "sandbox:write" + workspace_role: "admin" + }; + } + + // Fetch a reusable sandbox workload template by name. + rpc GetSandboxTemplate(GetSandboxTemplateRequest) + returns (SandboxTemplateResponse) { + option (openshell.options.v1.authorization) = { + auth_mode: "bearer" + scope: "sandbox:read" + workspace_role: "user" + }; + } + + // List reusable sandbox workload templates. + rpc ListSandboxTemplates(ListSandboxTemplatesRequest) + returns (ListSandboxTemplatesResponse) { + option (openshell.options.v1.authorization) = { + auth_mode: "bearer" + scope: "sandbox:read" + workspace_role: "user" + }; + } + + // Delete a reusable sandbox workload template by name. + rpc DeleteSandboxTemplate(DeleteSandboxTemplateRequest) + returns (DeleteSandboxTemplateResponse) { + option (openshell.options.v1.authorization) = { + auth_mode: "bearer" + scope: "sandbox:write" + workspace_role: "admin" + }; + } + // List provider records attached to a sandbox. rpc ListSandboxProviders(ListSandboxProvidersRequest) returns (ListSandboxProvidersResponse) { @@ -789,6 +830,8 @@ message Sandbox { SandboxSpec spec = 2; // Latest user-facing observed status derived by the gateway. SandboxStatus status = 3; + // Read-only provenance for sandboxes created from a reusable workload template. + SandboxWorkloadTemplateProvenance created_from_workload_template = 20; reserved 4, 5; reserved "phase", "current_policy_version"; @@ -831,7 +874,12 @@ message GpuResourceRequirements { optional uint32 count = 1; } -// Public sandbox template mapped onto compute-driver template inputs. +// Historical inline compute template mapped onto compute-driver template inputs. +// +// Despite its name, this is not a reusable named sandbox template resource. It +// is an inline part of `SandboxSpec` kept for v1 compatibility. A future +// breaking API cleanup may rename this message to free `SandboxTemplate` for +// the reusable template resource now represented by `SandboxWorkloadTemplate`. message SandboxTemplate { // Fully-qualified OCI image reference used to boot the sandbox. string image = 1; @@ -862,6 +910,60 @@ message SandboxTemplate { google.protobuf.Struct driver_config = 11; } +// Reusable named sandbox workload template resource. +// +// This is the actual workspace-scoped template resource used to create +// sandboxes by reference. It uses the longer name in v1 to avoid colliding with +// the historical inline `SandboxTemplate` message. A future breaking API +// cleanup may rename this resource to `SandboxTemplate`. +message SandboxWorkloadTemplate { + // Kubernetes-style metadata (id, name, labels, timestamps, resource version). + openshell.datamodel.v1.ObjectMeta metadata = 1; + // Desired reusable workload shape and template-owned driver config. + SandboxWorkloadTemplateSpec spec = 2; +} + +message SandboxWorkloadTemplateSpec { + // Portable workload shape. + SandboxWorkloadConfig workload = 1; + // Driver-keyed opaque config envelope supplied by the template owner. + google.protobuf.Struct driver_config = 2; + // Desired service level associated with this template. + SandboxServiceLevel desired_service_level = 3; +} + +message SandboxWorkloadConfig { + // Fully-qualified OCI image reference used to boot the sandbox. + string image = 1; + // Environment variables injected into the sandbox runtime. + map environment = 2; + // Portable resource requirements for sandboxes created from this workload. + SandboxResources resources = 3; +} + +message SandboxResources { + // Portable CPU quantity, for example "500m" or "2". + string cpu = 1; + // Portable memory quantity, for example "512Mi" or "2Gi". + string memory = 2; + // Optional number of GPUs requested. + optional uint32 gpu_count = 3; +} + +message SandboxServiceLevel { + SandboxStartup startup = 1; +} + +message SandboxStartup { + google.protobuf.Duration ready_within = 1; + uint32 max_burst = 2; +} + +message SandboxWorkloadTemplateProvenance { + string name = 1; + string resource_version = 2; +} + // User-facing sandbox status derived by the gateway from compute-driver observations. // // Public status does not embed driver-only flags such as `deleting`. @@ -939,6 +1041,47 @@ message CreateSandboxRequest { map annotations = 4; // Workspace for the sandbox. Empty defaults to "default". string workspace = 5; + // Workspace-scoped SandboxWorkloadTemplate name to resolve at creation time. + string workload_template_name = 6; +} + +message CreateSandboxTemplateRequest { + SandboxWorkloadTemplate template = 1; + // Workspace for the template. Empty defaults to "default". + string workspace = 2; +} + +message GetSandboxTemplateRequest { + string name = 1; + // Workspace scope. Empty defaults to "default". + string workspace = 2; +} + +message ListSandboxTemplatesRequest { + uint32 limit = 1; + uint32 offset = 2; + // Workspace scope. Empty defaults to "default". + string workspace = 3; + // List across all workspaces. Mutually exclusive with workspace. + bool all_workspaces = 4; +} + +message DeleteSandboxTemplateRequest { + string name = 1; + // Workspace scope. Empty defaults to "default". + string workspace = 2; +} + +message SandboxTemplateResponse { + SandboxWorkloadTemplate template = 1; +} + +message ListSandboxTemplatesResponse { + repeated SandboxWorkloadTemplate templates = 1; +} + +message DeleteSandboxTemplateResponse { + bool deleted = 1; } // Get sandbox request. diff --git a/python/openshell/sandbox.py b/python/openshell/sandbox.py index a76be8dd13..6af9572be2 100644 --- a/python/openshell/sandbox.py +++ b/python/openshell/sandbox.py @@ -459,6 +459,33 @@ def create( raise SandboxError("CreateSandbox returned empty sandbox id") return sandbox_ref + def create_from_template( + self, + *, + workspace: str, + template_name: str, + spec: openshell_pb2.SandboxSpec | None = None, + name: str | None = None, + labels: Mapping[str, str] | None = None, + ) -> SandboxRef: + if not template_name.strip(): + raise SandboxError("template_name is required") + request_spec = spec if spec is not None else openshell_pb2.SandboxSpec() + response = self._stub.CreateSandbox( + openshell_pb2.CreateSandboxRequest( + spec=request_spec, + name=name or "", + labels=dict(labels) if labels else {}, + workspace=workspace, + workload_template_name=template_name, + ), + timeout=self._timeout, + ) + sandbox_ref = _sandbox_ref(response.sandbox) + if sandbox_ref.id == "": + raise SandboxError("CreateSandbox returned empty sandbox id") + return sandbox_ref + def create_session( self, *, @@ -471,6 +498,26 @@ def create_session( self, self.create(workspace=workspace, spec=spec, name=name, labels=labels) ) + def create_session_from_template( + self, + *, + workspace: str, + template_name: str, + spec: openshell_pb2.SandboxSpec | None = None, + name: str | None = None, + labels: Mapping[str, str] | None = None, + ) -> SandboxSession: + return SandboxSession( + self, + self.create_from_template( + workspace=workspace, + template_name=template_name, + spec=spec, + name=name, + labels=labels, + ), + ) + def get(self, sandbox_name: str, *, workspace: str) -> SandboxRef: response = self._stub.GetSandbox( openshell_pb2.GetSandboxRequest(name=sandbox_name, workspace=workspace), @@ -899,6 +946,7 @@ def __init__( spec: openshell_pb2.SandboxSpec | None = None, name: str | None = None, labels: Mapping[str, str] | None = None, + template_name: str | None = None, timeout: float = 30.0, ready_timeout_seconds: float = 120.0, auto_refresh: bool = True, @@ -922,6 +970,7 @@ def __init__( self._name = name # Copy so later caller mutation cannot change what gets sent on enter. self._labels = dict(labels) if labels is not None else None + self._template_name = template_name self._timeout = timeout self._ready_timeout_seconds = ready_timeout_seconds self._auto_refresh = auto_refresh @@ -946,10 +995,12 @@ def __enter__(self) -> Sandbox: # Creation metadata cannot be applied when attaching to an existing # sandbox; reject it before opening a connection. if self._sandbox_input is not None and ( - self._name is not None or self._labels is not None + self._name is not None + or self._labels is not None + or self._template_name is not None ): raise SandboxError( - "name and labels cannot be set when attaching to an existing sandbox" + "name, labels, and template_name cannot be set when attaching to an existing sandbox" ) client = SandboxClient.from_active_cluster( @@ -961,7 +1012,15 @@ def __enter__(self) -> Sandbox: ) self._client = client - if self._sandbox_input is None: + if self._sandbox_input is None and self._template_name is not None: + self._session = client.create_session_from_template( + workspace=self._workspace, + template_name=self._template_name, + spec=self._spec, + name=self._name, + labels=self._labels, + ) + elif self._sandbox_input is None: self._session = client.create_session( workspace=self._workspace, spec=self._spec, diff --git a/python/openshell/sandbox_test.py b/python/openshell/sandbox_test.py index 9ff84341e7..95d8e7ed66 100644 --- a/python/openshell/sandbox_test.py +++ b/python/openshell/sandbox_test.py @@ -1632,6 +1632,7 @@ class _RecordingHighLevelClient: def __init__(self) -> None: self.create_kwargs: dict[str, Any] | None = None + self.create_template_kwargs: dict[str, Any] | None = None def create_session( self, @@ -1649,6 +1650,24 @@ def create_session( } return SimpleNamespace(sandbox=SimpleNamespace(name=name or "generated")) + def create_session_from_template( + self, + *, + workspace: str, + template_name: str, + spec: Any = None, + name: str | None = None, + labels: Any = None, + ) -> Any: + self.create_template_kwargs = { + "workspace": workspace, + "template_name": template_name, + "spec": spec, + "name": name, + "labels": labels, + } + return SimpleNamespace(sandbox=SimpleNamespace(name=name or "generated")) + def wait_ready( self, name: str, *, workspace: str, timeout_seconds: float = 300.0 ) -> SandboxRef: @@ -1675,6 +1694,37 @@ def test_create_forwards_name_and_labels() -> None: assert dict(ref.labels) == {"aiq": "deep-research"} +def test_create_from_template_forwards_workload_template_name() -> None: + stub = _FakeSandboxStub() + client = _client_with_fake_stub(stub) + spec = openshell_pb2.SandboxSpec(providers=["github"]) + + ref = client.create_from_template( + workspace="default", + template_name="gpu-kata", + spec=spec, + name="job-1", + labels={"team": "runtime"}, + ) + + assert stub.create_request is not None + assert stub.create_request.name == "job-1" + assert stub.create_request.workload_template_name == "gpu-kata" + assert dict(stub.create_request.labels) == {"team": "runtime"} + assert list(stub.create_request.spec.providers) == ["github"] + assert dict(ref.labels) == {"team": "runtime"} + + +def test_create_from_template_rejects_empty_template_name() -> None: + stub = _FakeSandboxStub() + client = _client_with_fake_stub(stub) + + with pytest.raises(SandboxError): + client.create_from_template(workspace="default", template_name=" ") + + assert stub.create_request is None + + def test_stop_and_start_forward_workspace_and_return_phase() -> None: stub = _FakeSandboxStub() client = _client_with_fake_stub(stub) @@ -1867,6 +1917,36 @@ def test_high_level_creation_forwards_name_and_labels( } +def test_high_level_template_creation_forwards_template_name( + monkeypatch: pytest.MonkeyPatch, +) -> None: + recording = _RecordingHighLevelClient() + monkeypatch.setattr( + SandboxClient, + "from_active_cluster", + classmethod(lambda _cls, **_kwargs: recording), + ) + + spec = openshell_pb2.SandboxSpec(providers=["github"]) + sandbox = Sandbox( + workspace="staging", + template_name="gpu-kata", + spec=spec, + name="job-1", + labels={"team": "runtime"}, + delete_on_exit=False, + ) + sandbox.__enter__() + + assert recording.create_template_kwargs == { + "workspace": "staging", + "template_name": "gpu-kata", + "spec": spec, + "name": "job-1", + "labels": {"team": "runtime"}, + } + + def test_high_level_attach_rejects_name() -> None: sandbox = Sandbox(workspace="default", sandbox="existing-sandbox", name="job-1") @@ -1887,6 +1967,15 @@ def test_high_level_attach_rejects_labels() -> None: sandbox.__enter__() +def test_high_level_attach_rejects_template_name() -> None: + sandbox = Sandbox( + workspace="default", sandbox="existing-sandbox", template_name="gpu-kata" + ) + + with pytest.raises(SandboxError): + sandbox.__enter__() + + # --------------------------------------------------------------------------- # Workspace support # --------------------------------------------------------------------------- diff --git a/sdk/go/openshell/v1/client.go b/sdk/go/openshell/v1/client.go index bc3ee43165..ec011372a5 100644 --- a/sdk/go/openshell/v1/client.go +++ b/sdk/go/openshell/v1/client.go @@ -4,6 +4,7 @@ package v1 import ( + "context" "sync" "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types" @@ -112,6 +113,12 @@ func NewClient(cfg Config) (*Client, error) { // Sandboxes returns the sandbox sub-client. func (c *Client) Sandboxes() SandboxInterface { return c.sandboxes } +// CreateSandboxFromTemplate creates a sandbox from a named workload template +// without changing the legacy Sandboxes() interface. +func (c *Client) CreateSandboxFromTemplate(ctx context.Context, workspace, name, templateName string, spec *SandboxSpec, labels map[string]string, opts ...CreateOptions) (*Sandbox, error) { + return c.sandboxes.(SandboxTemplateCreateInterface).CreateFromTemplate(ctx, workspace, name, templateName, spec, labels, opts...) +} + // 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 d2978bc08c..7a82c0e1a6 100644 --- a/sdk/go/openshell/v1/fake/fake.go +++ b/sdk/go/openshell/v1/fake/fake.go @@ -4,6 +4,7 @@ package fake import ( + "context" "sync" v1 "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1" @@ -107,6 +108,12 @@ func (fc *Client) isClosed() bool { // Sandboxes returns the sandbox sub-client. func (fc *Client) Sandboxes() v1.SandboxInterface { return fc.sandboxes } +// CreateSandboxFromTemplate creates a sandbox from a named workload template +// without changing the legacy Sandboxes() interface. +func (fc *Client) CreateSandboxFromTemplate(ctx context.Context, workspace, name, templateName string, spec *types.SandboxSpec, labels map[string]string, opts ...types.CreateOptions) (*types.Sandbox, error) { + return fc.sandboxes.(v1.SandboxTemplateCreateInterface).CreateFromTemplate(ctx, workspace, name, templateName, spec, labels, opts...) +} + // 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 da32adf4c5..f34e44a33f 100644 --- a/sdk/go/openshell/v1/fake/sandbox.go +++ b/sdk/go/openshell/v1/fake/sandbox.go @@ -260,6 +260,9 @@ type fakeSandboxClient struct { closedFunc func() bool } +var _ v1.SandboxInterface = (*fakeSandboxClient)(nil) +var _ v1.SandboxTemplateCreateInterface = (*fakeSandboxClient)(nil) + // newFakeSandboxClient creates a new fakeSandboxClient. func newFakeSandboxClient( store *objectStore[*types.Sandbox], @@ -315,6 +318,52 @@ func (c *fakeSandboxClient) Create(_ context.Context, workspace, name string, sp return result, nil } +// CreateFromTemplate creates a new sandbox from a named template with Provisioning phase. +func (c *fakeSandboxClient) CreateFromTemplate(_ context.Context, workspace, name, templateName string, spec *types.SandboxSpec, labels map[string]string, opts ...types.CreateOptions) (*types.Sandbox, error) { + if c.closedFunc() { + return nil, &types.StatusError{Code: types.ErrorUnavailable, Message: "client is closed"} + } + if templateName == "" { + return nil, &types.StatusError{Code: types.ErrorInvalidArgument, Message: "template name is required"} + } + if spec == nil { + spec = &types.SandboxSpec{} + } + + var annotations map[string]string + if len(opts) > 0 { + annotations = copyStringMap(opts[0].Annotations) + } + + sb := &types.Sandbox{ + Name: name, + Workspace: workspace, + CreatedAt: time.Now(), + Labels: copyStringMap(labels), + Annotations: annotations, + Spec: types.SandboxSpec{ + Providers: copyStringSlice(spec.Providers), + Policy: copySandboxPolicy(spec.Policy), + }, + Status: types.SandboxStatus{ + SandboxName: name, + Phase: types.SandboxProvisioning, + }, + } + + result, err := c.store.Create(workspace, sb) + if err != nil { + return nil, err + } + + c.broadcaster.Broadcast(types.Event[*types.Sandbox]{ + Type: types.EventAdded, + Object: copySandbox(result), + }, name) + + return result, nil +} + // Get retrieves a sandbox by name. func (c *fakeSandboxClient) Get(_ context.Context, workspace, name string) (*types.Sandbox, error) { if c.closedFunc() { diff --git a/sdk/go/openshell/v1/sandbox.go b/sdk/go/openshell/v1/sandbox.go index 871bbb1bf3..79174ac7f3 100644 --- a/sdk/go/openshell/v1/sandbox.go +++ b/sdk/go/openshell/v1/sandbox.go @@ -67,3 +67,9 @@ type SandboxInterface interface { Watch(ctx context.Context, workspace, name string, opts ...WatchOptions) (WatchInterface[*Sandbox], error) GetLogs(ctx context.Context, workspace, sandboxName string, opts ...LogOption) (*LogResult, error) } + +// SandboxTemplateCreateInterface defines additive sandbox creation from named +// workload templates without widening SandboxInterface. +type SandboxTemplateCreateInterface interface { + CreateFromTemplate(ctx context.Context, workspace, name, templateName string, spec *SandboxSpec, labels map[string]string, opts ...CreateOptions) (*Sandbox, error) +} diff --git a/sdk/go/openshell/v1/sandbox_client.go b/sdk/go/openshell/v1/sandbox_client.go index 94d6047a01..f33d0eeedb 100644 --- a/sdk/go/openshell/v1/sandbox_client.go +++ b/sdk/go/openshell/v1/sandbox_client.go @@ -21,6 +21,9 @@ type sandboxClient struct { client pb.OpenShellClient } +var _ SandboxInterface = (*sandboxClient)(nil) +var _ SandboxTemplateCreateInterface = (*sandboxClient)(nil) + func newSandboxClient(conn grpc.ClientConnInterface) *sandboxClient { return &sandboxClient{client: pb.NewOpenShellClient(conn)} } @@ -46,6 +49,44 @@ func (s *sandboxClient) Create(ctx context.Context, workspace, name string, spec return converter.SandboxFromProto(resp.GetSandbox()), nil } +func (s *sandboxClient) CreateFromTemplate(ctx context.Context, workspace, name, templateName string, spec *SandboxSpec, labels map[string]string, opts ...CreateOptions) (*Sandbox, error) { + if templateName == "" { + return nil, &StatusError{Code: ErrorInvalidArgument, Message: "template name is required"} + } + if err := validateTemplateCreateSpec(spec); err != nil { + return nil, err + } + protoSpec, err := converter.SandboxSpecToProtoChecked(spec) + if err != nil { + return nil, &StatusError{Code: ErrorInvalidArgument, Message: err.Error()} + } + req := &pb.CreateSandboxRequest{ + Name: name, + Spec: protoSpec, + Labels: labels, + Workspace: workspace, + WorkloadTemplateName: templateName, + } + if len(opts) > 0 { + req.Annotations = converter.CopyStringMap(opts[0].Annotations) + } + resp, err := s.client.CreateSandbox(ctx, req) + if err != nil { + return nil, converter.FromGRPCError(err) + } + return converter.SandboxFromProto(resp.GetSandbox()), nil +} + +func validateTemplateCreateSpec(spec *SandboxSpec) error { + if spec == nil { + return nil + } + if spec.LogLevel != "" || len(spec.Environment) > 0 || spec.Template != nil || spec.GPUCount != nil { + return &StatusError{Code: ErrorInvalidArgument, Message: "template creates only allow policy and providers in spec"} + } + return nil +} + func (s *sandboxClient) Get(ctx context.Context, workspace, name string) (*Sandbox, error) { resp, err := s.client.GetSandbox(ctx, &pb.GetSandboxRequest{ Name: name, diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index 102688df4f..5122689899 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -15,6 +15,7 @@ import ( sandboxv1 "github.com/NVIDIA/OpenShell/sdk/go/proto/sandboxv1" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" structpb "google.golang.org/protobuf/types/known/structpb" reflect "reflect" sync "sync" @@ -1041,9 +1042,11 @@ type Sandbox struct { // Desired sandbox configuration submitted through the API. Spec *SandboxSpec `protobuf:"bytes,2,opt,name=spec,proto3" json:"spec,omitempty"` // Latest user-facing observed status derived by the gateway. - Status *SandboxStatus `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Status *SandboxStatus `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` + // Read-only provenance for sandboxes created from a reusable workload template. + CreatedFromWorkloadTemplate *SandboxWorkloadTemplateProvenance `protobuf:"bytes,20,opt,name=created_from_workload_template,json=createdFromWorkloadTemplate,proto3" json:"created_from_workload_template,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Sandbox) Reset() { @@ -1097,6 +1100,13 @@ func (x *Sandbox) GetStatus() *SandboxStatus { return nil } +func (x *Sandbox) GetCreatedFromWorkloadTemplate() *SandboxWorkloadTemplateProvenance { + if x != nil { + return x.CreatedFromWorkloadTemplate + } + return nil +} + // Desired sandbox configuration provided through the public API. type SandboxSpec struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1281,7 +1291,12 @@ func (x *GpuResourceRequirements) GetCount() uint32 { return 0 } -// Public sandbox template mapped onto compute-driver template inputs. +// Historical inline compute template mapped onto compute-driver template inputs. +// +// Despite its name, this is not a reusable named sandbox template resource. It +// is an inline part of `SandboxSpec` kept for v1 compatibility. A future +// breaking API cleanup may rename this message to free `SandboxTemplate` for +// the reusable template resource now represented by `SandboxWorkloadTemplate`. type SandboxTemplate struct { state protoimpl.MessageState `protogen:"open.v1"` // Fully-qualified OCI image reference used to boot the sandbox. @@ -1406,43 +1421,36 @@ func (x *SandboxTemplate) GetDriverConfig() *structpb.Struct { return nil } -// User-facing sandbox status derived by the gateway from compute-driver observations. +// Reusable named sandbox workload template resource. // -// Public status does not embed driver-only flags such as `deleting`. -type SandboxStatus struct { +// This is the actual workspace-scoped template resource used to create +// sandboxes by reference. It uses the longer name in v1 to avoid colliding with +// the historical inline `SandboxTemplate` message. A future breaking API +// cleanup may rename this resource to `SandboxTemplate`. +type SandboxWorkloadTemplate struct { state protoimpl.MessageState `protogen:"open.v1"` - // Compute-platform sandbox object name. - SandboxName string `protobuf:"bytes,1,opt,name=sandbox_name,json=sandboxName,proto3" json:"sandbox_name,omitempty"` - // Name of the agent pod or equivalent runtime instance. - AgentPod string `protobuf:"bytes,2,opt,name=agent_pod,json=agentPod,proto3" json:"agent_pod,omitempty"` - // File descriptor or endpoint for reaching the agent service, when available. - AgentFd string `protobuf:"bytes,3,opt,name=agent_fd,json=agentFd,proto3" json:"agent_fd,omitempty"` - // File descriptor or endpoint for reaching the sandbox service, when available. - SandboxFd string `protobuf:"bytes,4,opt,name=sandbox_fd,json=sandboxFd,proto3" json:"sandbox_fd,omitempty"` - // Latest user-facing readiness and lifecycle conditions. - Conditions []*SandboxCondition `protobuf:"bytes,5,rep,name=conditions,proto3" json:"conditions,omitempty"` - // Gateway-derived lifecycle summary. - Phase SandboxPhase `protobuf:"varint,6,opt,name=phase,proto3,enum=openshell.v1.SandboxPhase" json:"phase,omitempty"` - // Currently active policy version (updated when sandbox reports loaded). - CurrentPolicyVersion uint32 `protobuf:"varint,7,opt,name=current_policy_version,json=currentPolicyVersion,proto3" json:"current_policy_version,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Kubernetes-style metadata (id, name, labels, timestamps, resource version). + Metadata *datamodelv1.ObjectMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // Desired reusable workload shape and template-owned driver config. + Spec *SandboxWorkloadTemplateSpec `protobuf:"bytes,2,opt,name=spec,proto3" json:"spec,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *SandboxStatus) Reset() { - *x = SandboxStatus{} +func (x *SandboxWorkloadTemplate) Reset() { + *x = SandboxWorkloadTemplate{} mi := &file_openshell_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SandboxStatus) String() string { +func (x *SandboxWorkloadTemplate) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SandboxStatus) ProtoMessage() {} +func (*SandboxWorkloadTemplate) ProtoMessage() {} -func (x *SandboxStatus) ProtoReflect() protoreflect.Message { +func (x *SandboxWorkloadTemplate) ProtoReflect() protoreflect.Message { mi := &file_openshell_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1454,92 +1462,115 @@ func (x *SandboxStatus) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SandboxStatus.ProtoReflect.Descriptor instead. -func (*SandboxStatus) Descriptor() ([]byte, []int) { +// Deprecated: Use SandboxWorkloadTemplate.ProtoReflect.Descriptor instead. +func (*SandboxWorkloadTemplate) Descriptor() ([]byte, []int) { return file_openshell_proto_rawDescGZIP(), []int{17} } -func (x *SandboxStatus) GetSandboxName() string { +func (x *SandboxWorkloadTemplate) GetMetadata() *datamodelv1.ObjectMeta { if x != nil { - return x.SandboxName + return x.Metadata } - return "" + return nil } -func (x *SandboxStatus) GetAgentPod() string { +func (x *SandboxWorkloadTemplate) GetSpec() *SandboxWorkloadTemplateSpec { if x != nil { - return x.AgentPod + return x.Spec } - return "" + return nil } -func (x *SandboxStatus) GetAgentFd() string { - if x != nil { - return x.AgentFd - } - return "" +type SandboxWorkloadTemplateSpec struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Portable workload shape. + Workload *SandboxWorkloadConfig `protobuf:"bytes,1,opt,name=workload,proto3" json:"workload,omitempty"` + // Driver-keyed opaque config envelope supplied by the template owner. + DriverConfig *structpb.Struct `protobuf:"bytes,2,opt,name=driver_config,json=driverConfig,proto3" json:"driver_config,omitempty"` + // Desired service level associated with this template. + DesiredServiceLevel *SandboxServiceLevel `protobuf:"bytes,3,opt,name=desired_service_level,json=desiredServiceLevel,proto3" json:"desired_service_level,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *SandboxStatus) GetSandboxFd() string { +func (x *SandboxWorkloadTemplateSpec) Reset() { + *x = SandboxWorkloadTemplateSpec{} + mi := &file_openshell_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxWorkloadTemplateSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxWorkloadTemplateSpec) ProtoMessage() {} + +func (x *SandboxWorkloadTemplateSpec) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[18] if x != nil { - return x.SandboxFd + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return "" + return mi.MessageOf(x) } -func (x *SandboxStatus) GetConditions() []*SandboxCondition { +// Deprecated: Use SandboxWorkloadTemplateSpec.ProtoReflect.Descriptor instead. +func (*SandboxWorkloadTemplateSpec) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{18} +} + +func (x *SandboxWorkloadTemplateSpec) GetWorkload() *SandboxWorkloadConfig { if x != nil { - return x.Conditions + return x.Workload } return nil } -func (x *SandboxStatus) GetPhase() SandboxPhase { +func (x *SandboxWorkloadTemplateSpec) GetDriverConfig() *structpb.Struct { if x != nil { - return x.Phase + return x.DriverConfig } - return SandboxPhase_SANDBOX_PHASE_UNSPECIFIED + return nil } -func (x *SandboxStatus) GetCurrentPolicyVersion() uint32 { +func (x *SandboxWorkloadTemplateSpec) GetDesiredServiceLevel() *SandboxServiceLevel { if x != nil { - return x.CurrentPolicyVersion + return x.DesiredServiceLevel } - return 0 + return nil } -// User-facing sandbox condition derived from driver-native conditions. -type SandboxCondition struct { +type SandboxWorkloadConfig struct { state protoimpl.MessageState `protogen:"open.v1"` - // Condition class, typically mirroring the underlying platform condition type. - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - // Condition status value such as `True`, `False`, or `Unknown`. - Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` - // Short machine-readable reason associated with the condition. - Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` - // Human-readable condition message. - Message string `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"` - // Timestamp reported by the underlying platform for the last transition. - LastTransitionTime string `protobuf:"bytes,5,opt,name=last_transition_time,json=lastTransitionTime,proto3" json:"last_transition_time,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Fully-qualified OCI image reference used to boot the sandbox. + Image string `protobuf:"bytes,1,opt,name=image,proto3" json:"image,omitempty"` + // Environment variables injected into the sandbox runtime. + Environment map[string]string `protobuf:"bytes,2,rep,name=environment,proto3" json:"environment,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Portable resource requirements for sandboxes created from this workload. + Resources *SandboxResources `protobuf:"bytes,3,opt,name=resources,proto3" json:"resources,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *SandboxCondition) Reset() { - *x = SandboxCondition{} - mi := &file_openshell_proto_msgTypes[18] +func (x *SandboxWorkloadConfig) Reset() { + *x = SandboxWorkloadConfig{} + mi := &file_openshell_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SandboxCondition) String() string { +func (x *SandboxWorkloadConfig) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SandboxCondition) ProtoMessage() {} +func (*SandboxWorkloadConfig) ProtoMessage() {} -func (x *SandboxCondition) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[18] +func (x *SandboxWorkloadConfig) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1550,80 +1581,117 @@ func (x *SandboxCondition) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SandboxCondition.ProtoReflect.Descriptor instead. -func (*SandboxCondition) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{18} +// Deprecated: Use SandboxWorkloadConfig.ProtoReflect.Descriptor instead. +func (*SandboxWorkloadConfig) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{19} } -func (x *SandboxCondition) GetType() string { +func (x *SandboxWorkloadConfig) GetImage() string { if x != nil { - return x.Type + return x.Image } return "" } -func (x *SandboxCondition) GetStatus() string { +func (x *SandboxWorkloadConfig) GetEnvironment() map[string]string { if x != nil { - return x.Status + return x.Environment } - return "" + return nil } -func (x *SandboxCondition) GetReason() string { +func (x *SandboxWorkloadConfig) GetResources() *SandboxResources { if x != nil { - return x.Reason + return x.Resources } - return "" + return nil } -func (x *SandboxCondition) GetMessage() string { +type SandboxResources struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Portable CPU quantity, for example "500m" or "2". + Cpu string `protobuf:"bytes,1,opt,name=cpu,proto3" json:"cpu,omitempty"` + // Portable memory quantity, for example "512Mi" or "2Gi". + Memory string `protobuf:"bytes,2,opt,name=memory,proto3" json:"memory,omitempty"` + // Optional number of GPUs requested. + GpuCount *uint32 `protobuf:"varint,3,opt,name=gpu_count,json=gpuCount,proto3,oneof" json:"gpu_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxResources) Reset() { + *x = SandboxResources{} + mi := &file_openshell_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxResources) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxResources) ProtoMessage() {} + +func (x *SandboxResources) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[20] if x != nil { - return x.Message + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxResources.ProtoReflect.Descriptor instead. +func (*SandboxResources) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{20} +} + +func (x *SandboxResources) GetCpu() string { + if x != nil { + return x.Cpu } return "" } -func (x *SandboxCondition) GetLastTransitionTime() string { +func (x *SandboxResources) GetMemory() string { if x != nil { - return x.LastTransitionTime + return x.Memory } return "" } -// Public platform event exposed on the sandbox watch stream. -type PlatformEvent struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Event timestamp in milliseconds since epoch. - TimestampMs int64 `protobuf:"varint,1,opt,name=timestamp_ms,json=timestampMs,proto3" json:"timestamp_ms,omitempty"` - // Event source (e.g. "kubernetes", "docker", "process"). - Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` - // Event type/severity (e.g. "Normal", "Warning"). - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` - // Short reason code (e.g. "Started", "Pulled", "Failed"). - Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` - // Human-readable event message. - Message string `protobuf:"bytes,5,opt,name=message,proto3" json:"message,omitempty"` - // Optional metadata as key-value pairs. - Metadata map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` +func (x *SandboxResources) GetGpuCount() uint32 { + if x != nil && x.GpuCount != nil { + return *x.GpuCount + } + return 0 +} + +type SandboxServiceLevel struct { + state protoimpl.MessageState `protogen:"open.v1"` + Startup *SandboxStartup `protobuf:"bytes,1,opt,name=startup,proto3" json:"startup,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *PlatformEvent) Reset() { - *x = PlatformEvent{} - mi := &file_openshell_proto_msgTypes[19] +func (x *SandboxServiceLevel) Reset() { + *x = SandboxServiceLevel{} + mi := &file_openshell_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *PlatformEvent) String() string { +func (x *SandboxServiceLevel) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PlatformEvent) ProtoMessage() {} +func (*SandboxServiceLevel) ProtoMessage() {} -func (x *PlatformEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[19] +func (x *SandboxServiceLevel) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1634,84 +1702,782 @@ func (x *PlatformEvent) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PlatformEvent.ProtoReflect.Descriptor instead. -func (*PlatformEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{19} +// Deprecated: Use SandboxServiceLevel.ProtoReflect.Descriptor instead. +func (*SandboxServiceLevel) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{21} } -func (x *PlatformEvent) GetTimestampMs() int64 { +func (x *SandboxServiceLevel) GetStartup() *SandboxStartup { if x != nil { - return x.TimestampMs + return x.Startup } - return 0 + return nil } -func (x *PlatformEvent) GetSource() string { - if x != nil { - return x.Source - } - return "" +type SandboxStartup struct { + state protoimpl.MessageState `protogen:"open.v1"` + ReadyWithin *durationpb.Duration `protobuf:"bytes,1,opt,name=ready_within,json=readyWithin,proto3" json:"ready_within,omitempty"` + MaxBurst uint32 `protobuf:"varint,2,opt,name=max_burst,json=maxBurst,proto3" json:"max_burst,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *PlatformEvent) GetType() string { +func (x *SandboxStartup) Reset() { + *x = SandboxStartup{} + mi := &file_openshell_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxStartup) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxStartup) ProtoMessage() {} + +func (x *SandboxStartup) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[22] if x != nil { - return x.Type + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return "" + return mi.MessageOf(x) } -func (x *PlatformEvent) GetReason() string { +// Deprecated: Use SandboxStartup.ProtoReflect.Descriptor instead. +func (*SandboxStartup) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{22} +} + +func (x *SandboxStartup) GetReadyWithin() *durationpb.Duration { if x != nil { - return x.Reason + return x.ReadyWithin } - return "" + return nil } -func (x *PlatformEvent) GetMessage() string { +func (x *SandboxStartup) GetMaxBurst() uint32 { if x != nil { - return x.Message + return x.MaxBurst } - return "" + return 0 } -func (x *PlatformEvent) GetMetadata() map[string]string { +type SandboxWorkloadTemplateProvenance struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + ResourceVersion string `protobuf:"bytes,2,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxWorkloadTemplateProvenance) Reset() { + *x = SandboxWorkloadTemplateProvenance{} + mi := &file_openshell_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxWorkloadTemplateProvenance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxWorkloadTemplateProvenance) ProtoMessage() {} + +func (x *SandboxWorkloadTemplateProvenance) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[23] + 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 SandboxWorkloadTemplateProvenance.ProtoReflect.Descriptor instead. +func (*SandboxWorkloadTemplateProvenance) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{23} +} + +func (x *SandboxWorkloadTemplateProvenance) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SandboxWorkloadTemplateProvenance) GetResourceVersion() string { + if x != nil { + return x.ResourceVersion + } + return "" +} + +// User-facing sandbox status derived by the gateway from compute-driver observations. +// +// Public status does not embed driver-only flags such as `deleting`. +type SandboxStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Compute-platform sandbox object name. + SandboxName string `protobuf:"bytes,1,opt,name=sandbox_name,json=sandboxName,proto3" json:"sandbox_name,omitempty"` + // Name of the agent pod or equivalent runtime instance. + AgentPod string `protobuf:"bytes,2,opt,name=agent_pod,json=agentPod,proto3" json:"agent_pod,omitempty"` + // File descriptor or endpoint for reaching the agent service, when available. + AgentFd string `protobuf:"bytes,3,opt,name=agent_fd,json=agentFd,proto3" json:"agent_fd,omitempty"` + // File descriptor or endpoint for reaching the sandbox service, when available. + SandboxFd string `protobuf:"bytes,4,opt,name=sandbox_fd,json=sandboxFd,proto3" json:"sandbox_fd,omitempty"` + // Latest user-facing readiness and lifecycle conditions. + Conditions []*SandboxCondition `protobuf:"bytes,5,rep,name=conditions,proto3" json:"conditions,omitempty"` + // Gateway-derived lifecycle summary. + Phase SandboxPhase `protobuf:"varint,6,opt,name=phase,proto3,enum=openshell.v1.SandboxPhase" json:"phase,omitempty"` + // Currently active policy version (updated when sandbox reports loaded). + CurrentPolicyVersion uint32 `protobuf:"varint,7,opt,name=current_policy_version,json=currentPolicyVersion,proto3" json:"current_policy_version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxStatus) Reset() { + *x = SandboxStatus{} + mi := &file_openshell_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxStatus) ProtoMessage() {} + +func (x *SandboxStatus) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[24] + 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 SandboxStatus.ProtoReflect.Descriptor instead. +func (*SandboxStatus) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{24} +} + +func (x *SandboxStatus) GetSandboxName() string { + if x != nil { + return x.SandboxName + } + return "" +} + +func (x *SandboxStatus) GetAgentPod() string { + if x != nil { + return x.AgentPod + } + return "" +} + +func (x *SandboxStatus) GetAgentFd() string { + if x != nil { + return x.AgentFd + } + return "" +} + +func (x *SandboxStatus) GetSandboxFd() string { + if x != nil { + return x.SandboxFd + } + return "" +} + +func (x *SandboxStatus) GetConditions() []*SandboxCondition { + if x != nil { + return x.Conditions + } + return nil +} + +func (x *SandboxStatus) GetPhase() SandboxPhase { + if x != nil { + return x.Phase + } + return SandboxPhase_SANDBOX_PHASE_UNSPECIFIED +} + +func (x *SandboxStatus) GetCurrentPolicyVersion() uint32 { + if x != nil { + return x.CurrentPolicyVersion + } + return 0 +} + +// User-facing sandbox condition derived from driver-native conditions. +type SandboxCondition struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Condition class, typically mirroring the underlying platform condition type. + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + // Condition status value such as `True`, `False`, or `Unknown`. + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + // Short machine-readable reason associated with the condition. + Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` + // Human-readable condition message. + Message string `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"` + // Timestamp reported by the underlying platform for the last transition. + LastTransitionTime string `protobuf:"bytes,5,opt,name=last_transition_time,json=lastTransitionTime,proto3" json:"last_transition_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxCondition) Reset() { + *x = SandboxCondition{} + mi := &file_openshell_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxCondition) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxCondition) ProtoMessage() {} + +func (x *SandboxCondition) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[25] + 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 SandboxCondition.ProtoReflect.Descriptor instead. +func (*SandboxCondition) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{25} +} + +func (x *SandboxCondition) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *SandboxCondition) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *SandboxCondition) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *SandboxCondition) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *SandboxCondition) GetLastTransitionTime() string { + if x != nil { + return x.LastTransitionTime + } + return "" +} + +// Public platform event exposed on the sandbox watch stream. +type PlatformEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Event timestamp in milliseconds since epoch. + TimestampMs int64 `protobuf:"varint,1,opt,name=timestamp_ms,json=timestampMs,proto3" json:"timestamp_ms,omitempty"` + // Event source (e.g. "kubernetes", "docker", "process"). + Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` + // Event type/severity (e.g. "Normal", "Warning"). + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + // Short reason code (e.g. "Started", "Pulled", "Failed"). + Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` + // Human-readable event message. + Message string `protobuf:"bytes,5,opt,name=message,proto3" json:"message,omitempty"` + // Optional metadata as key-value pairs. + Metadata map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PlatformEvent) Reset() { + *x = PlatformEvent{} + mi := &file_openshell_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PlatformEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlatformEvent) ProtoMessage() {} + +func (x *PlatformEvent) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[26] + 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 PlatformEvent.ProtoReflect.Descriptor instead. +func (*PlatformEvent) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{26} +} + +func (x *PlatformEvent) GetTimestampMs() int64 { + if x != nil { + return x.TimestampMs + } + return 0 +} + +func (x *PlatformEvent) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *PlatformEvent) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *PlatformEvent) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *PlatformEvent) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *PlatformEvent) GetMetadata() map[string]string { if x != nil { return x.Metadata } return nil } -// Create sandbox request. -type CreateSandboxRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Spec *SandboxSpec `protobuf:"bytes,1,opt,name=spec,proto3" json:"spec,omitempty"` - // Optional user-supplied sandbox name. When empty the server generates one. - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - // Optional labels for the sandbox (key-value metadata). - Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - // Optional annotations for the sandbox (non-selector metadata). - Annotations map[string]string `protobuf:"bytes,4,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - // Workspace for the sandbox. Empty defaults to "default". - Workspace string `protobuf:"bytes,5,opt,name=workspace,proto3" json:"workspace,omitempty"` +// Create sandbox request. +type CreateSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Spec *SandboxSpec `protobuf:"bytes,1,opt,name=spec,proto3" json:"spec,omitempty"` + // Optional user-supplied sandbox name. When empty the server generates one. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Optional labels for the sandbox (key-value metadata). + Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Optional annotations for the sandbox (non-selector metadata). + Annotations map[string]string `protobuf:"bytes,4,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Workspace for the sandbox. Empty defaults to "default". + Workspace string `protobuf:"bytes,5,opt,name=workspace,proto3" json:"workspace,omitempty"` + // Workspace-scoped SandboxWorkloadTemplate name to resolve at creation time. + WorkloadTemplateName string `protobuf:"bytes,6,opt,name=workload_template_name,json=workloadTemplateName,proto3" json:"workload_template_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateSandboxRequest) Reset() { + *x = CreateSandboxRequest{} + mi := &file_openshell_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSandboxRequest) ProtoMessage() {} + +func (x *CreateSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[27] + 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 CreateSandboxRequest.ProtoReflect.Descriptor instead. +func (*CreateSandboxRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{27} +} + +func (x *CreateSandboxRequest) GetSpec() *SandboxSpec { + if x != nil { + return x.Spec + } + return nil +} + +func (x *CreateSandboxRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CreateSandboxRequest) GetLabels() map[string]string { + if x != nil { + return x.Labels + } + return nil +} + +func (x *CreateSandboxRequest) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + +func (x *CreateSandboxRequest) GetWorkspace() string { + if x != nil { + return x.Workspace + } + return "" +} + +func (x *CreateSandboxRequest) GetWorkloadTemplateName() string { + if x != nil { + return x.WorkloadTemplateName + } + return "" +} + +type CreateSandboxTemplateRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Template *SandboxWorkloadTemplate `protobuf:"bytes,1,opt,name=template,proto3" json:"template,omitempty"` + // Workspace for the template. Empty defaults to "default". + Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateSandboxTemplateRequest) Reset() { + *x = CreateSandboxTemplateRequest{} + mi := &file_openshell_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateSandboxTemplateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSandboxTemplateRequest) ProtoMessage() {} + +func (x *CreateSandboxTemplateRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[28] + 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 CreateSandboxTemplateRequest.ProtoReflect.Descriptor instead. +func (*CreateSandboxTemplateRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{28} +} + +func (x *CreateSandboxTemplateRequest) GetTemplate() *SandboxWorkloadTemplate { + if x != nil { + return x.Template + } + return nil +} + +func (x *CreateSandboxTemplateRequest) GetWorkspace() string { + if x != nil { + return x.Workspace + } + return "" +} + +type GetSandboxTemplateRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Workspace scope. Empty defaults to "default". + Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSandboxTemplateRequest) Reset() { + *x = GetSandboxTemplateRequest{} + mi := &file_openshell_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSandboxTemplateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSandboxTemplateRequest) ProtoMessage() {} + +func (x *GetSandboxTemplateRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[29] + 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 GetSandboxTemplateRequest.ProtoReflect.Descriptor instead. +func (*GetSandboxTemplateRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{29} +} + +func (x *GetSandboxTemplateRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *GetSandboxTemplateRequest) GetWorkspace() string { + if x != nil { + return x.Workspace + } + return "" +} + +type ListSandboxTemplatesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Limit uint32 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` + Offset uint32 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` + // Workspace scope. Empty defaults to "default". + Workspace string `protobuf:"bytes,3,opt,name=workspace,proto3" json:"workspace,omitempty"` + // List across all workspaces. Mutually exclusive with workspace. + AllWorkspaces bool `protobuf:"varint,4,opt,name=all_workspaces,json=allWorkspaces,proto3" json:"all_workspaces,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListSandboxTemplatesRequest) Reset() { + *x = ListSandboxTemplatesRequest{} + mi := &file_openshell_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListSandboxTemplatesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSandboxTemplatesRequest) ProtoMessage() {} + +func (x *ListSandboxTemplatesRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[30] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListSandboxTemplatesRequest.ProtoReflect.Descriptor instead. +func (*ListSandboxTemplatesRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{30} +} + +func (x *ListSandboxTemplatesRequest) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *ListSandboxTemplatesRequest) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *ListSandboxTemplatesRequest) GetWorkspace() string { + if x != nil { + return x.Workspace + } + return "" +} + +func (x *ListSandboxTemplatesRequest) GetAllWorkspaces() bool { + if x != nil { + return x.AllWorkspaces + } + return false +} + +type DeleteSandboxTemplateRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Workspace scope. Empty defaults to "default". + Workspace string `protobuf:"bytes,2,opt,name=workspace,proto3" json:"workspace,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteSandboxTemplateRequest) Reset() { + *x = DeleteSandboxTemplateRequest{} + mi := &file_openshell_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteSandboxTemplateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSandboxTemplateRequest) ProtoMessage() {} + +func (x *DeleteSandboxTemplateRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[31] + 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 DeleteSandboxTemplateRequest.ProtoReflect.Descriptor instead. +func (*DeleteSandboxTemplateRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{31} +} + +func (x *DeleteSandboxTemplateRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DeleteSandboxTemplateRequest) GetWorkspace() string { + if x != nil { + return x.Workspace + } + return "" +} + +type SandboxTemplateResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Template *SandboxWorkloadTemplate `protobuf:"bytes,1,opt,name=template,proto3" json:"template,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxTemplateResponse) Reset() { + *x = SandboxTemplateResponse{} + mi := &file_openshell_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxTemplateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxTemplateResponse) ProtoMessage() {} + +func (x *SandboxTemplateResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[32] + 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 SandboxTemplateResponse.ProtoReflect.Descriptor instead. +func (*SandboxTemplateResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{32} +} + +func (x *SandboxTemplateResponse) GetTemplate() *SandboxWorkloadTemplate { + if x != nil { + return x.Template + } + return nil +} + +type ListSandboxTemplatesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Templates []*SandboxWorkloadTemplate `protobuf:"bytes,1,rep,name=templates,proto3" json:"templates,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *CreateSandboxRequest) Reset() { - *x = CreateSandboxRequest{} - mi := &file_openshell_proto_msgTypes[20] +func (x *ListSandboxTemplatesResponse) Reset() { + *x = ListSandboxTemplatesResponse{} + mi := &file_openshell_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *CreateSandboxRequest) String() string { +func (x *ListSandboxTemplatesResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CreateSandboxRequest) ProtoMessage() {} +func (*ListSandboxTemplatesResponse) ProtoMessage() {} -func (x *CreateSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[20] +func (x *ListSandboxTemplatesResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1722,44 +2488,60 @@ func (x *CreateSandboxRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CreateSandboxRequest.ProtoReflect.Descriptor instead. -func (*CreateSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{20} +// Deprecated: Use ListSandboxTemplatesResponse.ProtoReflect.Descriptor instead. +func (*ListSandboxTemplatesResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{33} } -func (x *CreateSandboxRequest) GetSpec() *SandboxSpec { +func (x *ListSandboxTemplatesResponse) GetTemplates() []*SandboxWorkloadTemplate { if x != nil { - return x.Spec + return x.Templates } return nil } -func (x *CreateSandboxRequest) GetName() string { - if x != nil { - return x.Name - } - return "" +type DeleteSandboxTemplateResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *CreateSandboxRequest) GetLabels() map[string]string { - if x != nil { - return x.Labels - } - return nil +func (x *DeleteSandboxTemplateResponse) Reset() { + *x = DeleteSandboxTemplateResponse{} + mi := &file_openshell_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *CreateSandboxRequest) GetAnnotations() map[string]string { +func (x *DeleteSandboxTemplateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSandboxTemplateResponse) ProtoMessage() {} + +func (x *DeleteSandboxTemplateResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[34] if x != nil { - return x.Annotations + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return nil + return mi.MessageOf(x) } -func (x *CreateSandboxRequest) GetWorkspace() string { +// Deprecated: Use DeleteSandboxTemplateResponse.ProtoReflect.Descriptor instead. +func (*DeleteSandboxTemplateResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{34} +} + +func (x *DeleteSandboxTemplateResponse) GetDeleted() bool { if x != nil { - return x.Workspace + return x.Deleted } - return "" + return false } // Get sandbox request. @@ -1775,7 +2557,7 @@ type GetSandboxRequest struct { func (x *GetSandboxRequest) Reset() { *x = GetSandboxRequest{} - mi := &file_openshell_proto_msgTypes[21] + mi := &file_openshell_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1787,7 +2569,7 @@ func (x *GetSandboxRequest) String() string { func (*GetSandboxRequest) ProtoMessage() {} func (x *GetSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[21] + mi := &file_openshell_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1800,7 +2582,7 @@ func (x *GetSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxRequest.ProtoReflect.Descriptor instead. func (*GetSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{21} + return file_openshell_proto_rawDescGZIP(), []int{35} } func (x *GetSandboxRequest) GetName() string { @@ -1834,7 +2616,7 @@ type ListSandboxesRequest struct { func (x *ListSandboxesRequest) Reset() { *x = ListSandboxesRequest{} - mi := &file_openshell_proto_msgTypes[22] + mi := &file_openshell_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1846,7 +2628,7 @@ func (x *ListSandboxesRequest) String() string { func (*ListSandboxesRequest) ProtoMessage() {} func (x *ListSandboxesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[22] + mi := &file_openshell_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1859,7 +2641,7 @@ func (x *ListSandboxesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{22} + return file_openshell_proto_rawDescGZIP(), []int{36} } func (x *ListSandboxesRequest) GetLimit() uint32 { @@ -1910,7 +2692,7 @@ type ListSandboxProvidersRequest struct { func (x *ListSandboxProvidersRequest) Reset() { *x = ListSandboxProvidersRequest{} - mi := &file_openshell_proto_msgTypes[23] + mi := &file_openshell_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1922,7 +2704,7 @@ func (x *ListSandboxProvidersRequest) String() string { func (*ListSandboxProvidersRequest) ProtoMessage() {} func (x *ListSandboxProvidersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[23] + mi := &file_openshell_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1935,7 +2717,7 @@ func (x *ListSandboxProvidersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxProvidersRequest.ProtoReflect.Descriptor instead. func (*ListSandboxProvidersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{23} + return file_openshell_proto_rawDescGZIP(), []int{37} } func (x *ListSandboxProvidersRequest) GetSandboxName() string { @@ -1972,7 +2754,7 @@ type AttachSandboxProviderRequest struct { func (x *AttachSandboxProviderRequest) Reset() { *x = AttachSandboxProviderRequest{} - mi := &file_openshell_proto_msgTypes[24] + mi := &file_openshell_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1984,7 +2766,7 @@ func (x *AttachSandboxProviderRequest) String() string { func (*AttachSandboxProviderRequest) ProtoMessage() {} func (x *AttachSandboxProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[24] + mi := &file_openshell_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1997,7 +2779,7 @@ func (x *AttachSandboxProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachSandboxProviderRequest.ProtoReflect.Descriptor instead. func (*AttachSandboxProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{24} + return file_openshell_proto_rawDescGZIP(), []int{38} } func (x *AttachSandboxProviderRequest) GetSandboxName() string { @@ -2048,7 +2830,7 @@ type DetachSandboxProviderRequest struct { func (x *DetachSandboxProviderRequest) Reset() { *x = DetachSandboxProviderRequest{} - mi := &file_openshell_proto_msgTypes[25] + mi := &file_openshell_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2060,7 +2842,7 @@ func (x *DetachSandboxProviderRequest) String() string { func (*DetachSandboxProviderRequest) ProtoMessage() {} func (x *DetachSandboxProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[25] + mi := &file_openshell_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2073,7 +2855,7 @@ func (x *DetachSandboxProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachSandboxProviderRequest.ProtoReflect.Descriptor instead. func (*DetachSandboxProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{25} + return file_openshell_proto_rawDescGZIP(), []int{39} } func (x *DetachSandboxProviderRequest) GetSandboxName() string { @@ -2117,7 +2899,7 @@ type DeleteSandboxRequest struct { func (x *DeleteSandboxRequest) Reset() { *x = DeleteSandboxRequest{} - mi := &file_openshell_proto_msgTypes[26] + mi := &file_openshell_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2129,7 +2911,7 @@ func (x *DeleteSandboxRequest) String() string { func (*DeleteSandboxRequest) ProtoMessage() {} func (x *DeleteSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[26] + mi := &file_openshell_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2142,7 +2924,7 @@ func (x *DeleteSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxRequest.ProtoReflect.Descriptor instead. func (*DeleteSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{26} + return file_openshell_proto_rawDescGZIP(), []int{40} } func (x *DeleteSandboxRequest) GetName() string { @@ -2172,7 +2954,7 @@ type StopSandboxRequest struct { func (x *StopSandboxRequest) Reset() { *x = StopSandboxRequest{} - mi := &file_openshell_proto_msgTypes[27] + mi := &file_openshell_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2184,7 +2966,7 @@ func (x *StopSandboxRequest) String() string { func (*StopSandboxRequest) ProtoMessage() {} func (x *StopSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[27] + mi := &file_openshell_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2197,7 +2979,7 @@ func (x *StopSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StopSandboxRequest.ProtoReflect.Descriptor instead. func (*StopSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{27} + return file_openshell_proto_rawDescGZIP(), []int{41} } func (x *StopSandboxRequest) GetName() string { @@ -2227,7 +3009,7 @@ type StartSandboxRequest struct { func (x *StartSandboxRequest) Reset() { *x = StartSandboxRequest{} - mi := &file_openshell_proto_msgTypes[28] + mi := &file_openshell_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2239,7 +3021,7 @@ func (x *StartSandboxRequest) String() string { func (*StartSandboxRequest) ProtoMessage() {} func (x *StartSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[28] + mi := &file_openshell_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2252,7 +3034,7 @@ func (x *StartSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartSandboxRequest.ProtoReflect.Descriptor instead. func (*StartSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{28} + return file_openshell_proto_rawDescGZIP(), []int{42} } func (x *StartSandboxRequest) GetName() string { @@ -2279,7 +3061,7 @@ type SandboxResponse struct { func (x *SandboxResponse) Reset() { *x = SandboxResponse{} - mi := &file_openshell_proto_msgTypes[29] + mi := &file_openshell_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2291,7 +3073,7 @@ func (x *SandboxResponse) String() string { func (*SandboxResponse) ProtoMessage() {} func (x *SandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[29] + mi := &file_openshell_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2304,7 +3086,7 @@ func (x *SandboxResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxResponse.ProtoReflect.Descriptor instead. func (*SandboxResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{29} + return file_openshell_proto_rawDescGZIP(), []int{43} } func (x *SandboxResponse) GetSandbox() *Sandbox { @@ -2324,7 +3106,7 @@ type ListSandboxesResponse struct { func (x *ListSandboxesResponse) Reset() { *x = ListSandboxesResponse{} - mi := &file_openshell_proto_msgTypes[30] + mi := &file_openshell_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2336,7 +3118,7 @@ func (x *ListSandboxesResponse) String() string { func (*ListSandboxesResponse) ProtoMessage() {} func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[30] + mi := &file_openshell_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2349,7 +3131,7 @@ func (x *ListSandboxesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{30} + return file_openshell_proto_rawDescGZIP(), []int{44} } func (x *ListSandboxesResponse) GetSandboxes() []*Sandbox { @@ -2369,7 +3151,7 @@ type ListSandboxProvidersResponse struct { func (x *ListSandboxProvidersResponse) Reset() { *x = ListSandboxProvidersResponse{} - mi := &file_openshell_proto_msgTypes[31] + mi := &file_openshell_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2381,7 +3163,7 @@ func (x *ListSandboxProvidersResponse) String() string { func (*ListSandboxProvidersResponse) ProtoMessage() {} func (x *ListSandboxProvidersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[31] + mi := &file_openshell_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2394,7 +3176,7 @@ func (x *ListSandboxProvidersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxProvidersResponse.ProtoReflect.Descriptor instead. func (*ListSandboxProvidersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{31} + return file_openshell_proto_rawDescGZIP(), []int{45} } func (x *ListSandboxProvidersResponse) GetProviders() []*datamodelv1.Provider { @@ -2416,7 +3198,7 @@ type AttachSandboxProviderResponse struct { func (x *AttachSandboxProviderResponse) Reset() { *x = AttachSandboxProviderResponse{} - mi := &file_openshell_proto_msgTypes[32] + mi := &file_openshell_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2428,7 +3210,7 @@ func (x *AttachSandboxProviderResponse) String() string { func (*AttachSandboxProviderResponse) ProtoMessage() {} func (x *AttachSandboxProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[32] + mi := &file_openshell_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2441,7 +3223,7 @@ func (x *AttachSandboxProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachSandboxProviderResponse.ProtoReflect.Descriptor instead. func (*AttachSandboxProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{32} + return file_openshell_proto_rawDescGZIP(), []int{46} } func (x *AttachSandboxProviderResponse) GetSandbox() *Sandbox { @@ -2470,7 +3252,7 @@ type DetachSandboxProviderResponse struct { func (x *DetachSandboxProviderResponse) Reset() { *x = DetachSandboxProviderResponse{} - mi := &file_openshell_proto_msgTypes[33] + mi := &file_openshell_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2482,7 +3264,7 @@ func (x *DetachSandboxProviderResponse) String() string { func (*DetachSandboxProviderResponse) ProtoMessage() {} func (x *DetachSandboxProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[33] + mi := &file_openshell_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2495,7 +3277,7 @@ func (x *DetachSandboxProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachSandboxProviderResponse.ProtoReflect.Descriptor instead. func (*DetachSandboxProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{33} + return file_openshell_proto_rawDescGZIP(), []int{47} } func (x *DetachSandboxProviderResponse) GetSandbox() *Sandbox { @@ -2522,7 +3304,7 @@ type DeleteSandboxResponse struct { func (x *DeleteSandboxResponse) Reset() { *x = DeleteSandboxResponse{} - mi := &file_openshell_proto_msgTypes[34] + mi := &file_openshell_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2534,7 +3316,7 @@ func (x *DeleteSandboxResponse) String() string { func (*DeleteSandboxResponse) ProtoMessage() {} func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[34] + mi := &file_openshell_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2547,7 +3329,7 @@ func (x *DeleteSandboxResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSandboxResponse.ProtoReflect.Descriptor instead. func (*DeleteSandboxResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{34} + return file_openshell_proto_rawDescGZIP(), []int{48} } func (x *DeleteSandboxResponse) GetDeleted() bool { @@ -2568,7 +3350,7 @@ type CreateSshSessionRequest struct { func (x *CreateSshSessionRequest) Reset() { *x = CreateSshSessionRequest{} - mi := &file_openshell_proto_msgTypes[35] + mi := &file_openshell_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2580,7 +3362,7 @@ func (x *CreateSshSessionRequest) String() string { func (*CreateSshSessionRequest) ProtoMessage() {} func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[35] + mi := &file_openshell_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2593,7 +3375,7 @@ func (x *CreateSshSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSshSessionRequest.ProtoReflect.Descriptor instead. func (*CreateSshSessionRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{35} + return file_openshell_proto_rawDescGZIP(), []int{49} } func (x *CreateSshSessionRequest) GetSandboxId() string { @@ -2636,7 +3418,7 @@ type CreateSshSessionResponse struct { func (x *CreateSshSessionResponse) Reset() { *x = CreateSshSessionResponse{} - mi := &file_openshell_proto_msgTypes[36] + mi := &file_openshell_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2648,7 +3430,7 @@ func (x *CreateSshSessionResponse) String() string { func (*CreateSshSessionResponse) ProtoMessage() {} func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[36] + mi := &file_openshell_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2661,7 +3443,7 @@ func (x *CreateSshSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSshSessionResponse.ProtoReflect.Descriptor instead. func (*CreateSshSessionResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{36} + return file_openshell_proto_rawDescGZIP(), []int{50} } func (x *CreateSshSessionResponse) GetSandboxId() string { @@ -2732,7 +3514,7 @@ type ExposeServiceRequest struct { func (x *ExposeServiceRequest) Reset() { *x = ExposeServiceRequest{} - mi := &file_openshell_proto_msgTypes[37] + mi := &file_openshell_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2744,7 +3526,7 @@ func (x *ExposeServiceRequest) String() string { func (*ExposeServiceRequest) ProtoMessage() {} func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[37] + mi := &file_openshell_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2757,7 +3539,7 @@ func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExposeServiceRequest.ProtoReflect.Descriptor instead. func (*ExposeServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{37} + return file_openshell_proto_rawDescGZIP(), []int{51} } func (x *ExposeServiceRequest) GetSandbox() string { @@ -2810,7 +3592,7 @@ type GetServiceRequest struct { func (x *GetServiceRequest) Reset() { *x = GetServiceRequest{} - mi := &file_openshell_proto_msgTypes[38] + mi := &file_openshell_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2822,7 +3604,7 @@ func (x *GetServiceRequest) String() string { func (*GetServiceRequest) ProtoMessage() {} func (x *GetServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[38] + mi := &file_openshell_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2835,7 +3617,7 @@ func (x *GetServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetServiceRequest.ProtoReflect.Descriptor instead. func (*GetServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{38} + return file_openshell_proto_rawDescGZIP(), []int{52} } func (x *GetServiceRequest) GetSandbox() string { @@ -2878,7 +3660,7 @@ type ListServicesRequest struct { func (x *ListServicesRequest) Reset() { *x = ListServicesRequest{} - mi := &file_openshell_proto_msgTypes[39] + mi := &file_openshell_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2890,7 +3672,7 @@ func (x *ListServicesRequest) String() string { func (*ListServicesRequest) ProtoMessage() {} func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[39] + mi := &file_openshell_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2903,7 +3685,7 @@ func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesRequest.ProtoReflect.Descriptor instead. func (*ListServicesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{39} + return file_openshell_proto_rawDescGZIP(), []int{53} } func (x *ListServicesRequest) GetSandbox() string { @@ -2951,7 +3733,7 @@ type ListServicesResponse struct { func (x *ListServicesResponse) Reset() { *x = ListServicesResponse{} - mi := &file_openshell_proto_msgTypes[40] + mi := &file_openshell_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2963,7 +3745,7 @@ func (x *ListServicesResponse) String() string { func (*ListServicesResponse) ProtoMessage() {} func (x *ListServicesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[40] + mi := &file_openshell_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2976,7 +3758,7 @@ func (x *ListServicesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesResponse.ProtoReflect.Descriptor instead. func (*ListServicesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{40} + return file_openshell_proto_rawDescGZIP(), []int{54} } func (x *ListServicesResponse) GetServices() []*ServiceEndpointResponse { @@ -3001,7 +3783,7 @@ type DeleteServiceRequest struct { func (x *DeleteServiceRequest) Reset() { *x = DeleteServiceRequest{} - mi := &file_openshell_proto_msgTypes[41] + mi := &file_openshell_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3013,7 +3795,7 @@ func (x *DeleteServiceRequest) String() string { func (*DeleteServiceRequest) ProtoMessage() {} func (x *DeleteServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[41] + mi := &file_openshell_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3026,7 +3808,7 @@ func (x *DeleteServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteServiceRequest.ProtoReflect.Descriptor instead. func (*DeleteServiceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{41} + return file_openshell_proto_rawDescGZIP(), []int{55} } func (x *DeleteServiceRequest) GetSandbox() string { @@ -3061,7 +3843,7 @@ type DeleteServiceResponse struct { func (x *DeleteServiceResponse) Reset() { *x = DeleteServiceResponse{} - mi := &file_openshell_proto_msgTypes[42] + mi := &file_openshell_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3073,7 +3855,7 @@ func (x *DeleteServiceResponse) String() string { func (*DeleteServiceResponse) ProtoMessage() {} func (x *DeleteServiceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[42] + mi := &file_openshell_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3086,7 +3868,7 @@ func (x *DeleteServiceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteServiceResponse.ProtoReflect.Descriptor instead. func (*DeleteServiceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{42} + return file_openshell_proto_rawDescGZIP(), []int{56} } func (x *DeleteServiceResponse) GetDeleted() bool { @@ -3117,7 +3899,7 @@ type ServiceEndpoint struct { func (x *ServiceEndpoint) Reset() { *x = ServiceEndpoint{} - mi := &file_openshell_proto_msgTypes[43] + mi := &file_openshell_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3129,7 +3911,7 @@ func (x *ServiceEndpoint) String() string { func (*ServiceEndpoint) ProtoMessage() {} func (x *ServiceEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[43] + mi := &file_openshell_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3142,7 +3924,7 @@ func (x *ServiceEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceEndpoint.ProtoReflect.Descriptor instead. func (*ServiceEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{43} + return file_openshell_proto_rawDescGZIP(), []int{57} } func (x *ServiceEndpoint) GetMetadata() *datamodelv1.ObjectMeta { @@ -3198,7 +3980,7 @@ type ServiceEndpointResponse struct { func (x *ServiceEndpointResponse) Reset() { *x = ServiceEndpointResponse{} - mi := &file_openshell_proto_msgTypes[44] + mi := &file_openshell_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3210,7 +3992,7 @@ func (x *ServiceEndpointResponse) String() string { func (*ServiceEndpointResponse) ProtoMessage() {} func (x *ServiceEndpointResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[44] + mi := &file_openshell_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3223,7 +4005,7 @@ func (x *ServiceEndpointResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceEndpointResponse.ProtoReflect.Descriptor instead. func (*ServiceEndpointResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{44} + return file_openshell_proto_rawDescGZIP(), []int{58} } func (x *ServiceEndpointResponse) GetEndpoint() *ServiceEndpoint { @@ -3251,7 +4033,7 @@ type RevokeSshSessionRequest struct { func (x *RevokeSshSessionRequest) Reset() { *x = RevokeSshSessionRequest{} - mi := &file_openshell_proto_msgTypes[45] + mi := &file_openshell_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3263,7 +4045,7 @@ func (x *RevokeSshSessionRequest) String() string { func (*RevokeSshSessionRequest) ProtoMessage() {} func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[45] + mi := &file_openshell_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3276,7 +4058,7 @@ func (x *RevokeSshSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RevokeSshSessionRequest.ProtoReflect.Descriptor instead. func (*RevokeSshSessionRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{45} + return file_openshell_proto_rawDescGZIP(), []int{59} } func (x *RevokeSshSessionRequest) GetToken() string { @@ -3297,7 +4079,7 @@ type RevokeSshSessionResponse struct { func (x *RevokeSshSessionResponse) Reset() { *x = RevokeSshSessionResponse{} - mi := &file_openshell_proto_msgTypes[46] + mi := &file_openshell_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3309,7 +4091,7 @@ func (x *RevokeSshSessionResponse) String() string { func (*RevokeSshSessionResponse) ProtoMessage() {} func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[46] + mi := &file_openshell_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3322,7 +4104,7 @@ func (x *RevokeSshSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RevokeSshSessionResponse.ProtoReflect.Descriptor instead. func (*RevokeSshSessionResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{46} + return file_openshell_proto_rawDescGZIP(), []int{60} } func (x *RevokeSshSessionResponse) GetRevoked() bool { @@ -3359,7 +4141,7 @@ type ExecSandboxRequest struct { func (x *ExecSandboxRequest) Reset() { *x = ExecSandboxRequest{} - mi := &file_openshell_proto_msgTypes[47] + mi := &file_openshell_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3371,7 +4153,7 @@ func (x *ExecSandboxRequest) String() string { func (*ExecSandboxRequest) ProtoMessage() {} func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[47] + mi := &file_openshell_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3384,7 +4166,7 @@ func (x *ExecSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxRequest.ProtoReflect.Descriptor instead. func (*ExecSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{47} + return file_openshell_proto_rawDescGZIP(), []int{61} } func (x *ExecSandboxRequest) GetSandboxId() string { @@ -3460,7 +4242,7 @@ type ExecSandboxStdout struct { func (x *ExecSandboxStdout) Reset() { *x = ExecSandboxStdout{} - mi := &file_openshell_proto_msgTypes[48] + mi := &file_openshell_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3472,7 +4254,7 @@ func (x *ExecSandboxStdout) String() string { func (*ExecSandboxStdout) ProtoMessage() {} func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[48] + mi := &file_openshell_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3485,7 +4267,7 @@ func (x *ExecSandboxStdout) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxStdout.ProtoReflect.Descriptor instead. func (*ExecSandboxStdout) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{48} + return file_openshell_proto_rawDescGZIP(), []int{62} } func (x *ExecSandboxStdout) GetData() []byte { @@ -3505,7 +4287,7 @@ type ExecSandboxStderr struct { func (x *ExecSandboxStderr) Reset() { *x = ExecSandboxStderr{} - mi := &file_openshell_proto_msgTypes[49] + mi := &file_openshell_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3517,7 +4299,7 @@ func (x *ExecSandboxStderr) String() string { func (*ExecSandboxStderr) ProtoMessage() {} func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[49] + mi := &file_openshell_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3530,7 +4312,7 @@ func (x *ExecSandboxStderr) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxStderr.ProtoReflect.Descriptor instead. func (*ExecSandboxStderr) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{49} + return file_openshell_proto_rawDescGZIP(), []int{63} } func (x *ExecSandboxStderr) GetData() []byte { @@ -3550,7 +4332,7 @@ type ExecSandboxExit struct { func (x *ExecSandboxExit) Reset() { *x = ExecSandboxExit{} - mi := &file_openshell_proto_msgTypes[50] + mi := &file_openshell_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3562,7 +4344,7 @@ func (x *ExecSandboxExit) String() string { func (*ExecSandboxExit) ProtoMessage() {} func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[50] + mi := &file_openshell_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3575,7 +4357,7 @@ func (x *ExecSandboxExit) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxExit.ProtoReflect.Descriptor instead. func (*ExecSandboxExit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{50} + return file_openshell_proto_rawDescGZIP(), []int{64} } func (x *ExecSandboxExit) GetExitCode() int32 { @@ -3600,7 +4382,7 @@ type ExecSandboxEvent struct { func (x *ExecSandboxEvent) Reset() { *x = ExecSandboxEvent{} - mi := &file_openshell_proto_msgTypes[51] + mi := &file_openshell_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3612,7 +4394,7 @@ func (x *ExecSandboxEvent) String() string { func (*ExecSandboxEvent) ProtoMessage() {} func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[51] + mi := &file_openshell_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3625,7 +4407,7 @@ func (x *ExecSandboxEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxEvent.ProtoReflect.Descriptor instead. func (*ExecSandboxEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{51} + return file_openshell_proto_rawDescGZIP(), []int{65} } func (x *ExecSandboxEvent) GetPayload() isExecSandboxEvent_Payload { @@ -3707,7 +4489,7 @@ type TcpForwardInit struct { func (x *TcpForwardInit) Reset() { *x = TcpForwardInit{} - mi := &file_openshell_proto_msgTypes[52] + mi := &file_openshell_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3719,7 +4501,7 @@ func (x *TcpForwardInit) String() string { func (*TcpForwardInit) ProtoMessage() {} func (x *TcpForwardInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[52] + mi := &file_openshell_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3732,7 +4514,7 @@ func (x *TcpForwardInit) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpForwardInit.ProtoReflect.Descriptor instead. func (*TcpForwardInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{52} + return file_openshell_proto_rawDescGZIP(), []int{66} } func (x *TcpForwardInit) GetSandboxId() string { @@ -3811,7 +4593,7 @@ type TcpForwardFrame struct { func (x *TcpForwardFrame) Reset() { *x = TcpForwardFrame{} - mi := &file_openshell_proto_msgTypes[53] + mi := &file_openshell_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3823,7 +4605,7 @@ func (x *TcpForwardFrame) String() string { func (*TcpForwardFrame) ProtoMessage() {} func (x *TcpForwardFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[53] + mi := &file_openshell_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3836,7 +4618,7 @@ func (x *TcpForwardFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpForwardFrame.ProtoReflect.Descriptor instead. func (*TcpForwardFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{53} + return file_openshell_proto_rawDescGZIP(), []int{67} } func (x *TcpForwardFrame) GetPayload() isTcpForwardFrame_Payload { @@ -3895,7 +4677,7 @@ type ExecSandboxInput struct { func (x *ExecSandboxInput) Reset() { *x = ExecSandboxInput{} - mi := &file_openshell_proto_msgTypes[54] + mi := &file_openshell_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3907,7 +4689,7 @@ func (x *ExecSandboxInput) String() string { func (*ExecSandboxInput) ProtoMessage() {} func (x *ExecSandboxInput) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[54] + mi := &file_openshell_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3920,7 +4702,7 @@ func (x *ExecSandboxInput) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxInput.ProtoReflect.Descriptor instead. func (*ExecSandboxInput) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{54} + return file_openshell_proto_rawDescGZIP(), []int{68} } func (x *ExecSandboxInput) GetPayload() isExecSandboxInput_Payload { @@ -3993,7 +4775,7 @@ type ExecSandboxWindowResize struct { func (x *ExecSandboxWindowResize) Reset() { *x = ExecSandboxWindowResize{} - mi := &file_openshell_proto_msgTypes[55] + mi := &file_openshell_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4005,7 +4787,7 @@ func (x *ExecSandboxWindowResize) String() string { func (*ExecSandboxWindowResize) ProtoMessage() {} func (x *ExecSandboxWindowResize) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[55] + mi := &file_openshell_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4018,7 +4800,7 @@ func (x *ExecSandboxWindowResize) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecSandboxWindowResize.ProtoReflect.Descriptor instead. func (*ExecSandboxWindowResize) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{55} + return file_openshell_proto_rawDescGZIP(), []int{69} } func (x *ExecSandboxWindowResize) GetCols() uint32 { @@ -4055,7 +4837,7 @@ type SshSession struct { func (x *SshSession) Reset() { *x = SshSession{} - mi := &file_openshell_proto_msgTypes[56] + mi := &file_openshell_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4067,7 +4849,7 @@ func (x *SshSession) String() string { func (*SshSession) ProtoMessage() {} func (x *SshSession) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[56] + mi := &file_openshell_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4080,7 +4862,7 @@ func (x *SshSession) ProtoReflect() protoreflect.Message { // Deprecated: Use SshSession.ProtoReflect.Descriptor instead. func (*SshSession) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{56} + return file_openshell_proto_rawDescGZIP(), []int{70} } func (x *SshSession) GetMetadata() *datamodelv1.ObjectMeta { @@ -4148,7 +4930,7 @@ type WatchSandboxRequest struct { func (x *WatchSandboxRequest) Reset() { *x = WatchSandboxRequest{} - mi := &file_openshell_proto_msgTypes[57] + mi := &file_openshell_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4160,7 +4942,7 @@ func (x *WatchSandboxRequest) String() string { func (*WatchSandboxRequest) ProtoMessage() {} func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[57] + mi := &file_openshell_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4173,7 +4955,7 @@ func (x *WatchSandboxRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WatchSandboxRequest.ProtoReflect.Descriptor instead. func (*WatchSandboxRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{57} + return file_openshell_proto_rawDescGZIP(), []int{71} } func (x *WatchSandboxRequest) GetId() string { @@ -4263,7 +5045,7 @@ type SandboxStreamEvent struct { func (x *SandboxStreamEvent) Reset() { *x = SandboxStreamEvent{} - mi := &file_openshell_proto_msgTypes[58] + mi := &file_openshell_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4275,7 +5057,7 @@ func (x *SandboxStreamEvent) String() string { func (*SandboxStreamEvent) ProtoMessage() {} func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[58] + mi := &file_openshell_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4288,7 +5070,7 @@ func (x *SandboxStreamEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStreamEvent.ProtoReflect.Descriptor instead. func (*SandboxStreamEvent) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{58} + return file_openshell_proto_rawDescGZIP(), []int{72} } func (x *SandboxStreamEvent) GetPayload() isSandboxStreamEvent_Payload { @@ -4401,7 +5183,7 @@ type SandboxLogLine struct { func (x *SandboxLogLine) Reset() { *x = SandboxLogLine{} - mi := &file_openshell_proto_msgTypes[59] + mi := &file_openshell_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4413,7 +5195,7 @@ func (x *SandboxLogLine) String() string { func (*SandboxLogLine) ProtoMessage() {} func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[59] + mi := &file_openshell_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4426,7 +5208,7 @@ func (x *SandboxLogLine) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxLogLine.ProtoReflect.Descriptor instead. func (*SandboxLogLine) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{59} + return file_openshell_proto_rawDescGZIP(), []int{73} } func (x *SandboxLogLine) GetSandboxId() string { @@ -4487,7 +5269,7 @@ type SandboxStreamWarning struct { func (x *SandboxStreamWarning) Reset() { *x = SandboxStreamWarning{} - mi := &file_openshell_proto_msgTypes[60] + mi := &file_openshell_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4499,7 +5281,7 @@ func (x *SandboxStreamWarning) String() string { func (*SandboxStreamWarning) ProtoMessage() {} func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[60] + mi := &file_openshell_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4512,7 +5294,7 @@ func (x *SandboxStreamWarning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStreamWarning.ProtoReflect.Descriptor instead. func (*SandboxStreamWarning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{60} + return file_openshell_proto_rawDescGZIP(), []int{74} } func (x *SandboxStreamWarning) GetMessage() string { @@ -4534,7 +5316,7 @@ type CreateProviderRequest struct { func (x *CreateProviderRequest) Reset() { *x = CreateProviderRequest{} - mi := &file_openshell_proto_msgTypes[61] + mi := &file_openshell_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4546,7 +5328,7 @@ func (x *CreateProviderRequest) String() string { func (*CreateProviderRequest) ProtoMessage() {} func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[61] + mi := &file_openshell_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4559,7 +5341,7 @@ func (x *CreateProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateProviderRequest.ProtoReflect.Descriptor instead. func (*CreateProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{61} + return file_openshell_proto_rawDescGZIP(), []int{75} } func (x *CreateProviderRequest) GetProvider() *datamodelv1.Provider { @@ -4588,7 +5370,7 @@ type GetProviderRequest struct { func (x *GetProviderRequest) Reset() { *x = GetProviderRequest{} - mi := &file_openshell_proto_msgTypes[62] + mi := &file_openshell_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4600,7 +5382,7 @@ func (x *GetProviderRequest) String() string { func (*GetProviderRequest) ProtoMessage() {} func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[62] + mi := &file_openshell_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4613,7 +5395,7 @@ func (x *GetProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRequest.ProtoReflect.Descriptor instead. func (*GetProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{62} + return file_openshell_proto_rawDescGZIP(), []int{76} } func (x *GetProviderRequest) GetName() string { @@ -4645,7 +5427,7 @@ type ListProvidersRequest struct { func (x *ListProvidersRequest) Reset() { *x = ListProvidersRequest{} - mi := &file_openshell_proto_msgTypes[63] + mi := &file_openshell_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4657,7 +5439,7 @@ func (x *ListProvidersRequest) String() string { func (*ListProvidersRequest) ProtoMessage() {} func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[63] + mi := &file_openshell_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4670,7 +5452,7 @@ func (x *ListProvidersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProvidersRequest.ProtoReflect.Descriptor instead. func (*ListProvidersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{63} + return file_openshell_proto_rawDescGZIP(), []int{77} } func (x *ListProvidersRequest) GetLimit() uint32 { @@ -4716,7 +5498,7 @@ type UpdateProviderRequest struct { func (x *UpdateProviderRequest) Reset() { *x = UpdateProviderRequest{} - mi := &file_openshell_proto_msgTypes[64] + mi := &file_openshell_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4728,7 +5510,7 @@ func (x *UpdateProviderRequest) String() string { func (*UpdateProviderRequest) ProtoMessage() {} func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[64] + mi := &file_openshell_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4741,7 +5523,7 @@ func (x *UpdateProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{64} + return file_openshell_proto_rawDescGZIP(), []int{78} } func (x *UpdateProviderRequest) GetProvider() *datamodelv1.Provider { @@ -4777,7 +5559,7 @@ type DeleteProviderRequest struct { func (x *DeleteProviderRequest) Reset() { *x = DeleteProviderRequest{} - mi := &file_openshell_proto_msgTypes[65] + mi := &file_openshell_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4789,7 +5571,7 @@ func (x *DeleteProviderRequest) String() string { func (*DeleteProviderRequest) ProtoMessage() {} func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[65] + mi := &file_openshell_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4802,7 +5584,7 @@ func (x *DeleteProviderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{65} + return file_openshell_proto_rawDescGZIP(), []int{79} } func (x *DeleteProviderRequest) GetName() string { @@ -4829,7 +5611,7 @@ type ProviderResponse struct { func (x *ProviderResponse) Reset() { *x = ProviderResponse{} - mi := &file_openshell_proto_msgTypes[66] + mi := &file_openshell_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4841,7 +5623,7 @@ func (x *ProviderResponse) String() string { func (*ProviderResponse) ProtoMessage() {} func (x *ProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[66] + mi := &file_openshell_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4854,7 +5636,7 @@ func (x *ProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderResponse.ProtoReflect.Descriptor instead. func (*ProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{66} + return file_openshell_proto_rawDescGZIP(), []int{80} } func (x *ProviderResponse) GetProvider() *datamodelv1.Provider { @@ -4874,7 +5656,7 @@ type ListProvidersResponse struct { func (x *ListProvidersResponse) Reset() { *x = ListProvidersResponse{} - mi := &file_openshell_proto_msgTypes[67] + mi := &file_openshell_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4886,7 +5668,7 @@ func (x *ListProvidersResponse) String() string { func (*ListProvidersResponse) ProtoMessage() {} func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[67] + mi := &file_openshell_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4899,7 +5681,7 @@ func (x *ListProvidersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProvidersResponse.ProtoReflect.Descriptor instead. func (*ListProvidersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{67} + return file_openshell_proto_rawDescGZIP(), []int{81} } func (x *ListProvidersResponse) GetProviders() []*datamodelv1.Provider { @@ -4923,7 +5705,7 @@ type ListProviderProfilesRequest struct { func (x *ListProviderProfilesRequest) Reset() { *x = ListProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[68] + mi := &file_openshell_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4935,7 +5717,7 @@ func (x *ListProviderProfilesRequest) String() string { func (*ListProviderProfilesRequest) ProtoMessage() {} func (x *ListProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[68] + mi := &file_openshell_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4948,7 +5730,7 @@ func (x *ListProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ListProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{68} + return file_openshell_proto_rawDescGZIP(), []int{82} } func (x *ListProviderProfilesRequest) GetLimit() uint32 { @@ -4986,7 +5768,7 @@ type GetProviderProfileRequest struct { func (x *GetProviderProfileRequest) Reset() { *x = GetProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[69] + mi := &file_openshell_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4998,7 +5780,7 @@ func (x *GetProviderProfileRequest) String() string { func (*GetProviderProfileRequest) ProtoMessage() {} func (x *GetProviderProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[69] + mi := &file_openshell_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5011,7 +5793,7 @@ func (x *GetProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderProfileRequest.ProtoReflect.Descriptor instead. func (*GetProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{69} + return file_openshell_proto_rawDescGZIP(), []int{83} } func (x *GetProviderProfileRequest) GetId() string { @@ -5039,7 +5821,7 @@ type ProviderProfileImportItem struct { func (x *ProviderProfileImportItem) Reset() { *x = ProviderProfileImportItem{} - mi := &file_openshell_proto_msgTypes[70] + mi := &file_openshell_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5051,7 +5833,7 @@ func (x *ProviderProfileImportItem) String() string { func (*ProviderProfileImportItem) ProtoMessage() {} func (x *ProviderProfileImportItem) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[70] + mi := &file_openshell_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5064,7 +5846,7 @@ func (x *ProviderProfileImportItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileImportItem.ProtoReflect.Descriptor instead. func (*ProviderProfileImportItem) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{70} + return file_openshell_proto_rawDescGZIP(), []int{84} } func (x *ProviderProfileImportItem) GetProfile() *ProviderProfile { @@ -5095,7 +5877,7 @@ type ProviderProfileDiagnostic struct { func (x *ProviderProfileDiagnostic) Reset() { *x = ProviderProfileDiagnostic{} - mi := &file_openshell_proto_msgTypes[71] + mi := &file_openshell_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5107,7 +5889,7 @@ func (x *ProviderProfileDiagnostic) String() string { func (*ProviderProfileDiagnostic) ProtoMessage() {} func (x *ProviderProfileDiagnostic) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[71] + mi := &file_openshell_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5120,7 +5902,7 @@ func (x *ProviderProfileDiagnostic) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileDiagnostic.ProtoReflect.Descriptor instead. func (*ProviderProfileDiagnostic) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{71} + return file_openshell_proto_rawDescGZIP(), []int{85} } func (x *ProviderProfileDiagnostic) GetSource() string { @@ -5177,7 +5959,7 @@ type ProviderCredentialTokenGrantAudienceOverride struct { func (x *ProviderCredentialTokenGrantAudienceOverride) Reset() { *x = ProviderCredentialTokenGrantAudienceOverride{} - mi := &file_openshell_proto_msgTypes[72] + mi := &file_openshell_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5189,7 +5971,7 @@ func (x *ProviderCredentialTokenGrantAudienceOverride) String() string { func (*ProviderCredentialTokenGrantAudienceOverride) ProtoMessage() {} func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[72] + mi := &file_openshell_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5202,7 +5984,7 @@ func (x *ProviderCredentialTokenGrantAudienceOverride) ProtoReflect() protorefle // Deprecated: Use ProviderCredentialTokenGrantAudienceOverride.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrantAudienceOverride) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{72} + return file_openshell_proto_rawDescGZIP(), []int{86} } func (x *ProviderCredentialTokenGrantAudienceOverride) GetHost() string { @@ -5267,7 +6049,7 @@ type ProviderCredentialTokenGrant struct { func (x *ProviderCredentialTokenGrant) Reset() { *x = ProviderCredentialTokenGrant{} - mi := &file_openshell_proto_msgTypes[73] + mi := &file_openshell_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5279,7 +6061,7 @@ func (x *ProviderCredentialTokenGrant) String() string { func (*ProviderCredentialTokenGrant) ProtoMessage() {} func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[73] + mi := &file_openshell_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5292,7 +6074,7 @@ func (x *ProviderCredentialTokenGrant) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialTokenGrant.ProtoReflect.Descriptor instead. func (*ProviderCredentialTokenGrant) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{73} + return file_openshell_proto_rawDescGZIP(), []int{87} } func (x *ProviderCredentialTokenGrant) GetTokenEndpoint() string { @@ -5363,7 +6145,7 @@ type ProviderProfileCredential struct { func (x *ProviderProfileCredential) Reset() { *x = ProviderProfileCredential{} - mi := &file_openshell_proto_msgTypes[74] + mi := &file_openshell_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5375,7 +6157,7 @@ func (x *ProviderProfileCredential) String() string { func (*ProviderProfileCredential) ProtoMessage() {} func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[74] + mi := &file_openshell_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5388,7 +6170,7 @@ func (x *ProviderProfileCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileCredential.ProtoReflect.Descriptor instead. func (*ProviderProfileCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{74} + return file_openshell_proto_rawDescGZIP(), []int{88} } func (x *ProviderProfileCredential) GetName() string { @@ -5473,7 +6255,7 @@ type ProviderCredentialRefreshMaterial struct { func (x *ProviderCredentialRefreshMaterial) Reset() { *x = ProviderCredentialRefreshMaterial{} - mi := &file_openshell_proto_msgTypes[75] + mi := &file_openshell_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5485,7 +6267,7 @@ func (x *ProviderCredentialRefreshMaterial) String() string { func (*ProviderCredentialRefreshMaterial) ProtoMessage() {} func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[75] + mi := &file_openshell_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5498,7 +6280,7 @@ func (x *ProviderCredentialRefreshMaterial) ProtoReflect() protoreflect.Message // Deprecated: Use ProviderCredentialRefreshMaterial.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshMaterial) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{75} + return file_openshell_proto_rawDescGZIP(), []int{89} } func (x *ProviderCredentialRefreshMaterial) GetName() string { @@ -5543,7 +6325,7 @@ type ProviderCredentialRefreshOutput struct { func (x *ProviderCredentialRefreshOutput) Reset() { *x = ProviderCredentialRefreshOutput{} - mi := &file_openshell_proto_msgTypes[76] + mi := &file_openshell_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5555,7 +6337,7 @@ func (x *ProviderCredentialRefreshOutput) String() string { func (*ProviderCredentialRefreshOutput) ProtoMessage() {} func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[76] + mi := &file_openshell_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5568,7 +6350,7 @@ func (x *ProviderCredentialRefreshOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefreshOutput.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshOutput) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{76} + return file_openshell_proto_rawDescGZIP(), []int{90} } func (x *ProviderCredentialRefreshOutput) GetOutput() string { @@ -5600,7 +6382,7 @@ type ProviderCredentialRefresh struct { func (x *ProviderCredentialRefresh) Reset() { *x = ProviderCredentialRefresh{} - mi := &file_openshell_proto_msgTypes[77] + mi := &file_openshell_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5612,7 +6394,7 @@ func (x *ProviderCredentialRefresh) String() string { func (*ProviderCredentialRefresh) ProtoMessage() {} func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[77] + mi := &file_openshell_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5625,7 +6407,7 @@ func (x *ProviderCredentialRefresh) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefresh.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefresh) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{77} + return file_openshell_proto_rawDescGZIP(), []int{91} } func (x *ProviderCredentialRefresh) GetStrategy() ProviderCredentialRefreshStrategy { @@ -5694,7 +6476,7 @@ type ProviderCredentialRefreshStatus struct { func (x *ProviderCredentialRefreshStatus) Reset() { *x = ProviderCredentialRefreshStatus{} - mi := &file_openshell_proto_msgTypes[78] + mi := &file_openshell_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5706,7 +6488,7 @@ func (x *ProviderCredentialRefreshStatus) String() string { func (*ProviderCredentialRefreshStatus) ProtoMessage() {} func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[78] + mi := &file_openshell_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5719,7 +6501,7 @@ func (x *ProviderCredentialRefreshStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderCredentialRefreshStatus.ProtoReflect.Descriptor instead. func (*ProviderCredentialRefreshStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{78} + return file_openshell_proto_rawDescGZIP(), []int{92} } func (x *ProviderCredentialRefreshStatus) GetProviderName() string { @@ -5796,7 +6578,7 @@ type ProviderProfileDiscovery struct { func (x *ProviderProfileDiscovery) Reset() { *x = ProviderProfileDiscovery{} - mi := &file_openshell_proto_msgTypes[79] + mi := &file_openshell_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5808,7 +6590,7 @@ func (x *ProviderProfileDiscovery) String() string { func (*ProviderProfileDiscovery) ProtoMessage() {} func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[79] + mi := &file_openshell_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5821,7 +6603,7 @@ func (x *ProviderProfileDiscovery) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileDiscovery.ProtoReflect.Descriptor instead. func (*ProviderProfileDiscovery) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{79} + return file_openshell_proto_rawDescGZIP(), []int{93} } func (x *ProviderProfileDiscovery) GetCredentials() []string { @@ -5878,7 +6660,7 @@ type StoredProviderCredentialRefreshState struct { func (x *StoredProviderCredentialRefreshState) Reset() { *x = StoredProviderCredentialRefreshState{} - mi := &file_openshell_proto_msgTypes[80] + mi := &file_openshell_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5890,7 +6672,7 @@ func (x *StoredProviderCredentialRefreshState) String() string { func (*StoredProviderCredentialRefreshState) ProtoMessage() {} func (x *StoredProviderCredentialRefreshState) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[80] + mi := &file_openshell_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5903,7 +6685,7 @@ func (x *StoredProviderCredentialRefreshState) ProtoReflect() protoreflect.Messa // Deprecated: Use StoredProviderCredentialRefreshState.ProtoReflect.Descriptor instead. func (*StoredProviderCredentialRefreshState) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{80} + return file_openshell_proto_rawDescGZIP(), []int{94} } func (x *StoredProviderCredentialRefreshState) GetMetadata() *datamodelv1.ObjectMeta { @@ -6058,7 +6840,7 @@ type StoredRefreshMaterialDeletion struct { func (x *StoredRefreshMaterialDeletion) Reset() { *x = StoredRefreshMaterialDeletion{} - mi := &file_openshell_proto_msgTypes[81] + mi := &file_openshell_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6070,7 +6852,7 @@ func (x *StoredRefreshMaterialDeletion) String() string { func (*StoredRefreshMaterialDeletion) ProtoMessage() {} func (x *StoredRefreshMaterialDeletion) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[81] + mi := &file_openshell_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6083,7 +6865,7 @@ func (x *StoredRefreshMaterialDeletion) ProtoReflect() protoreflect.Message { // Deprecated: Use StoredRefreshMaterialDeletion.ProtoReflect.Descriptor instead. func (*StoredRefreshMaterialDeletion) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{81} + return file_openshell_proto_rawDescGZIP(), []int{95} } func (x *StoredRefreshMaterialDeletion) GetMaterialKey() string { @@ -6112,7 +6894,7 @@ type GetProviderRefreshStatusRequest struct { func (x *GetProviderRefreshStatusRequest) Reset() { *x = GetProviderRefreshStatusRequest{} - mi := &file_openshell_proto_msgTypes[82] + mi := &file_openshell_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6124,7 +6906,7 @@ func (x *GetProviderRefreshStatusRequest) String() string { func (*GetProviderRefreshStatusRequest) ProtoMessage() {} func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[82] + mi := &file_openshell_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6137,7 +6919,7 @@ func (x *GetProviderRefreshStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRefreshStatusRequest.ProtoReflect.Descriptor instead. func (*GetProviderRefreshStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{82} + return file_openshell_proto_rawDescGZIP(), []int{96} } func (x *GetProviderRefreshStatusRequest) GetProvider() string { @@ -6170,7 +6952,7 @@ type GetProviderRefreshStatusResponse struct { func (x *GetProviderRefreshStatusResponse) Reset() { *x = GetProviderRefreshStatusResponse{} - mi := &file_openshell_proto_msgTypes[83] + mi := &file_openshell_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6182,7 +6964,7 @@ func (x *GetProviderRefreshStatusResponse) String() string { func (*GetProviderRefreshStatusResponse) ProtoMessage() {} func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[83] + mi := &file_openshell_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6195,7 +6977,7 @@ func (x *GetProviderRefreshStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProviderRefreshStatusResponse.ProtoReflect.Descriptor instead. func (*GetProviderRefreshStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{83} + return file_openshell_proto_rawDescGZIP(), []int{97} } func (x *GetProviderRefreshStatusResponse) GetCredentials() []*ProviderCredentialRefreshStatus { @@ -6224,7 +7006,7 @@ type ConfigureProviderRefreshRequest struct { func (x *ConfigureProviderRefreshRequest) Reset() { *x = ConfigureProviderRefreshRequest{} - mi := &file_openshell_proto_msgTypes[84] + mi := &file_openshell_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6236,7 +7018,7 @@ func (x *ConfigureProviderRefreshRequest) String() string { func (*ConfigureProviderRefreshRequest) ProtoMessage() {} func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[84] + mi := &file_openshell_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6249,7 +7031,7 @@ func (x *ConfigureProviderRefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureProviderRefreshRequest.ProtoReflect.Descriptor instead. func (*ConfigureProviderRefreshRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{84} + return file_openshell_proto_rawDescGZIP(), []int{98} } func (x *ConfigureProviderRefreshRequest) GetProvider() string { @@ -6310,7 +7092,7 @@ type ConfigureProviderRefreshResponse struct { func (x *ConfigureProviderRefreshResponse) Reset() { *x = ConfigureProviderRefreshResponse{} - mi := &file_openshell_proto_msgTypes[85] + mi := &file_openshell_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6322,7 +7104,7 @@ func (x *ConfigureProviderRefreshResponse) String() string { func (*ConfigureProviderRefreshResponse) ProtoMessage() {} func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[85] + mi := &file_openshell_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6335,7 +7117,7 @@ func (x *ConfigureProviderRefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureProviderRefreshResponse.ProtoReflect.Descriptor instead. func (*ConfigureProviderRefreshResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{85} + return file_openshell_proto_rawDescGZIP(), []int{99} } func (x *ConfigureProviderRefreshResponse) GetStatus() *ProviderCredentialRefreshStatus { @@ -6357,7 +7139,7 @@ type RotateProviderCredentialRequest struct { func (x *RotateProviderCredentialRequest) Reset() { *x = RotateProviderCredentialRequest{} - mi := &file_openshell_proto_msgTypes[86] + mi := &file_openshell_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6369,7 +7151,7 @@ func (x *RotateProviderCredentialRequest) String() string { func (*RotateProviderCredentialRequest) ProtoMessage() {} func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[86] + mi := &file_openshell_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6382,7 +7164,7 @@ func (x *RotateProviderCredentialRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateProviderCredentialRequest.ProtoReflect.Descriptor instead. func (*RotateProviderCredentialRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{86} + return file_openshell_proto_rawDescGZIP(), []int{100} } func (x *RotateProviderCredentialRequest) GetProvider() string { @@ -6415,7 +7197,7 @@ type RotateProviderCredentialResponse struct { func (x *RotateProviderCredentialResponse) Reset() { *x = RotateProviderCredentialResponse{} - mi := &file_openshell_proto_msgTypes[87] + mi := &file_openshell_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6427,7 +7209,7 @@ func (x *RotateProviderCredentialResponse) String() string { func (*RotateProviderCredentialResponse) ProtoMessage() {} func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[87] + mi := &file_openshell_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6440,7 +7222,7 @@ func (x *RotateProviderCredentialResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateProviderCredentialResponse.ProtoReflect.Descriptor instead. func (*RotateProviderCredentialResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{87} + return file_openshell_proto_rawDescGZIP(), []int{101} } func (x *RotateProviderCredentialResponse) GetStatus() *ProviderCredentialRefreshStatus { @@ -6462,7 +7244,7 @@ type DeleteProviderRefreshRequest struct { func (x *DeleteProviderRefreshRequest) Reset() { *x = DeleteProviderRefreshRequest{} - mi := &file_openshell_proto_msgTypes[88] + mi := &file_openshell_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6474,7 +7256,7 @@ func (x *DeleteProviderRefreshRequest) String() string { func (*DeleteProviderRefreshRequest) ProtoMessage() {} func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[88] + mi := &file_openshell_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6487,7 +7269,7 @@ func (x *DeleteProviderRefreshRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRefreshRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderRefreshRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{88} + return file_openshell_proto_rawDescGZIP(), []int{102} } func (x *DeleteProviderRefreshRequest) GetProvider() string { @@ -6520,7 +7302,7 @@ type DeleteProviderRefreshResponse struct { func (x *DeleteProviderRefreshResponse) Reset() { *x = DeleteProviderRefreshResponse{} - mi := &file_openshell_proto_msgTypes[89] + mi := &file_openshell_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6532,7 +7314,7 @@ func (x *DeleteProviderRefreshResponse) String() string { func (*DeleteProviderRefreshResponse) ProtoMessage() {} func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[89] + mi := &file_openshell_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6545,7 +7327,7 @@ func (x *DeleteProviderRefreshResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderRefreshResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderRefreshResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{89} + return file_openshell_proto_rawDescGZIP(), []int{103} } func (x *DeleteProviderRefreshResponse) GetDeleted() bool { @@ -6585,7 +7367,7 @@ type ProviderProfile struct { func (x *ProviderProfile) Reset() { *x = ProviderProfile{} - mi := &file_openshell_proto_msgTypes[90] + mi := &file_openshell_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6597,7 +7379,7 @@ func (x *ProviderProfile) String() string { func (*ProviderProfile) ProtoMessage() {} func (x *ProviderProfile) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[90] + mi := &file_openshell_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6610,7 +7392,7 @@ func (x *ProviderProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfile.ProtoReflect.Descriptor instead. func (*ProviderProfile) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{90} + return file_openshell_proto_rawDescGZIP(), []int{104} } func (x *ProviderProfile) GetId() string { @@ -6715,7 +7497,7 @@ type StoredProviderProfile struct { func (x *StoredProviderProfile) Reset() { *x = StoredProviderProfile{} - mi := &file_openshell_proto_msgTypes[91] + mi := &file_openshell_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6727,7 +7509,7 @@ func (x *StoredProviderProfile) String() string { func (*StoredProviderProfile) ProtoMessage() {} func (x *StoredProviderProfile) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[91] + mi := &file_openshell_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6740,7 +7522,7 @@ func (x *StoredProviderProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use StoredProviderProfile.ProtoReflect.Descriptor instead. func (*StoredProviderProfile) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{91} + return file_openshell_proto_rawDescGZIP(), []int{105} } func (x *StoredProviderProfile) GetMetadata() *datamodelv1.ObjectMeta { @@ -6767,7 +7549,7 @@ type ProviderProfileResponse struct { func (x *ProviderProfileResponse) Reset() { *x = ProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[92] + mi := &file_openshell_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6779,7 +7561,7 @@ func (x *ProviderProfileResponse) String() string { func (*ProviderProfileResponse) ProtoMessage() {} func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[92] + mi := &file_openshell_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6792,7 +7574,7 @@ func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileResponse.ProtoReflect.Descriptor instead. func (*ProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{92} + return file_openshell_proto_rawDescGZIP(), []int{106} } func (x *ProviderProfileResponse) GetProfile() *ProviderProfile { @@ -6812,7 +7594,7 @@ type ListProviderProfilesResponse struct { func (x *ListProviderProfilesResponse) Reset() { *x = ListProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[93] + mi := &file_openshell_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6824,7 +7606,7 @@ func (x *ListProviderProfilesResponse) String() string { func (*ListProviderProfilesResponse) ProtoMessage() {} func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[93] + mi := &file_openshell_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6837,7 +7619,7 @@ func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ListProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{93} + return file_openshell_proto_rawDescGZIP(), []int{107} } func (x *ListProviderProfilesResponse) GetProfiles() []*ProviderProfile { @@ -6860,7 +7642,7 @@ type ImportProviderProfilesRequest struct { func (x *ImportProviderProfilesRequest) Reset() { *x = ImportProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[94] + mi := &file_openshell_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6872,7 +7654,7 @@ func (x *ImportProviderProfilesRequest) String() string { func (*ImportProviderProfilesRequest) ProtoMessage() {} func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[94] + mi := &file_openshell_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6885,7 +7667,7 @@ func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{94} + return file_openshell_proto_rawDescGZIP(), []int{108} } func (x *ImportProviderProfilesRequest) GetProfiles() []*ProviderProfileImportItem { @@ -6914,7 +7696,7 @@ type ImportProviderProfilesResponse struct { func (x *ImportProviderProfilesResponse) Reset() { *x = ImportProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[95] + mi := &file_openshell_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6926,7 +7708,7 @@ func (x *ImportProviderProfilesResponse) String() string { func (*ImportProviderProfilesResponse) ProtoMessage() {} func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[95] + mi := &file_openshell_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6939,7 +7721,7 @@ func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{95} + return file_openshell_proto_rawDescGZIP(), []int{109} } func (x *ImportProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -6983,7 +7765,7 @@ type UpdateProviderProfilesRequest struct { func (x *UpdateProviderProfilesRequest) Reset() { *x = UpdateProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[96] + mi := &file_openshell_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6995,7 +7777,7 @@ func (x *UpdateProviderProfilesRequest) String() string { func (*UpdateProviderProfilesRequest) ProtoMessage() {} func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[96] + mi := &file_openshell_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7008,7 +7790,7 @@ func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{96} + return file_openshell_proto_rawDescGZIP(), []int{110} } func (x *UpdateProviderProfilesRequest) GetProfile() *ProviderProfileImportItem { @@ -7051,7 +7833,7 @@ type UpdateProviderProfilesResponse struct { func (x *UpdateProviderProfilesResponse) Reset() { *x = UpdateProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[97] + mi := &file_openshell_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7063,7 +7845,7 @@ func (x *UpdateProviderProfilesResponse) String() string { func (*UpdateProviderProfilesResponse) ProtoMessage() {} func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[97] + mi := &file_openshell_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7076,7 +7858,7 @@ func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{97} + return file_openshell_proto_rawDescGZIP(), []int{111} } func (x *UpdateProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -7113,7 +7895,7 @@ type LintProviderProfilesRequest struct { func (x *LintProviderProfilesRequest) Reset() { *x = LintProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[98] + mi := &file_openshell_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7125,7 +7907,7 @@ func (x *LintProviderProfilesRequest) String() string { func (*LintProviderProfilesRequest) ProtoMessage() {} func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[98] + mi := &file_openshell_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7138,7 +7920,7 @@ func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*LintProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{98} + return file_openshell_proto_rawDescGZIP(), []int{112} } func (x *LintProviderProfilesRequest) GetProfiles() []*ProviderProfileImportItem { @@ -7166,7 +7948,7 @@ type LintProviderProfilesResponse struct { func (x *LintProviderProfilesResponse) Reset() { *x = LintProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[99] + mi := &file_openshell_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7178,7 +7960,7 @@ func (x *LintProviderProfilesResponse) String() string { func (*LintProviderProfilesResponse) ProtoMessage() {} func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[99] + mi := &file_openshell_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7191,7 +7973,7 @@ func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*LintProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{99} + return file_openshell_proto_rawDescGZIP(), []int{113} } func (x *LintProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -7218,7 +8000,7 @@ type DeleteProviderResponse struct { func (x *DeleteProviderResponse) Reset() { *x = DeleteProviderResponse{} - mi := &file_openshell_proto_msgTypes[100] + mi := &file_openshell_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7230,7 +8012,7 @@ func (x *DeleteProviderResponse) String() string { func (*DeleteProviderResponse) ProtoMessage() {} func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[100] + mi := &file_openshell_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7243,7 +8025,7 @@ func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{100} + return file_openshell_proto_rawDescGZIP(), []int{114} } func (x *DeleteProviderResponse) GetDeleted() bool { @@ -7266,7 +8048,7 @@ type DeleteProviderProfileRequest struct { func (x *DeleteProviderProfileRequest) Reset() { *x = DeleteProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[101] + mi := &file_openshell_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7278,7 +8060,7 @@ func (x *DeleteProviderProfileRequest) String() string { func (*DeleteProviderProfileRequest) ProtoMessage() {} func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[101] + mi := &file_openshell_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7291,7 +8073,7 @@ func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{101} + return file_openshell_proto_rawDescGZIP(), []int{115} } func (x *DeleteProviderProfileRequest) GetId() string { @@ -7318,7 +8100,7 @@ type DeleteProviderProfileResponse struct { func (x *DeleteProviderProfileResponse) Reset() { *x = DeleteProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[102] + mi := &file_openshell_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7330,7 +8112,7 @@ func (x *DeleteProviderProfileResponse) String() string { func (*DeleteProviderProfileResponse) ProtoMessage() {} func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[102] + mi := &file_openshell_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7343,7 +8125,7 @@ func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{102} + return file_openshell_proto_rawDescGZIP(), []int{116} } func (x *DeleteProviderProfileResponse) GetDeleted() bool { @@ -7368,7 +8150,7 @@ type GetSandboxProviderEnvironmentRequest struct { func (x *GetSandboxProviderEnvironmentRequest) Reset() { *x = GetSandboxProviderEnvironmentRequest{} - mi := &file_openshell_proto_msgTypes[103] + mi := &file_openshell_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7380,7 +8162,7 @@ func (x *GetSandboxProviderEnvironmentRequest) String() string { func (*GetSandboxProviderEnvironmentRequest) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[103] + mi := &file_openshell_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7393,7 +8175,7 @@ func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Messa // Deprecated: Use GetSandboxProviderEnvironmentRequest.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{103} + return file_openshell_proto_rawDescGZIP(), []int{117} } func (x *GetSandboxProviderEnvironmentRequest) GetSandboxId() string { @@ -7422,7 +8204,7 @@ type StaticCredentialEndpointBinding struct { func (x *StaticCredentialEndpointBinding) Reset() { *x = StaticCredentialEndpointBinding{} - mi := &file_openshell_proto_msgTypes[104] + mi := &file_openshell_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7434,7 +8216,7 @@ func (x *StaticCredentialEndpointBinding) String() string { func (*StaticCredentialEndpointBinding) ProtoMessage() {} func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[104] + mi := &file_openshell_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7447,7 +8229,7 @@ func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialEndpointBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialEndpointBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{104} + return file_openshell_proto_rawDescGZIP(), []int{118} } func (x *StaticCredentialEndpointBinding) GetHost() string { @@ -7491,7 +8273,7 @@ type StaticCredentialBinding struct { func (x *StaticCredentialBinding) Reset() { *x = StaticCredentialBinding{} - mi := &file_openshell_proto_msgTypes[105] + mi := &file_openshell_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7503,7 +8285,7 @@ func (x *StaticCredentialBinding) String() string { func (*StaticCredentialBinding) ProtoMessage() {} func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[105] + mi := &file_openshell_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7516,7 +8298,7 @@ func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{105} + return file_openshell_proto_rawDescGZIP(), []int{119} } func (x *StaticCredentialBinding) GetEndpoints() []*StaticCredentialEndpointBinding { @@ -7567,7 +8349,7 @@ type GetSandboxProviderEnvironmentResponse struct { func (x *GetSandboxProviderEnvironmentResponse) Reset() { *x = GetSandboxProviderEnvironmentResponse{} - mi := &file_openshell_proto_msgTypes[106] + mi := &file_openshell_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7579,7 +8361,7 @@ func (x *GetSandboxProviderEnvironmentResponse) String() string { func (*GetSandboxProviderEnvironmentResponse) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[106] + mi := &file_openshell_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7592,7 +8374,7 @@ func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Mess // Deprecated: Use GetSandboxProviderEnvironmentResponse.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{106} + return file_openshell_proto_rawDescGZIP(), []int{120} } func (x *GetSandboxProviderEnvironmentResponse) GetEnvironment() map[string]string { @@ -7684,7 +8466,7 @@ type UpdateConfigRequest struct { func (x *UpdateConfigRequest) Reset() { *x = UpdateConfigRequest{} - mi := &file_openshell_proto_msgTypes[107] + mi := &file_openshell_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7696,7 +8478,7 @@ func (x *UpdateConfigRequest) String() string { func (*UpdateConfigRequest) ProtoMessage() {} func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[107] + mi := &file_openshell_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7709,7 +8491,7 @@ func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigRequest.ProtoReflect.Descriptor instead. func (*UpdateConfigRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{107} + return file_openshell_proto_rawDescGZIP(), []int{121} } func (x *UpdateConfigRequest) GetName() string { @@ -7799,7 +8581,7 @@ type PolicyMergeOperation struct { func (x *PolicyMergeOperation) Reset() { *x = PolicyMergeOperation{} - mi := &file_openshell_proto_msgTypes[108] + mi := &file_openshell_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7811,7 +8593,7 @@ func (x *PolicyMergeOperation) String() string { func (*PolicyMergeOperation) ProtoMessage() {} func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[108] + mi := &file_openshell_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7824,7 +8606,7 @@ func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyMergeOperation.ProtoReflect.Descriptor instead. func (*PolicyMergeOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{108} + return file_openshell_proto_rawDescGZIP(), []int{122} } func (x *PolicyMergeOperation) GetOperation() isPolicyMergeOperation_Operation { @@ -7938,7 +8720,7 @@ type AddNetworkRule struct { func (x *AddNetworkRule) Reset() { *x = AddNetworkRule{} - mi := &file_openshell_proto_msgTypes[109] + mi := &file_openshell_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7950,7 +8732,7 @@ func (x *AddNetworkRule) String() string { func (*AddNetworkRule) ProtoMessage() {} func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[109] + mi := &file_openshell_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7963,7 +8745,7 @@ func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use AddNetworkRule.ProtoReflect.Descriptor instead. func (*AddNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{109} + return file_openshell_proto_rawDescGZIP(), []int{123} } func (x *AddNetworkRule) GetRuleName() string { @@ -7991,7 +8773,7 @@ type RemoveNetworkEndpoint struct { func (x *RemoveNetworkEndpoint) Reset() { *x = RemoveNetworkEndpoint{} - mi := &file_openshell_proto_msgTypes[110] + mi := &file_openshell_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8003,7 +8785,7 @@ func (x *RemoveNetworkEndpoint) String() string { func (*RemoveNetworkEndpoint) ProtoMessage() {} func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[110] + mi := &file_openshell_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8016,7 +8798,7 @@ func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkEndpoint.ProtoReflect.Descriptor instead. func (*RemoveNetworkEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{110} + return file_openshell_proto_rawDescGZIP(), []int{124} } func (x *RemoveNetworkEndpoint) GetRuleName() string { @@ -8049,7 +8831,7 @@ type RemoveNetworkRule struct { func (x *RemoveNetworkRule) Reset() { *x = RemoveNetworkRule{} - mi := &file_openshell_proto_msgTypes[111] + mi := &file_openshell_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8061,7 +8843,7 @@ func (x *RemoveNetworkRule) String() string { func (*RemoveNetworkRule) ProtoMessage() {} func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[111] + mi := &file_openshell_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8074,7 +8856,7 @@ func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkRule.ProtoReflect.Descriptor instead. func (*RemoveNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{111} + return file_openshell_proto_rawDescGZIP(), []int{125} } func (x *RemoveNetworkRule) GetRuleName() string { @@ -8095,7 +8877,7 @@ type AddDenyRules struct { func (x *AddDenyRules) Reset() { *x = AddDenyRules{} - mi := &file_openshell_proto_msgTypes[112] + mi := &file_openshell_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8107,7 +8889,7 @@ func (x *AddDenyRules) String() string { func (*AddDenyRules) ProtoMessage() {} func (x *AddDenyRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[112] + mi := &file_openshell_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8120,7 +8902,7 @@ func (x *AddDenyRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddDenyRules.ProtoReflect.Descriptor instead. func (*AddDenyRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{112} + return file_openshell_proto_rawDescGZIP(), []int{126} } func (x *AddDenyRules) GetHost() string { @@ -8155,7 +8937,7 @@ type AddAllowRules struct { func (x *AddAllowRules) Reset() { *x = AddAllowRules{} - mi := &file_openshell_proto_msgTypes[113] + mi := &file_openshell_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8167,7 +8949,7 @@ func (x *AddAllowRules) String() string { func (*AddAllowRules) ProtoMessage() {} func (x *AddAllowRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[113] + mi := &file_openshell_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8180,7 +8962,7 @@ func (x *AddAllowRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAllowRules.ProtoReflect.Descriptor instead. func (*AddAllowRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{113} + return file_openshell_proto_rawDescGZIP(), []int{127} } func (x *AddAllowRules) GetHost() string { @@ -8214,7 +8996,7 @@ type RemoveNetworkBinary struct { func (x *RemoveNetworkBinary) Reset() { *x = RemoveNetworkBinary{} - mi := &file_openshell_proto_msgTypes[114] + mi := &file_openshell_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8226,7 +9008,7 @@ func (x *RemoveNetworkBinary) String() string { func (*RemoveNetworkBinary) ProtoMessage() {} func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[114] + mi := &file_openshell_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8239,7 +9021,7 @@ func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkBinary.ProtoReflect.Descriptor instead. func (*RemoveNetworkBinary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{114} + return file_openshell_proto_rawDescGZIP(), []int{128} } func (x *RemoveNetworkBinary) GetRuleName() string { @@ -8275,7 +9057,7 @@ type UpdateConfigResponse struct { func (x *UpdateConfigResponse) Reset() { *x = UpdateConfigResponse{} - mi := &file_openshell_proto_msgTypes[115] + mi := &file_openshell_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8287,7 +9069,7 @@ func (x *UpdateConfigResponse) String() string { func (*UpdateConfigResponse) ProtoMessage() {} func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[115] + mi := &file_openshell_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8300,7 +9082,7 @@ func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigResponse.ProtoReflect.Descriptor instead. func (*UpdateConfigResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{115} + return file_openshell_proto_rawDescGZIP(), []int{129} } func (x *UpdateConfigResponse) GetVersion() uint32 { @@ -8355,7 +9137,7 @@ type GetSandboxPolicyStatusRequest struct { func (x *GetSandboxPolicyStatusRequest) Reset() { *x = GetSandboxPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[116] + mi := &file_openshell_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8367,7 +9149,7 @@ func (x *GetSandboxPolicyStatusRequest) String() string { func (*GetSandboxPolicyStatusRequest) ProtoMessage() {} func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[116] + mi := &file_openshell_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8380,7 +9162,7 @@ func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{116} + return file_openshell_proto_rawDescGZIP(), []int{130} } func (x *GetSandboxPolicyStatusRequest) GetName() string { @@ -8424,7 +9206,7 @@ type GetSandboxPolicyStatusResponse struct { func (x *GetSandboxPolicyStatusResponse) Reset() { *x = GetSandboxPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[117] + mi := &file_openshell_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8436,7 +9218,7 @@ func (x *GetSandboxPolicyStatusResponse) String() string { func (*GetSandboxPolicyStatusResponse) ProtoMessage() {} func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[117] + mi := &file_openshell_proto_msgTypes[131] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8449,7 +9231,7 @@ func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{117} + return file_openshell_proto_rawDescGZIP(), []int{131} } func (x *GetSandboxPolicyStatusResponse) GetRevision() *SandboxPolicyRevision { @@ -8483,7 +9265,7 @@ type ListSandboxPoliciesRequest struct { func (x *ListSandboxPoliciesRequest) Reset() { *x = ListSandboxPoliciesRequest{} - mi := &file_openshell_proto_msgTypes[118] + mi := &file_openshell_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8495,7 +9277,7 @@ func (x *ListSandboxPoliciesRequest) String() string { func (*ListSandboxPoliciesRequest) ProtoMessage() {} func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[118] + mi := &file_openshell_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8508,7 +9290,7 @@ func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{118} + return file_openshell_proto_rawDescGZIP(), []int{132} } func (x *ListSandboxPoliciesRequest) GetName() string { @@ -8556,7 +9338,7 @@ type ListSandboxPoliciesResponse struct { func (x *ListSandboxPoliciesResponse) Reset() { *x = ListSandboxPoliciesResponse{} - mi := &file_openshell_proto_msgTypes[119] + mi := &file_openshell_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8568,7 +9350,7 @@ func (x *ListSandboxPoliciesResponse) String() string { func (*ListSandboxPoliciesResponse) ProtoMessage() {} func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[119] + mi := &file_openshell_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8581,7 +9363,7 @@ func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{119} + return file_openshell_proto_rawDescGZIP(), []int{133} } func (x *ListSandboxPoliciesResponse) GetRevisions() []*SandboxPolicyRevision { @@ -8608,7 +9390,7 @@ type ReportPolicyStatusRequest struct { func (x *ReportPolicyStatusRequest) Reset() { *x = ReportPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[120] + mi := &file_openshell_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8620,7 +9402,7 @@ func (x *ReportPolicyStatusRequest) String() string { func (*ReportPolicyStatusRequest) ProtoMessage() {} func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[120] + mi := &file_openshell_proto_msgTypes[134] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8633,7 +9415,7 @@ func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{120} + return file_openshell_proto_rawDescGZIP(), []int{134} } func (x *ReportPolicyStatusRequest) GetSandboxId() string { @@ -8673,7 +9455,7 @@ type ReportPolicyStatusResponse struct { func (x *ReportPolicyStatusResponse) Reset() { *x = ReportPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[121] + mi := &file_openshell_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8685,7 +9467,7 @@ func (x *ReportPolicyStatusResponse) String() string { func (*ReportPolicyStatusResponse) ProtoMessage() {} func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[121] + mi := &file_openshell_proto_msgTypes[135] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8698,7 +9480,7 @@ func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{121} + return file_openshell_proto_rawDescGZIP(), []int{135} } // A versioned policy revision with metadata. @@ -8726,7 +9508,7 @@ type SandboxPolicyRevision struct { func (x *SandboxPolicyRevision) Reset() { *x = SandboxPolicyRevision{} - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8738,7 +9520,7 @@ func (x *SandboxPolicyRevision) String() string { func (*SandboxPolicyRevision) ProtoMessage() {} func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[136] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8751,7 +9533,7 @@ func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxPolicyRevision.ProtoReflect.Descriptor instead. func (*SandboxPolicyRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{122} + return file_openshell_proto_rawDescGZIP(), []int{136} } func (x *SandboxPolicyRevision) GetVersion() uint32 { @@ -8831,7 +9613,7 @@ type GetSandboxLogsRequest struct { func (x *GetSandboxLogsRequest) Reset() { *x = GetSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8843,7 +9625,7 @@ func (x *GetSandboxLogsRequest) String() string { func (*GetSandboxLogsRequest) ProtoMessage() {} func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[137] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8856,7 +9638,7 @@ func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*GetSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{123} + return file_openshell_proto_rawDescGZIP(), []int{137} } func (x *GetSandboxLogsRequest) GetSandboxId() string { @@ -8914,7 +9696,7 @@ type PushSandboxLogsRequest struct { func (x *PushSandboxLogsRequest) Reset() { *x = PushSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8926,7 +9708,7 @@ func (x *PushSandboxLogsRequest) String() string { func (*PushSandboxLogsRequest) ProtoMessage() {} func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[138] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8939,7 +9721,7 @@ func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*PushSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{124} + return file_openshell_proto_rawDescGZIP(), []int{138} } func (x *PushSandboxLogsRequest) GetSandboxId() string { @@ -8965,7 +9747,7 @@ type PushSandboxLogsResponse struct { func (x *PushSandboxLogsResponse) Reset() { *x = PushSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8977,7 +9759,7 @@ func (x *PushSandboxLogsResponse) String() string { func (*PushSandboxLogsResponse) ProtoMessage() {} func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[139] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8990,7 +9772,7 @@ func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*PushSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{125} + return file_openshell_proto_rawDescGZIP(), []int{139} } // Get sandbox logs response. @@ -9006,7 +9788,7 @@ type GetSandboxLogsResponse struct { func (x *GetSandboxLogsResponse) Reset() { *x = GetSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[140] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9018,7 +9800,7 @@ func (x *GetSandboxLogsResponse) String() string { func (*GetSandboxLogsResponse) ProtoMessage() {} func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[140] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9031,7 +9813,7 @@ func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*GetSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{126} + return file_openshell_proto_rawDescGZIP(), []int{140} } func (x *GetSandboxLogsResponse) GetLogs() []*SandboxLogLine { @@ -9064,7 +9846,7 @@ type SupervisorMessage struct { func (x *SupervisorMessage) Reset() { *x = SupervisorMessage{} - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9076,7 +9858,7 @@ func (x *SupervisorMessage) String() string { func (*SupervisorMessage) ProtoMessage() {} func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[141] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9089,7 +9871,7 @@ func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMessage.ProtoReflect.Descriptor instead. func (*SupervisorMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{127} + return file_openshell_proto_rawDescGZIP(), []int{141} } func (x *SupervisorMessage) GetPayload() isSupervisorMessage_Payload { @@ -9180,7 +9962,7 @@ type GatewayMessage struct { func (x *GatewayMessage) Reset() { *x = GatewayMessage{} - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[142] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9192,7 +9974,7 @@ func (x *GatewayMessage) String() string { func (*GatewayMessage) ProtoMessage() {} func (x *GatewayMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[142] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9205,7 +9987,7 @@ func (x *GatewayMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayMessage.ProtoReflect.Descriptor instead. func (*GatewayMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{128} + return file_openshell_proto_rawDescGZIP(), []int{142} } func (x *GatewayMessage) GetPayload() isGatewayMessage_Payload { @@ -9307,7 +10089,7 @@ type SupervisorHello struct { func (x *SupervisorHello) Reset() { *x = SupervisorHello{} - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[143] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9319,7 +10101,7 @@ func (x *SupervisorHello) String() string { func (*SupervisorHello) ProtoMessage() {} func (x *SupervisorHello) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[143] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9332,7 +10114,7 @@ func (x *SupervisorHello) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHello.ProtoReflect.Descriptor instead. func (*SupervisorHello) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{129} + return file_openshell_proto_rawDescGZIP(), []int{143} } func (x *SupervisorHello) GetSandboxId() string { @@ -9362,7 +10144,7 @@ type SessionAccepted struct { func (x *SessionAccepted) Reset() { *x = SessionAccepted{} - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[144] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9374,7 +10156,7 @@ func (x *SessionAccepted) String() string { func (*SessionAccepted) ProtoMessage() {} func (x *SessionAccepted) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[144] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9387,7 +10169,7 @@ func (x *SessionAccepted) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionAccepted.ProtoReflect.Descriptor instead. func (*SessionAccepted) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{130} + return file_openshell_proto_rawDescGZIP(), []int{144} } func (x *SessionAccepted) GetSessionId() string { @@ -9415,7 +10197,7 @@ type SessionRejected struct { func (x *SessionRejected) Reset() { *x = SessionRejected{} - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9427,7 +10209,7 @@ func (x *SessionRejected) String() string { func (*SessionRejected) ProtoMessage() {} func (x *SessionRejected) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[145] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9440,7 +10222,7 @@ func (x *SessionRejected) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRejected.ProtoReflect.Descriptor instead. func (*SessionRejected) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{131} + return file_openshell_proto_rawDescGZIP(), []int{145} } func (x *SessionRejected) GetReason() string { @@ -9459,7 +10241,7 @@ type SupervisorHeartbeat struct { func (x *SupervisorHeartbeat) Reset() { *x = SupervisorHeartbeat{} - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9471,7 +10253,7 @@ func (x *SupervisorHeartbeat) String() string { func (*SupervisorHeartbeat) ProtoMessage() {} func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[146] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9484,7 +10266,7 @@ func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHeartbeat.ProtoReflect.Descriptor instead. func (*SupervisorHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{132} + return file_openshell_proto_rawDescGZIP(), []int{146} } // Gateway heartbeat. @@ -9496,7 +10278,7 @@ type GatewayHeartbeat struct { func (x *GatewayHeartbeat) Reset() { *x = GatewayHeartbeat{} - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[147] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9508,7 +10290,7 @@ func (x *GatewayHeartbeat) String() string { func (*GatewayHeartbeat) ProtoMessage() {} func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[147] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9521,7 +10303,7 @@ func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayHeartbeat.ProtoReflect.Descriptor instead. func (*GatewayHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{133} + return file_openshell_proto_rawDescGZIP(), []int{147} } // Gateway requests the supervisor to open a relay channel. @@ -9550,7 +10332,7 @@ type RelayOpen struct { func (x *RelayOpen) Reset() { *x = RelayOpen{} - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9562,7 +10344,7 @@ func (x *RelayOpen) String() string { func (*RelayOpen) ProtoMessage() {} func (x *RelayOpen) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[148] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9575,7 +10357,7 @@ func (x *RelayOpen) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpen.ProtoReflect.Descriptor instead. func (*RelayOpen) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{134} + return file_openshell_proto_rawDescGZIP(), []int{148} } func (x *RelayOpen) GetChannelId() string { @@ -9642,7 +10424,7 @@ type SshRelayTarget struct { func (x *SshRelayTarget) Reset() { *x = SshRelayTarget{} - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9654,7 +10436,7 @@ func (x *SshRelayTarget) String() string { func (*SshRelayTarget) ProtoMessage() {} func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[149] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9667,7 +10449,7 @@ func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use SshRelayTarget.ProtoReflect.Descriptor instead. func (*SshRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{135} + return file_openshell_proto_rawDescGZIP(), []int{149} } // TCP target dialed by the supervisor from inside the sandbox. @@ -9683,7 +10465,7 @@ type TcpRelayTarget struct { func (x *TcpRelayTarget) Reset() { *x = TcpRelayTarget{} - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9695,7 +10477,7 @@ func (x *TcpRelayTarget) String() string { func (*TcpRelayTarget) ProtoMessage() {} func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[150] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9708,7 +10490,7 @@ func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpRelayTarget.ProtoReflect.Descriptor instead. func (*TcpRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{136} + return file_openshell_proto_rawDescGZIP(), []int{150} } func (x *TcpRelayTarget) GetHost() string { @@ -9736,7 +10518,7 @@ type RelayInit struct { func (x *RelayInit) Reset() { *x = RelayInit{} - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9748,7 +10530,7 @@ func (x *RelayInit) String() string { func (*RelayInit) ProtoMessage() {} func (x *RelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[151] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9761,7 +10543,7 @@ func (x *RelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayInit.ProtoReflect.Descriptor instead. func (*RelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{137} + return file_openshell_proto_rawDescGZIP(), []int{151} } func (x *RelayInit) GetChannelId() string { @@ -9788,7 +10570,7 @@ type RelayFrame struct { func (x *RelayFrame) Reset() { *x = RelayFrame{} - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9800,7 +10582,7 @@ func (x *RelayFrame) String() string { func (*RelayFrame) ProtoMessage() {} func (x *RelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[152] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9813,7 +10595,7 @@ func (x *RelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayFrame.ProtoReflect.Descriptor instead. func (*RelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{138} + return file_openshell_proto_rawDescGZIP(), []int{152} } func (x *RelayFrame) GetPayload() isRelayFrame_Payload { @@ -9872,7 +10654,7 @@ type RelayOpenResult struct { func (x *RelayOpenResult) Reset() { *x = RelayOpenResult{} - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9884,7 +10666,7 @@ func (x *RelayOpenResult) String() string { func (*RelayOpenResult) ProtoMessage() {} func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[153] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9897,7 +10679,7 @@ func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpenResult.ProtoReflect.Descriptor instead. func (*RelayOpenResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{139} + return file_openshell_proto_rawDescGZIP(), []int{153} } func (x *RelayOpenResult) GetChannelId() string { @@ -9934,7 +10716,7 @@ type RelayClose struct { func (x *RelayClose) Reset() { *x = RelayClose{} - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[154] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9946,7 +10728,7 @@ func (x *RelayClose) String() string { func (*RelayClose) ProtoMessage() {} func (x *RelayClose) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[154] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9959,7 +10741,7 @@ func (x *RelayClose) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayClose.ProtoReflect.Descriptor instead. func (*RelayClose) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{140} + return file_openshell_proto_rawDescGZIP(), []int{154} } func (x *RelayClose) GetChannelId() string { @@ -9993,7 +10775,7 @@ type L7RequestSample struct { func (x *L7RequestSample) Reset() { *x = L7RequestSample{} - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[155] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10005,7 +10787,7 @@ func (x *L7RequestSample) String() string { func (*L7RequestSample) ProtoMessage() {} func (x *L7RequestSample) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[155] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10018,7 +10800,7 @@ func (x *L7RequestSample) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RequestSample.ProtoReflect.Descriptor instead. func (*L7RequestSample) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{141} + return file_openshell_proto_rawDescGZIP(), []int{155} } func (x *L7RequestSample) GetMethod() string { @@ -10092,7 +10874,7 @@ type DenialSummary struct { func (x *DenialSummary) Reset() { *x = DenialSummary{} - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[156] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10104,7 +10886,7 @@ func (x *DenialSummary) String() string { func (*DenialSummary) ProtoMessage() {} func (x *DenialSummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[156] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10117,7 +10899,7 @@ func (x *DenialSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialSummary.ProtoReflect.Descriptor instead. func (*DenialSummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{142} + return file_openshell_proto_rawDescGZIP(), []int{156} } func (x *DenialSummary) GetSandboxId() string { @@ -10252,7 +11034,7 @@ type DenialGroupCount struct { func (x *DenialGroupCount) Reset() { *x = DenialGroupCount{} - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[157] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10264,7 +11046,7 @@ func (x *DenialGroupCount) String() string { func (*DenialGroupCount) ProtoMessage() {} func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[157] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10277,7 +11059,7 @@ func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialGroupCount.ProtoReflect.Descriptor instead. func (*DenialGroupCount) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{143} + return file_openshell_proto_rawDescGZIP(), []int{157} } func (x *DenialGroupCount) GetDenyGroup() string { @@ -10310,7 +11092,7 @@ type NetworkActivitySummary struct { func (x *NetworkActivitySummary) Reset() { *x = NetworkActivitySummary{} - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[158] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10322,7 +11104,7 @@ func (x *NetworkActivitySummary) String() string { func (*NetworkActivitySummary) ProtoMessage() {} func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[158] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10335,7 +11117,7 @@ func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkActivitySummary.ProtoReflect.Descriptor instead. func (*NetworkActivitySummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{144} + return file_openshell_proto_rawDescGZIP(), []int{158} } func (x *NetworkActivitySummary) GetNetworkActivityCount() uint32 { @@ -10409,7 +11191,7 @@ type PolicyChunk struct { func (x *PolicyChunk) Reset() { *x = PolicyChunk{} - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[159] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10421,7 +11203,7 @@ func (x *PolicyChunk) String() string { func (*PolicyChunk) ProtoMessage() {} func (x *PolicyChunk) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[159] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10434,7 +11216,7 @@ func (x *PolicyChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyChunk.ProtoReflect.Descriptor instead. func (*PolicyChunk) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{145} + return file_openshell_proto_rawDescGZIP(), []int{159} } func (x *PolicyChunk) GetId() string { @@ -10580,7 +11362,7 @@ type DraftPolicyUpdate struct { func (x *DraftPolicyUpdate) Reset() { *x = DraftPolicyUpdate{} - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[160] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10592,7 +11374,7 @@ func (x *DraftPolicyUpdate) String() string { func (*DraftPolicyUpdate) ProtoMessage() {} func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[160] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10605,7 +11387,7 @@ func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftPolicyUpdate.ProtoReflect.Descriptor instead. func (*DraftPolicyUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{146} + return file_openshell_proto_rawDescGZIP(), []int{160} } func (x *DraftPolicyUpdate) GetDraftVersion() uint64 { @@ -10663,7 +11445,7 @@ type SubmitPolicyAnalysisRequest struct { func (x *SubmitPolicyAnalysisRequest) Reset() { *x = SubmitPolicyAnalysisRequest{} - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[161] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10675,7 +11457,7 @@ func (x *SubmitPolicyAnalysisRequest) String() string { func (*SubmitPolicyAnalysisRequest) ProtoMessage() {} func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[161] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10688,7 +11470,7 @@ func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisRequest.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{147} + return file_openshell_proto_rawDescGZIP(), []int{161} } func (x *SubmitPolicyAnalysisRequest) GetSummaries() []*DenialSummary { @@ -10751,7 +11533,7 @@ type SubmitPolicyAnalysisResponse struct { func (x *SubmitPolicyAnalysisResponse) Reset() { *x = SubmitPolicyAnalysisResponse{} - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[162] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10763,7 +11545,7 @@ func (x *SubmitPolicyAnalysisResponse) String() string { func (*SubmitPolicyAnalysisResponse) ProtoMessage() {} func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[162] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10776,7 +11558,7 @@ func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisResponse.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{148} + return file_openshell_proto_rawDescGZIP(), []int{162} } func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunks() uint32 { @@ -10822,7 +11604,7 @@ type GetDraftPolicyRequest struct { func (x *GetDraftPolicyRequest) Reset() { *x = GetDraftPolicyRequest{} - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[163] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10834,7 +11616,7 @@ func (x *GetDraftPolicyRequest) String() string { func (*GetDraftPolicyRequest) ProtoMessage() {} func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[163] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10847,7 +11629,7 @@ func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyRequest.ProtoReflect.Descriptor instead. func (*GetDraftPolicyRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{149} + return file_openshell_proto_rawDescGZIP(), []int{163} } func (x *GetDraftPolicyRequest) GetName() string { @@ -10887,7 +11669,7 @@ type GetDraftPolicyResponse struct { func (x *GetDraftPolicyResponse) Reset() { *x = GetDraftPolicyResponse{} - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[164] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10899,7 +11681,7 @@ func (x *GetDraftPolicyResponse) String() string { func (*GetDraftPolicyResponse) ProtoMessage() {} func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[164] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10912,7 +11694,7 @@ func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyResponse.ProtoReflect.Descriptor instead. func (*GetDraftPolicyResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{150} + return file_openshell_proto_rawDescGZIP(), []int{164} } func (x *GetDraftPolicyResponse) GetChunks() []*PolicyChunk { @@ -10958,7 +11740,7 @@ type ApproveDraftChunkRequest struct { func (x *ApproveDraftChunkRequest) Reset() { *x = ApproveDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[165] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10970,7 +11752,7 @@ func (x *ApproveDraftChunkRequest) String() string { func (*ApproveDraftChunkRequest) ProtoMessage() {} func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[165] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10983,7 +11765,7 @@ func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkRequest.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{151} + return file_openshell_proto_rawDescGZIP(), []int{165} } func (x *ApproveDraftChunkRequest) GetName() string { @@ -11019,7 +11801,7 @@ type ApproveDraftChunkResponse struct { func (x *ApproveDraftChunkResponse) Reset() { *x = ApproveDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[166] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11031,7 +11813,7 @@ func (x *ApproveDraftChunkResponse) String() string { func (*ApproveDraftChunkResponse) ProtoMessage() {} func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[166] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11044,7 +11826,7 @@ func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkResponse.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{152} + return file_openshell_proto_rawDescGZIP(), []int{166} } func (x *ApproveDraftChunkResponse) GetPolicyVersion() uint32 { @@ -11078,7 +11860,7 @@ type RejectDraftChunkRequest struct { func (x *RejectDraftChunkRequest) Reset() { *x = RejectDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[167] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11090,7 +11872,7 @@ func (x *RejectDraftChunkRequest) String() string { func (*RejectDraftChunkRequest) ProtoMessage() {} func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[167] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11103,7 +11885,7 @@ func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkRequest.ProtoReflect.Descriptor instead. func (*RejectDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{153} + return file_openshell_proto_rawDescGZIP(), []int{167} } func (x *RejectDraftChunkRequest) GetName() string { @@ -11142,7 +11924,7 @@ type RejectDraftChunkResponse struct { func (x *RejectDraftChunkResponse) Reset() { *x = RejectDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[168] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11154,7 +11936,7 @@ func (x *RejectDraftChunkResponse) String() string { func (*RejectDraftChunkResponse) ProtoMessage() {} func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[168] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11167,7 +11949,7 @@ func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkResponse.ProtoReflect.Descriptor instead. func (*RejectDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{154} + return file_openshell_proto_rawDescGZIP(), []int{168} } // Approve all pending chunks. @@ -11185,7 +11967,7 @@ type ApproveAllDraftChunksRequest struct { func (x *ApproveAllDraftChunksRequest) Reset() { *x = ApproveAllDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[169] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11197,7 +11979,7 @@ func (x *ApproveAllDraftChunksRequest) String() string { func (*ApproveAllDraftChunksRequest) ProtoMessage() {} func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[169] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11210,7 +11992,7 @@ func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{155} + return file_openshell_proto_rawDescGZIP(), []int{169} } func (x *ApproveAllDraftChunksRequest) GetName() string { @@ -11250,7 +12032,7 @@ type ApproveAllDraftChunksResponse struct { func (x *ApproveAllDraftChunksResponse) Reset() { *x = ApproveAllDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[170] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11262,7 +12044,7 @@ func (x *ApproveAllDraftChunksResponse) String() string { func (*ApproveAllDraftChunksResponse) ProtoMessage() {} func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[170] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11275,7 +12057,7 @@ func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{156} + return file_openshell_proto_rawDescGZIP(), []int{170} } func (x *ApproveAllDraftChunksResponse) GetPolicyVersion() uint32 { @@ -11323,7 +12105,7 @@ type EditDraftChunkRequest struct { func (x *EditDraftChunkRequest) Reset() { *x = EditDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[171] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11335,7 +12117,7 @@ func (x *EditDraftChunkRequest) String() string { func (*EditDraftChunkRequest) ProtoMessage() {} func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[171] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11348,7 +12130,7 @@ func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkRequest.ProtoReflect.Descriptor instead. func (*EditDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{157} + return file_openshell_proto_rawDescGZIP(), []int{171} } func (x *EditDraftChunkRequest) GetName() string { @@ -11387,7 +12169,7 @@ type EditDraftChunkResponse struct { func (x *EditDraftChunkResponse) Reset() { *x = EditDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[172] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11399,7 +12181,7 @@ func (x *EditDraftChunkResponse) String() string { func (*EditDraftChunkResponse) ProtoMessage() {} func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[172] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11412,7 +12194,7 @@ func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkResponse.ProtoReflect.Descriptor instead. func (*EditDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{158} + return file_openshell_proto_rawDescGZIP(), []int{172} } // Reverse an approval (remove merged rule from active policy). @@ -11430,7 +12212,7 @@ type UndoDraftChunkRequest struct { func (x *UndoDraftChunkRequest) Reset() { *x = UndoDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[173] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11442,7 +12224,7 @@ func (x *UndoDraftChunkRequest) String() string { func (*UndoDraftChunkRequest) ProtoMessage() {} func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[173] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11455,7 +12237,7 @@ func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkRequest.ProtoReflect.Descriptor instead. func (*UndoDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{159} + return file_openshell_proto_rawDescGZIP(), []int{173} } func (x *UndoDraftChunkRequest) GetName() string { @@ -11491,7 +12273,7 @@ type UndoDraftChunkResponse struct { func (x *UndoDraftChunkResponse) Reset() { *x = UndoDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[174] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11503,7 +12285,7 @@ func (x *UndoDraftChunkResponse) String() string { func (*UndoDraftChunkResponse) ProtoMessage() {} func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[174] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11516,7 +12298,7 @@ func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkResponse.ProtoReflect.Descriptor instead. func (*UndoDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{160} + return file_openshell_proto_rawDescGZIP(), []int{174} } func (x *UndoDraftChunkResponse) GetPolicyVersion() uint32 { @@ -11546,7 +12328,7 @@ type ClearDraftChunksRequest struct { func (x *ClearDraftChunksRequest) Reset() { *x = ClearDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[175] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11558,7 +12340,7 @@ func (x *ClearDraftChunksRequest) String() string { func (*ClearDraftChunksRequest) ProtoMessage() {} func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[175] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11571,7 +12353,7 @@ func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ClearDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{161} + return file_openshell_proto_rawDescGZIP(), []int{175} } func (x *ClearDraftChunksRequest) GetName() string { @@ -11598,7 +12380,7 @@ type ClearDraftChunksResponse struct { func (x *ClearDraftChunksResponse) Reset() { *x = ClearDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[176] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11610,7 +12392,7 @@ func (x *ClearDraftChunksResponse) String() string { func (*ClearDraftChunksResponse) ProtoMessage() {} func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[176] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11623,7 +12405,7 @@ func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ClearDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{162} + return file_openshell_proto_rawDescGZIP(), []int{176} } func (x *ClearDraftChunksResponse) GetChunksCleared() uint32 { @@ -11646,7 +12428,7 @@ type GetDraftHistoryRequest struct { func (x *GetDraftHistoryRequest) Reset() { *x = GetDraftHistoryRequest{} - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[177] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11658,7 +12440,7 @@ func (x *GetDraftHistoryRequest) String() string { func (*GetDraftHistoryRequest) ProtoMessage() {} func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[177] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11671,7 +12453,7 @@ func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryRequest.ProtoReflect.Descriptor instead. func (*GetDraftHistoryRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{163} + return file_openshell_proto_rawDescGZIP(), []int{177} } func (x *GetDraftHistoryRequest) GetName() string { @@ -11705,7 +12487,7 @@ type DraftHistoryEntry struct { func (x *DraftHistoryEntry) Reset() { *x = DraftHistoryEntry{} - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[178] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11717,7 +12499,7 @@ func (x *DraftHistoryEntry) String() string { func (*DraftHistoryEntry) ProtoMessage() {} func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[178] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11730,7 +12512,7 @@ func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftHistoryEntry.ProtoReflect.Descriptor instead. func (*DraftHistoryEntry) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{164} + return file_openshell_proto_rawDescGZIP(), []int{178} } func (x *DraftHistoryEntry) GetTimestampMs() int64 { @@ -11771,7 +12553,7 @@ type GetDraftHistoryResponse struct { func (x *GetDraftHistoryResponse) Reset() { *x = GetDraftHistoryResponse{} - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[179] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11783,7 +12565,7 @@ func (x *GetDraftHistoryResponse) String() string { func (*GetDraftHistoryResponse) ProtoMessage() {} func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[179] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11796,7 +12578,7 @@ func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryResponse.ProtoReflect.Descriptor instead. func (*GetDraftHistoryResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{165} + return file_openshell_proto_rawDescGZIP(), []int{179} } func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry { @@ -11825,7 +12607,7 @@ type PolicyRevisionPayload struct { func (x *PolicyRevisionPayload) Reset() { *x = PolicyRevisionPayload{} - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[180] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11837,7 +12619,7 @@ func (x *PolicyRevisionPayload) String() string { func (*PolicyRevisionPayload) ProtoMessage() {} func (x *PolicyRevisionPayload) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[180] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11850,7 +12632,7 @@ func (x *PolicyRevisionPayload) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyRevisionPayload.ProtoReflect.Descriptor instead. func (*PolicyRevisionPayload) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{166} + return file_openshell_proto_rawDescGZIP(), []int{180} } func (x *PolicyRevisionPayload) GetPolicy() *sandboxv1.SandboxPolicy { @@ -11923,7 +12705,7 @@ type DraftChunkPayload struct { func (x *DraftChunkPayload) Reset() { *x = DraftChunkPayload{} - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[181] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11935,7 +12717,7 @@ func (x *DraftChunkPayload) String() string { func (*DraftChunkPayload) ProtoMessage() {} func (x *DraftChunkPayload) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[181] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11948,7 +12730,7 @@ func (x *DraftChunkPayload) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftChunkPayload.ProtoReflect.Descriptor instead. func (*DraftChunkPayload) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{167} + return file_openshell_proto_rawDescGZIP(), []int{181} } func (x *DraftChunkPayload) GetRuleName() string { @@ -12054,7 +12836,7 @@ type StoredPolicyRevision struct { func (x *StoredPolicyRevision) Reset() { *x = StoredPolicyRevision{} - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[182] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12066,7 +12848,7 @@ func (x *StoredPolicyRevision) String() string { func (*StoredPolicyRevision) ProtoMessage() {} func (x *StoredPolicyRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[182] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12079,7 +12861,7 @@ func (x *StoredPolicyRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use StoredPolicyRevision.ProtoReflect.Descriptor instead. func (*StoredPolicyRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{168} + return file_openshell_proto_rawDescGZIP(), []int{182} } func (x *StoredPolicyRevision) GetId() string { @@ -12182,7 +12964,7 @@ type StoredDraftChunk struct { func (x *StoredDraftChunk) Reset() { *x = StoredDraftChunk{} - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[183] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12194,7 +12976,7 @@ func (x *StoredDraftChunk) String() string { func (*StoredDraftChunk) ProtoMessage() {} func (x *StoredDraftChunk) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[183] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12207,7 +12989,7 @@ func (x *StoredDraftChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use StoredDraftChunk.ProtoReflect.Descriptor instead. func (*StoredDraftChunk) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{169} + return file_openshell_proto_rawDescGZIP(), []int{183} } func (x *StoredDraftChunk) GetId() string { @@ -12356,7 +13138,7 @@ type CreateWorkspaceRequest struct { func (x *CreateWorkspaceRequest) Reset() { *x = CreateWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[184] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12368,7 +13150,7 @@ func (x *CreateWorkspaceRequest) String() string { func (*CreateWorkspaceRequest) ProtoMessage() {} func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[184] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12381,7 +13163,7 @@ func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceRequest.ProtoReflect.Descriptor instead. func (*CreateWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{170} + return file_openshell_proto_rawDescGZIP(), []int{184} } func (x *CreateWorkspaceRequest) GetName() string { @@ -12408,7 +13190,7 @@ type CreateWorkspaceResponse struct { func (x *CreateWorkspaceResponse) Reset() { *x = CreateWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[185] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12420,7 +13202,7 @@ func (x *CreateWorkspaceResponse) String() string { func (*CreateWorkspaceResponse) ProtoMessage() {} func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[185] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12433,7 +13215,7 @@ func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceResponse.ProtoReflect.Descriptor instead. func (*CreateWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{171} + return file_openshell_proto_rawDescGZIP(), []int{185} } func (x *CreateWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -12454,7 +13236,7 @@ type GetWorkspaceRequest struct { func (x *GetWorkspaceRequest) Reset() { *x = GetWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[186] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12466,7 +13248,7 @@ func (x *GetWorkspaceRequest) String() string { func (*GetWorkspaceRequest) ProtoMessage() {} func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[186] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12479,7 +13261,7 @@ func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceRequest.ProtoReflect.Descriptor instead. func (*GetWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{172} + return file_openshell_proto_rawDescGZIP(), []int{186} } func (x *GetWorkspaceRequest) GetName() string { @@ -12499,7 +13281,7 @@ type GetWorkspaceResponse struct { func (x *GetWorkspaceResponse) Reset() { *x = GetWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[187] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12511,7 +13293,7 @@ func (x *GetWorkspaceResponse) String() string { func (*GetWorkspaceResponse) ProtoMessage() {} func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[187] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12524,7 +13306,7 @@ func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceResponse.ProtoReflect.Descriptor instead. func (*GetWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{173} + return file_openshell_proto_rawDescGZIP(), []int{187} } func (x *GetWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -12547,7 +13329,7 @@ type ListWorkspacesRequest struct { func (x *ListWorkspacesRequest) Reset() { *x = ListWorkspacesRequest{} - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[188] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12559,7 +13341,7 @@ func (x *ListWorkspacesRequest) String() string { func (*ListWorkspacesRequest) ProtoMessage() {} func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[188] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12572,7 +13354,7 @@ func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesRequest.ProtoReflect.Descriptor instead. func (*ListWorkspacesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{174} + return file_openshell_proto_rawDescGZIP(), []int{188} } func (x *ListWorkspacesRequest) GetLimit() uint32 { @@ -12606,7 +13388,7 @@ type ListWorkspacesResponse struct { func (x *ListWorkspacesResponse) Reset() { *x = ListWorkspacesResponse{} - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[189] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12618,7 +13400,7 @@ func (x *ListWorkspacesResponse) String() string { func (*ListWorkspacesResponse) ProtoMessage() {} func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[189] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12631,7 +13413,7 @@ func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesResponse.ProtoReflect.Descriptor instead. func (*ListWorkspacesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{175} + return file_openshell_proto_rawDescGZIP(), []int{189} } func (x *ListWorkspacesResponse) GetWorkspaces() []*datamodelv1.Workspace { @@ -12652,7 +13434,7 @@ type DeleteWorkspaceRequest struct { func (x *DeleteWorkspaceRequest) Reset() { *x = DeleteWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[190] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12664,7 +13446,7 @@ func (x *DeleteWorkspaceRequest) String() string { func (*DeleteWorkspaceRequest) ProtoMessage() {} func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[190] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12677,7 +13459,7 @@ func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{176} + return file_openshell_proto_rawDescGZIP(), []int{190} } func (x *DeleteWorkspaceRequest) GetName() string { @@ -12697,7 +13479,7 @@ type DeleteWorkspaceResponse struct { func (x *DeleteWorkspaceResponse) Reset() { *x = DeleteWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[191] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12709,7 +13491,7 @@ func (x *DeleteWorkspaceResponse) String() string { func (*DeleteWorkspaceResponse) ProtoMessage() {} func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[191] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12722,7 +13504,7 @@ func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceResponse.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{177} + return file_openshell_proto_rawDescGZIP(), []int{191} } func (x *DeleteWorkspaceResponse) GetDeleted() bool { @@ -12746,7 +13528,7 @@ type WorkspaceMember struct { func (x *WorkspaceMember) Reset() { *x = WorkspaceMember{} - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[192] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12758,7 +13540,7 @@ func (x *WorkspaceMember) String() string { func (*WorkspaceMember) ProtoMessage() {} func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[192] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12771,7 +13553,7 @@ func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkspaceMember.ProtoReflect.Descriptor instead. func (*WorkspaceMember) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{178} + return file_openshell_proto_rawDescGZIP(), []int{192} } func (x *WorkspaceMember) GetMetadata() *datamodelv1.ObjectMeta { @@ -12810,7 +13592,7 @@ type AddWorkspaceMemberRequest struct { func (x *AddWorkspaceMemberRequest) Reset() { *x = AddWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12822,7 +13604,7 @@ func (x *AddWorkspaceMemberRequest) String() string { func (*AddWorkspaceMemberRequest) ProtoMessage() {} func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[193] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12835,7 +13617,7 @@ func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{179} + return file_openshell_proto_rawDescGZIP(), []int{193} } func (x *AddWorkspaceMemberRequest) GetWorkspace() string { @@ -12869,7 +13651,7 @@ type AddWorkspaceMemberResponse struct { func (x *AddWorkspaceMemberResponse) Reset() { *x = AddWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12881,7 +13663,7 @@ func (x *AddWorkspaceMemberResponse) String() string { func (*AddWorkspaceMemberResponse) ProtoMessage() {} func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[194] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12894,7 +13676,7 @@ func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{180} + return file_openshell_proto_rawDescGZIP(), []int{194} } func (x *AddWorkspaceMemberResponse) GetMember() *WorkspaceMember { @@ -12917,7 +13699,7 @@ type RemoveWorkspaceMemberRequest struct { func (x *RemoveWorkspaceMemberRequest) Reset() { *x = RemoveWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12929,7 +13711,7 @@ func (x *RemoveWorkspaceMemberRequest) String() string { func (*RemoveWorkspaceMemberRequest) ProtoMessage() {} func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[195] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12942,7 +13724,7 @@ func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{181} + return file_openshell_proto_rawDescGZIP(), []int{195} } func (x *RemoveWorkspaceMemberRequest) GetWorkspace() string { @@ -12969,7 +13751,7 @@ type RemoveWorkspaceMemberResponse struct { func (x *RemoveWorkspaceMemberResponse) Reset() { *x = RemoveWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12981,7 +13763,7 @@ func (x *RemoveWorkspaceMemberResponse) String() string { func (*RemoveWorkspaceMemberResponse) ProtoMessage() {} func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[196] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12994,7 +13776,7 @@ func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{182} + return file_openshell_proto_rawDescGZIP(), []int{196} } func (x *RemoveWorkspaceMemberResponse) GetRemoved() bool { @@ -13017,7 +13799,7 @@ type ListWorkspaceMembersRequest struct { func (x *ListWorkspaceMembersRequest) Reset() { *x = ListWorkspaceMembersRequest{} - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13029,7 +13811,7 @@ func (x *ListWorkspaceMembersRequest) String() string { func (*ListWorkspaceMembersRequest) ProtoMessage() {} func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[197] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13042,7 +13824,7 @@ func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersRequest.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{183} + return file_openshell_proto_rawDescGZIP(), []int{197} } func (x *ListWorkspaceMembersRequest) GetWorkspace() string { @@ -13076,7 +13858,7 @@ type ListWorkspaceMembersResponse struct { func (x *ListWorkspaceMembersResponse) Reset() { *x = ListWorkspaceMembersResponse{} - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13088,7 +13870,7 @@ func (x *ListWorkspaceMembersResponse) String() string { func (*ListWorkspaceMembersResponse) ProtoMessage() {} func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[198] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13101,7 +13883,7 @@ func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersResponse.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{184} + return file_openshell_proto_rawDescGZIP(), []int{198} } func (x *ListWorkspaceMembersResponse) GetMembers() []*WorkspaceMember { @@ -13129,7 +13911,7 @@ type ExtensionServiceCredential struct { func (x *ExtensionServiceCredential) Reset() { *x = ExtensionServiceCredential{} - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13141,7 +13923,7 @@ func (x *ExtensionServiceCredential) String() string { func (*ExtensionServiceCredential) ProtoMessage() {} func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[199] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13154,7 +13936,7 @@ func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionServiceCredential.ProtoReflect.Descriptor instead. func (*ExtensionServiceCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{185} + return file_openshell_proto_rawDescGZIP(), []int{199} } func (x *ExtensionServiceCredential) GetServiceName() string { @@ -13182,7 +13964,7 @@ var File_openshell_proto protoreflect.FileDescriptor const file_openshell_proto_rawDesc = "" + "\n" + - "\x0fopenshell.proto\x12\fopenshell.v1\x1a\x0fdatamodel.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\roptions.proto\x1a\rsandbox.proto\"\x1a\n" + + "\x0fopenshell.proto\x12\fopenshell.v1\x1a\x0fdatamodel.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\roptions.proto\x1a\rsandbox.proto\"\x1a\n" + "\x18IssueSandboxTokenRequest\"[\n" + "\x19IssueSandboxTokenResponse\x12\x1a\n" + "\x05token\x18\x01 \x01(\tB\x04\x88\xb5\x18\x01R\x05token\x12\"\n" + @@ -13215,11 +13997,12 @@ const file_openshell_proto_rawDesc = "" + "\x19ComputeDriverCapabilities\x12\x1f\n" + "\vdriver_name\x18\x01 \x01(\tR\n" + "driverName\x12%\n" + - "\x0edriver_version\x18\x02 \x01(\tR\rdriverVersion\"\xd8\x01\n" + + "\x0edriver_version\x18\x02 \x01(\tR\rdriverVersion\"\xce\x02\n" + "\aSandbox\x12>\n" + "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x12-\n" + "\x04spec\x18\x02 \x01(\v2\x19.openshell.v1.SandboxSpecR\x04spec\x123\n" + - "\x06status\x18\x03 \x01(\v2\x1b.openshell.v1.SandboxStatusR\x06statusJ\x04\b\x04\x10\x05J\x04\b\x05\x10\x06R\x05phaseR\x16current_policy_version\"\xd7\x03\n" + + "\x06status\x18\x03 \x01(\v2\x1b.openshell.v1.SandboxStatusR\x06status\x12t\n" + + "\x1ecreated_from_workload_template\x18\x14 \x01(\v2/.openshell.v1.SandboxWorkloadTemplateProvenanceR\x1bcreatedFromWorkloadTemplateJ\x04\b\x04\x10\x05J\x04\b\x05\x10\x06R\x05phaseR\x16current_policy_version\"\xd7\x03\n" + "\vSandboxSpec\x12\x1b\n" + "\tlog_level\x18\x01 \x01(\tR\blogLevel\x12L\n" + "\venvironment\x18\x05 \x03(\v2*.openshell.v1.SandboxSpec.EnvironmentEntryR\venvironment\x129\n" + @@ -13258,7 +14041,35 @@ const file_openshell_proto_rawDesc = "" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x12\n" + "\x10_user_namespacesJ\x04\b\t\x10\n" + - "R\x16volume_claim_templates\"\xb1\x02\n" + + "R\x16volume_claim_templates\"\x98\x01\n" + + "\x17SandboxWorkloadTemplate\x12>\n" + + "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x12=\n" + + "\x04spec\x18\x02 \x01(\v2).openshell.v1.SandboxWorkloadTemplateSpecR\x04spec\"\xf3\x01\n" + + "\x1bSandboxWorkloadTemplateSpec\x12?\n" + + "\bworkload\x18\x01 \x01(\v2#.openshell.v1.SandboxWorkloadConfigR\bworkload\x12<\n" + + "\rdriver_config\x18\x02 \x01(\v2\x17.google.protobuf.StructR\fdriverConfig\x12U\n" + + "\x15desired_service_level\x18\x03 \x01(\v2!.openshell.v1.SandboxServiceLevelR\x13desiredServiceLevel\"\x83\x02\n" + + "\x15SandboxWorkloadConfig\x12\x14\n" + + "\x05image\x18\x01 \x01(\tR\x05image\x12V\n" + + "\venvironment\x18\x02 \x03(\v24.openshell.v1.SandboxWorkloadConfig.EnvironmentEntryR\venvironment\x12<\n" + + "\tresources\x18\x03 \x01(\v2\x1e.openshell.v1.SandboxResourcesR\tresources\x1a>\n" + + "\x10EnvironmentEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"l\n" + + "\x10SandboxResources\x12\x10\n" + + "\x03cpu\x18\x01 \x01(\tR\x03cpu\x12\x16\n" + + "\x06memory\x18\x02 \x01(\tR\x06memory\x12 \n" + + "\tgpu_count\x18\x03 \x01(\rH\x00R\bgpuCount\x88\x01\x01B\f\n" + + "\n" + + "_gpu_count\"M\n" + + "\x13SandboxServiceLevel\x126\n" + + "\astartup\x18\x01 \x01(\v2\x1c.openshell.v1.SandboxStartupR\astartup\"k\n" + + "\x0eSandboxStartup\x12<\n" + + "\fready_within\x18\x01 \x01(\v2\x19.google.protobuf.DurationR\vreadyWithin\x12\x1b\n" + + "\tmax_burst\x18\x02 \x01(\rR\bmaxBurst\"b\n" + + "!SandboxWorkloadTemplateProvenance\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12)\n" + + "\x10resource_version\x18\x02 \x01(\tR\x0fresourceVersion\"\xb1\x02\n" + "\rSandboxStatus\x12!\n" + "\fsandbox_name\x18\x01 \x01(\tR\vsandboxName\x12\x1b\n" + "\tagent_pod\x18\x02 \x01(\tR\bagentPod\x12\x19\n" + @@ -13285,19 +14096,40 @@ const file_openshell_proto_rawDesc = "" + "\bmetadata\x18\x06 \x03(\v2).openshell.v1.PlatformEvent.MetadataEntryR\bmetadata\x1a;\n" + "\rMetadataEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x91\x03\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xc7\x03\n" + "\x14CreateSandboxRequest\x12-\n" + "\x04spec\x18\x01 \x01(\v2\x19.openshell.v1.SandboxSpecR\x04spec\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12F\n" + "\x06labels\x18\x03 \x03(\v2..openshell.v1.CreateSandboxRequest.LabelsEntryR\x06labels\x12U\n" + "\vannotations\x18\x04 \x03(\v23.openshell.v1.CreateSandboxRequest.AnnotationsEntryR\vannotations\x12\x1c\n" + - "\tworkspace\x18\x05 \x01(\tR\tworkspace\x1a9\n" + + "\tworkspace\x18\x05 \x01(\tR\tworkspace\x124\n" + + "\x16workload_template_name\x18\x06 \x01(\tR\x14workloadTemplateName\x1a9\n" + "\vLabelsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a>\n" + "\x10AnnotationsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"E\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x7f\n" + + "\x1cCreateSandboxTemplateRequest\x12A\n" + + "\btemplate\x18\x01 \x01(\v2%.openshell.v1.SandboxWorkloadTemplateR\btemplate\x12\x1c\n" + + "\tworkspace\x18\x02 \x01(\tR\tworkspace\"M\n" + + "\x19GetSandboxTemplateRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" + + "\tworkspace\x18\x02 \x01(\tR\tworkspace\"\x90\x01\n" + + "\x1bListSandboxTemplatesRequest\x12\x14\n" + + "\x05limit\x18\x01 \x01(\rR\x05limit\x12\x16\n" + + "\x06offset\x18\x02 \x01(\rR\x06offset\x12\x1c\n" + + "\tworkspace\x18\x03 \x01(\tR\tworkspace\x12%\n" + + "\x0eall_workspaces\x18\x04 \x01(\bR\rallWorkspaces\"P\n" + + "\x1cDeleteSandboxTemplateRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" + + "\tworkspace\x18\x02 \x01(\tR\tworkspace\"\\\n" + + "\x17SandboxTemplateResponse\x12A\n" + + "\btemplate\x18\x01 \x01(\v2%.openshell.v1.SandboxWorkloadTemplateR\btemplate\"c\n" + + "\x1cListSandboxTemplatesResponse\x12C\n" + + "\ttemplates\x18\x01 \x03(\v2%.openshell.v1.SandboxWorkloadTemplateR\ttemplates\"9\n" + + "\x1dDeleteSandboxTemplateResponse\x12\x18\n" + + "\adeleted\x18\x01 \x01(\bR\adeleted\"E\n" + "\x11GetSandboxRequest\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" + "\tworkspace\x18\x02 \x01(\tR\tworkspace\"\xb0\x01\n" + @@ -14227,7 +15059,7 @@ const file_openshell_proto_rawDesc = "" + "\rWorkspaceRole\x12\x1e\n" + "\x1aWORKSPACE_ROLE_UNSPECIFIED\x10\x00\x12\x17\n" + "\x13WORKSPACE_ROLE_USER\x10\x01\x12\x18\n" + - "\x14WORKSPACE_ROLE_ADMIN\x10\x022\x94D\n" + + "\x14WORKSPACE_ROLE_ADMIN\x10\x022\xd7H\n" + "\tOpenShell\x12Z\n" + "\x06Health\x12\x1b.openshell.v1.HealthRequest\x1a\x1c.openshell.v1.HealthResponse\"\x15\x82\xb5\x18\x11\n" + "\x0funauthenticated\x12i\n" + @@ -14241,7 +15073,15 @@ const file_openshell_proto_rawDesc = "" + "GetSandbox\x12\x1f.openshell.v1.GetSandboxRequest\x1a\x1d.openshell.v1.SandboxResponse\" \x82\xb5\x18\x1c\n" + "\x06bearer\x12\x04user\"\fsandbox:read\x12z\n" + "\rListSandboxes\x12\".openshell.v1.ListSandboxesRequest\x1a#.openshell.v1.ListSandboxesResponse\" \x82\xb5\x18\x1c\n" + + "\x06bearer\x12\x04user\"\fsandbox:read\x12\x8e\x01\n" + + "\x15CreateSandboxTemplate\x12*.openshell.v1.CreateSandboxTemplateRequest\x1a%.openshell.v1.SandboxTemplateResponse\"\"\x82\xb5\x18\x1e\n" + + "\x06bearer\x12\x05admin\"\rsandbox:write\x12\x86\x01\n" + + "\x12GetSandboxTemplate\x12'.openshell.v1.GetSandboxTemplateRequest\x1a%.openshell.v1.SandboxTemplateResponse\" \x82\xb5\x18\x1c\n" + "\x06bearer\x12\x04user\"\fsandbox:read\x12\x8f\x01\n" + + "\x14ListSandboxTemplates\x12).openshell.v1.ListSandboxTemplatesRequest\x1a*.openshell.v1.ListSandboxTemplatesResponse\" \x82\xb5\x18\x1c\n" + + "\x06bearer\x12\x04user\"\fsandbox:read\x12\x94\x01\n" + + "\x15DeleteSandboxTemplate\x12*.openshell.v1.DeleteSandboxTemplateRequest\x1a+.openshell.v1.DeleteSandboxTemplateResponse\"\"\x82\xb5\x18\x1e\n" + + "\x06bearer\x12\x05admin\"\rsandbox:write\x12\x8f\x01\n" + "\x14ListSandboxProviders\x12).openshell.v1.ListSandboxProvidersRequest\x1a*.openshell.v1.ListSandboxProvidersResponse\" \x82\xb5\x18\x1c\n" + "\x06bearer\x12\x04user\"\fsandbox:read\x12\x93\x01\n" + "\x15AttachSandboxProvider\x12*.openshell.v1.AttachSandboxProviderRequest\x1a+.openshell.v1.AttachSandboxProviderResponse\"!\x82\xb5\x18\x1d\n" + @@ -14378,7 +15218,7 @@ func file_openshell_proto_rawDescGZIP() []byte { } var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 211) +var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 226) var file_openshell_proto_goTypes = []any{ (SandboxPhase)(0), // 0: openshell.v1.SandboxPhase (ProviderCredentialRefreshStrategy)(0), // 1: openshell.v1.ProviderCredentialRefreshStrategy @@ -14403,510 +15243,547 @@ var file_openshell_proto_goTypes = []any{ (*ResourceRequirements)(nil), // 20: openshell.v1.ResourceRequirements (*GpuResourceRequirements)(nil), // 21: openshell.v1.GpuResourceRequirements (*SandboxTemplate)(nil), // 22: openshell.v1.SandboxTemplate - (*SandboxStatus)(nil), // 23: openshell.v1.SandboxStatus - (*SandboxCondition)(nil), // 24: openshell.v1.SandboxCondition - (*PlatformEvent)(nil), // 25: openshell.v1.PlatformEvent - (*CreateSandboxRequest)(nil), // 26: openshell.v1.CreateSandboxRequest - (*GetSandboxRequest)(nil), // 27: openshell.v1.GetSandboxRequest - (*ListSandboxesRequest)(nil), // 28: openshell.v1.ListSandboxesRequest - (*ListSandboxProvidersRequest)(nil), // 29: openshell.v1.ListSandboxProvidersRequest - (*AttachSandboxProviderRequest)(nil), // 30: openshell.v1.AttachSandboxProviderRequest - (*DetachSandboxProviderRequest)(nil), // 31: openshell.v1.DetachSandboxProviderRequest - (*DeleteSandboxRequest)(nil), // 32: openshell.v1.DeleteSandboxRequest - (*StopSandboxRequest)(nil), // 33: openshell.v1.StopSandboxRequest - (*StartSandboxRequest)(nil), // 34: openshell.v1.StartSandboxRequest - (*SandboxResponse)(nil), // 35: openshell.v1.SandboxResponse - (*ListSandboxesResponse)(nil), // 36: openshell.v1.ListSandboxesResponse - (*ListSandboxProvidersResponse)(nil), // 37: openshell.v1.ListSandboxProvidersResponse - (*AttachSandboxProviderResponse)(nil), // 38: openshell.v1.AttachSandboxProviderResponse - (*DetachSandboxProviderResponse)(nil), // 39: openshell.v1.DetachSandboxProviderResponse - (*DeleteSandboxResponse)(nil), // 40: openshell.v1.DeleteSandboxResponse - (*CreateSshSessionRequest)(nil), // 41: openshell.v1.CreateSshSessionRequest - (*CreateSshSessionResponse)(nil), // 42: openshell.v1.CreateSshSessionResponse - (*ExposeServiceRequest)(nil), // 43: openshell.v1.ExposeServiceRequest - (*GetServiceRequest)(nil), // 44: openshell.v1.GetServiceRequest - (*ListServicesRequest)(nil), // 45: openshell.v1.ListServicesRequest - (*ListServicesResponse)(nil), // 46: openshell.v1.ListServicesResponse - (*DeleteServiceRequest)(nil), // 47: openshell.v1.DeleteServiceRequest - (*DeleteServiceResponse)(nil), // 48: openshell.v1.DeleteServiceResponse - (*ServiceEndpoint)(nil), // 49: openshell.v1.ServiceEndpoint - (*ServiceEndpointResponse)(nil), // 50: openshell.v1.ServiceEndpointResponse - (*RevokeSshSessionRequest)(nil), // 51: openshell.v1.RevokeSshSessionRequest - (*RevokeSshSessionResponse)(nil), // 52: openshell.v1.RevokeSshSessionResponse - (*ExecSandboxRequest)(nil), // 53: openshell.v1.ExecSandboxRequest - (*ExecSandboxStdout)(nil), // 54: openshell.v1.ExecSandboxStdout - (*ExecSandboxStderr)(nil), // 55: openshell.v1.ExecSandboxStderr - (*ExecSandboxExit)(nil), // 56: openshell.v1.ExecSandboxExit - (*ExecSandboxEvent)(nil), // 57: openshell.v1.ExecSandboxEvent - (*TcpForwardInit)(nil), // 58: openshell.v1.TcpForwardInit - (*TcpForwardFrame)(nil), // 59: openshell.v1.TcpForwardFrame - (*ExecSandboxInput)(nil), // 60: openshell.v1.ExecSandboxInput - (*ExecSandboxWindowResize)(nil), // 61: openshell.v1.ExecSandboxWindowResize - (*SshSession)(nil), // 62: openshell.v1.SshSession - (*WatchSandboxRequest)(nil), // 63: openshell.v1.WatchSandboxRequest - (*SandboxStreamEvent)(nil), // 64: openshell.v1.SandboxStreamEvent - (*SandboxLogLine)(nil), // 65: openshell.v1.SandboxLogLine - (*SandboxStreamWarning)(nil), // 66: openshell.v1.SandboxStreamWarning - (*CreateProviderRequest)(nil), // 67: openshell.v1.CreateProviderRequest - (*GetProviderRequest)(nil), // 68: openshell.v1.GetProviderRequest - (*ListProvidersRequest)(nil), // 69: openshell.v1.ListProvidersRequest - (*UpdateProviderRequest)(nil), // 70: openshell.v1.UpdateProviderRequest - (*DeleteProviderRequest)(nil), // 71: openshell.v1.DeleteProviderRequest - (*ProviderResponse)(nil), // 72: openshell.v1.ProviderResponse - (*ListProvidersResponse)(nil), // 73: openshell.v1.ListProvidersResponse - (*ListProviderProfilesRequest)(nil), // 74: openshell.v1.ListProviderProfilesRequest - (*GetProviderProfileRequest)(nil), // 75: openshell.v1.GetProviderProfileRequest - (*ProviderProfileImportItem)(nil), // 76: openshell.v1.ProviderProfileImportItem - (*ProviderProfileDiagnostic)(nil), // 77: openshell.v1.ProviderProfileDiagnostic - (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 78: openshell.v1.ProviderCredentialTokenGrantAudienceOverride - (*ProviderCredentialTokenGrant)(nil), // 79: openshell.v1.ProviderCredentialTokenGrant - (*ProviderProfileCredential)(nil), // 80: openshell.v1.ProviderProfileCredential - (*ProviderCredentialRefreshMaterial)(nil), // 81: openshell.v1.ProviderCredentialRefreshMaterial - (*ProviderCredentialRefreshOutput)(nil), // 82: openshell.v1.ProviderCredentialRefreshOutput - (*ProviderCredentialRefresh)(nil), // 83: openshell.v1.ProviderCredentialRefresh - (*ProviderCredentialRefreshStatus)(nil), // 84: openshell.v1.ProviderCredentialRefreshStatus - (*ProviderProfileDiscovery)(nil), // 85: openshell.v1.ProviderProfileDiscovery - (*StoredProviderCredentialRefreshState)(nil), // 86: openshell.v1.StoredProviderCredentialRefreshState - (*StoredRefreshMaterialDeletion)(nil), // 87: openshell.v1.StoredRefreshMaterialDeletion - (*GetProviderRefreshStatusRequest)(nil), // 88: openshell.v1.GetProviderRefreshStatusRequest - (*GetProviderRefreshStatusResponse)(nil), // 89: openshell.v1.GetProviderRefreshStatusResponse - (*ConfigureProviderRefreshRequest)(nil), // 90: openshell.v1.ConfigureProviderRefreshRequest - (*ConfigureProviderRefreshResponse)(nil), // 91: openshell.v1.ConfigureProviderRefreshResponse - (*RotateProviderCredentialRequest)(nil), // 92: openshell.v1.RotateProviderCredentialRequest - (*RotateProviderCredentialResponse)(nil), // 93: openshell.v1.RotateProviderCredentialResponse - (*DeleteProviderRefreshRequest)(nil), // 94: openshell.v1.DeleteProviderRefreshRequest - (*DeleteProviderRefreshResponse)(nil), // 95: openshell.v1.DeleteProviderRefreshResponse - (*ProviderProfile)(nil), // 96: openshell.v1.ProviderProfile - (*StoredProviderProfile)(nil), // 97: openshell.v1.StoredProviderProfile - (*ProviderProfileResponse)(nil), // 98: openshell.v1.ProviderProfileResponse - (*ListProviderProfilesResponse)(nil), // 99: openshell.v1.ListProviderProfilesResponse - (*ImportProviderProfilesRequest)(nil), // 100: openshell.v1.ImportProviderProfilesRequest - (*ImportProviderProfilesResponse)(nil), // 101: openshell.v1.ImportProviderProfilesResponse - (*UpdateProviderProfilesRequest)(nil), // 102: openshell.v1.UpdateProviderProfilesRequest - (*UpdateProviderProfilesResponse)(nil), // 103: openshell.v1.UpdateProviderProfilesResponse - (*LintProviderProfilesRequest)(nil), // 104: openshell.v1.LintProviderProfilesRequest - (*LintProviderProfilesResponse)(nil), // 105: openshell.v1.LintProviderProfilesResponse - (*DeleteProviderResponse)(nil), // 106: openshell.v1.DeleteProviderResponse - (*DeleteProviderProfileRequest)(nil), // 107: openshell.v1.DeleteProviderProfileRequest - (*DeleteProviderProfileResponse)(nil), // 108: openshell.v1.DeleteProviderProfileResponse - (*GetSandboxProviderEnvironmentRequest)(nil), // 109: openshell.v1.GetSandboxProviderEnvironmentRequest - (*StaticCredentialEndpointBinding)(nil), // 110: openshell.v1.StaticCredentialEndpointBinding - (*StaticCredentialBinding)(nil), // 111: openshell.v1.StaticCredentialBinding - (*GetSandboxProviderEnvironmentResponse)(nil), // 112: openshell.v1.GetSandboxProviderEnvironmentResponse - (*UpdateConfigRequest)(nil), // 113: openshell.v1.UpdateConfigRequest - (*PolicyMergeOperation)(nil), // 114: openshell.v1.PolicyMergeOperation - (*AddNetworkRule)(nil), // 115: openshell.v1.AddNetworkRule - (*RemoveNetworkEndpoint)(nil), // 116: openshell.v1.RemoveNetworkEndpoint - (*RemoveNetworkRule)(nil), // 117: openshell.v1.RemoveNetworkRule - (*AddDenyRules)(nil), // 118: openshell.v1.AddDenyRules - (*AddAllowRules)(nil), // 119: openshell.v1.AddAllowRules - (*RemoveNetworkBinary)(nil), // 120: openshell.v1.RemoveNetworkBinary - (*UpdateConfigResponse)(nil), // 121: openshell.v1.UpdateConfigResponse - (*GetSandboxPolicyStatusRequest)(nil), // 122: openshell.v1.GetSandboxPolicyStatusRequest - (*GetSandboxPolicyStatusResponse)(nil), // 123: openshell.v1.GetSandboxPolicyStatusResponse - (*ListSandboxPoliciesRequest)(nil), // 124: openshell.v1.ListSandboxPoliciesRequest - (*ListSandboxPoliciesResponse)(nil), // 125: openshell.v1.ListSandboxPoliciesResponse - (*ReportPolicyStatusRequest)(nil), // 126: openshell.v1.ReportPolicyStatusRequest - (*ReportPolicyStatusResponse)(nil), // 127: openshell.v1.ReportPolicyStatusResponse - (*SandboxPolicyRevision)(nil), // 128: openshell.v1.SandboxPolicyRevision - (*GetSandboxLogsRequest)(nil), // 129: openshell.v1.GetSandboxLogsRequest - (*PushSandboxLogsRequest)(nil), // 130: openshell.v1.PushSandboxLogsRequest - (*PushSandboxLogsResponse)(nil), // 131: openshell.v1.PushSandboxLogsResponse - (*GetSandboxLogsResponse)(nil), // 132: openshell.v1.GetSandboxLogsResponse - (*SupervisorMessage)(nil), // 133: openshell.v1.SupervisorMessage - (*GatewayMessage)(nil), // 134: openshell.v1.GatewayMessage - (*SupervisorHello)(nil), // 135: openshell.v1.SupervisorHello - (*SessionAccepted)(nil), // 136: openshell.v1.SessionAccepted - (*SessionRejected)(nil), // 137: openshell.v1.SessionRejected - (*SupervisorHeartbeat)(nil), // 138: openshell.v1.SupervisorHeartbeat - (*GatewayHeartbeat)(nil), // 139: openshell.v1.GatewayHeartbeat - (*RelayOpen)(nil), // 140: openshell.v1.RelayOpen - (*SshRelayTarget)(nil), // 141: openshell.v1.SshRelayTarget - (*TcpRelayTarget)(nil), // 142: openshell.v1.TcpRelayTarget - (*RelayInit)(nil), // 143: openshell.v1.RelayInit - (*RelayFrame)(nil), // 144: openshell.v1.RelayFrame - (*RelayOpenResult)(nil), // 145: openshell.v1.RelayOpenResult - (*RelayClose)(nil), // 146: openshell.v1.RelayClose - (*L7RequestSample)(nil), // 147: openshell.v1.L7RequestSample - (*DenialSummary)(nil), // 148: openshell.v1.DenialSummary - (*DenialGroupCount)(nil), // 149: openshell.v1.DenialGroupCount - (*NetworkActivitySummary)(nil), // 150: openshell.v1.NetworkActivitySummary - (*PolicyChunk)(nil), // 151: openshell.v1.PolicyChunk - (*DraftPolicyUpdate)(nil), // 152: openshell.v1.DraftPolicyUpdate - (*SubmitPolicyAnalysisRequest)(nil), // 153: openshell.v1.SubmitPolicyAnalysisRequest - (*SubmitPolicyAnalysisResponse)(nil), // 154: openshell.v1.SubmitPolicyAnalysisResponse - (*GetDraftPolicyRequest)(nil), // 155: openshell.v1.GetDraftPolicyRequest - (*GetDraftPolicyResponse)(nil), // 156: openshell.v1.GetDraftPolicyResponse - (*ApproveDraftChunkRequest)(nil), // 157: openshell.v1.ApproveDraftChunkRequest - (*ApproveDraftChunkResponse)(nil), // 158: openshell.v1.ApproveDraftChunkResponse - (*RejectDraftChunkRequest)(nil), // 159: openshell.v1.RejectDraftChunkRequest - (*RejectDraftChunkResponse)(nil), // 160: openshell.v1.RejectDraftChunkResponse - (*ApproveAllDraftChunksRequest)(nil), // 161: openshell.v1.ApproveAllDraftChunksRequest - (*ApproveAllDraftChunksResponse)(nil), // 162: openshell.v1.ApproveAllDraftChunksResponse - (*EditDraftChunkRequest)(nil), // 163: openshell.v1.EditDraftChunkRequest - (*EditDraftChunkResponse)(nil), // 164: openshell.v1.EditDraftChunkResponse - (*UndoDraftChunkRequest)(nil), // 165: openshell.v1.UndoDraftChunkRequest - (*UndoDraftChunkResponse)(nil), // 166: openshell.v1.UndoDraftChunkResponse - (*ClearDraftChunksRequest)(nil), // 167: openshell.v1.ClearDraftChunksRequest - (*ClearDraftChunksResponse)(nil), // 168: openshell.v1.ClearDraftChunksResponse - (*GetDraftHistoryRequest)(nil), // 169: openshell.v1.GetDraftHistoryRequest - (*DraftHistoryEntry)(nil), // 170: openshell.v1.DraftHistoryEntry - (*GetDraftHistoryResponse)(nil), // 171: openshell.v1.GetDraftHistoryResponse - (*PolicyRevisionPayload)(nil), // 172: openshell.v1.PolicyRevisionPayload - (*DraftChunkPayload)(nil), // 173: openshell.v1.DraftChunkPayload - (*StoredPolicyRevision)(nil), // 174: openshell.v1.StoredPolicyRevision - (*StoredDraftChunk)(nil), // 175: openshell.v1.StoredDraftChunk - (*CreateWorkspaceRequest)(nil), // 176: openshell.v1.CreateWorkspaceRequest - (*CreateWorkspaceResponse)(nil), // 177: openshell.v1.CreateWorkspaceResponse - (*GetWorkspaceRequest)(nil), // 178: openshell.v1.GetWorkspaceRequest - (*GetWorkspaceResponse)(nil), // 179: openshell.v1.GetWorkspaceResponse - (*ListWorkspacesRequest)(nil), // 180: openshell.v1.ListWorkspacesRequest - (*ListWorkspacesResponse)(nil), // 181: openshell.v1.ListWorkspacesResponse - (*DeleteWorkspaceRequest)(nil), // 182: openshell.v1.DeleteWorkspaceRequest - (*DeleteWorkspaceResponse)(nil), // 183: openshell.v1.DeleteWorkspaceResponse - (*WorkspaceMember)(nil), // 184: openshell.v1.WorkspaceMember - (*AddWorkspaceMemberRequest)(nil), // 185: openshell.v1.AddWorkspaceMemberRequest - (*AddWorkspaceMemberResponse)(nil), // 186: openshell.v1.AddWorkspaceMemberResponse - (*RemoveWorkspaceMemberRequest)(nil), // 187: openshell.v1.RemoveWorkspaceMemberRequest - (*RemoveWorkspaceMemberResponse)(nil), // 188: openshell.v1.RemoveWorkspaceMemberResponse - (*ListWorkspaceMembersRequest)(nil), // 189: openshell.v1.ListWorkspaceMembersRequest - (*ListWorkspaceMembersResponse)(nil), // 190: openshell.v1.ListWorkspaceMembersResponse - (*ExtensionServiceCredential)(nil), // 191: openshell.v1.ExtensionServiceCredential - nil, // 192: openshell.v1.SandboxSpec.EnvironmentEntry - nil, // 193: openshell.v1.SandboxTemplate.LabelsEntry - nil, // 194: openshell.v1.SandboxTemplate.AnnotationsEntry - nil, // 195: openshell.v1.SandboxTemplate.EnvironmentEntry - nil, // 196: openshell.v1.PlatformEvent.MetadataEntry - nil, // 197: openshell.v1.CreateSandboxRequest.LabelsEntry - nil, // 198: openshell.v1.CreateSandboxRequest.AnnotationsEntry - nil, // 199: openshell.v1.ExecSandboxRequest.EnvironmentEntry - nil, // 200: openshell.v1.SandboxLogLine.FieldsEntry - nil, // 201: openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry - nil, // 202: openshell.v1.StoredProviderCredentialRefreshState.MaterialEntry - nil, // 203: openshell.v1.StoredProviderCredentialRefreshState.AdditionalOutputKeysEntry - nil, // 204: openshell.v1.StoredProviderCredentialRefreshState.SecretMaterialHandlesEntry - nil, // 205: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - nil, // 206: openshell.v1.ProviderProfile.AnnotationsEntry - nil, // 207: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - nil, // 208: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry - nil, // 209: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - nil, // 210: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - nil, // 211: openshell.v1.UpdateConfigRequest.AnnotationsEntry - nil, // 212: openshell.v1.UpdateConfigResponse.AnnotationsEntry - nil, // 213: openshell.v1.SandboxPolicyRevision.ProvenanceEntry - nil, // 214: openshell.v1.PolicyRevisionPayload.ProvenanceEntry - nil, // 215: openshell.v1.StoredPolicyRevision.ProvenanceEntry - nil, // 216: openshell.v1.CreateWorkspaceRequest.LabelsEntry - (*datamodelv1.ObjectMeta)(nil), // 217: openshell.datamodel.v1.ObjectMeta - (*sandboxv1.SandboxPolicy)(nil), // 218: openshell.sandbox.v1.SandboxPolicy - (*structpb.Struct)(nil), // 219: google.protobuf.Struct - (*datamodelv1.Provider)(nil), // 220: openshell.datamodel.v1.Provider - (*datamodelv1.CredentialHandle)(nil), // 221: openshell.datamodel.v1.CredentialHandle - (*sandboxv1.NetworkEndpoint)(nil), // 222: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 223: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 224: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 225: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 226: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 227: openshell.sandbox.v1.L7Rule - (*datamodelv1.Workspace)(nil), // 228: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 229: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 230: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 231: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 232: openshell.sandbox.v1.GetGatewayConfigResponse + (*SandboxWorkloadTemplate)(nil), // 23: openshell.v1.SandboxWorkloadTemplate + (*SandboxWorkloadTemplateSpec)(nil), // 24: openshell.v1.SandboxWorkloadTemplateSpec + (*SandboxWorkloadConfig)(nil), // 25: openshell.v1.SandboxWorkloadConfig + (*SandboxResources)(nil), // 26: openshell.v1.SandboxResources + (*SandboxServiceLevel)(nil), // 27: openshell.v1.SandboxServiceLevel + (*SandboxStartup)(nil), // 28: openshell.v1.SandboxStartup + (*SandboxWorkloadTemplateProvenance)(nil), // 29: openshell.v1.SandboxWorkloadTemplateProvenance + (*SandboxStatus)(nil), // 30: openshell.v1.SandboxStatus + (*SandboxCondition)(nil), // 31: openshell.v1.SandboxCondition + (*PlatformEvent)(nil), // 32: openshell.v1.PlatformEvent + (*CreateSandboxRequest)(nil), // 33: openshell.v1.CreateSandboxRequest + (*CreateSandboxTemplateRequest)(nil), // 34: openshell.v1.CreateSandboxTemplateRequest + (*GetSandboxTemplateRequest)(nil), // 35: openshell.v1.GetSandboxTemplateRequest + (*ListSandboxTemplatesRequest)(nil), // 36: openshell.v1.ListSandboxTemplatesRequest + (*DeleteSandboxTemplateRequest)(nil), // 37: openshell.v1.DeleteSandboxTemplateRequest + (*SandboxTemplateResponse)(nil), // 38: openshell.v1.SandboxTemplateResponse + (*ListSandboxTemplatesResponse)(nil), // 39: openshell.v1.ListSandboxTemplatesResponse + (*DeleteSandboxTemplateResponse)(nil), // 40: openshell.v1.DeleteSandboxTemplateResponse + (*GetSandboxRequest)(nil), // 41: openshell.v1.GetSandboxRequest + (*ListSandboxesRequest)(nil), // 42: openshell.v1.ListSandboxesRequest + (*ListSandboxProvidersRequest)(nil), // 43: openshell.v1.ListSandboxProvidersRequest + (*AttachSandboxProviderRequest)(nil), // 44: openshell.v1.AttachSandboxProviderRequest + (*DetachSandboxProviderRequest)(nil), // 45: openshell.v1.DetachSandboxProviderRequest + (*DeleteSandboxRequest)(nil), // 46: openshell.v1.DeleteSandboxRequest + (*StopSandboxRequest)(nil), // 47: openshell.v1.StopSandboxRequest + (*StartSandboxRequest)(nil), // 48: openshell.v1.StartSandboxRequest + (*SandboxResponse)(nil), // 49: openshell.v1.SandboxResponse + (*ListSandboxesResponse)(nil), // 50: openshell.v1.ListSandboxesResponse + (*ListSandboxProvidersResponse)(nil), // 51: openshell.v1.ListSandboxProvidersResponse + (*AttachSandboxProviderResponse)(nil), // 52: openshell.v1.AttachSandboxProviderResponse + (*DetachSandboxProviderResponse)(nil), // 53: openshell.v1.DetachSandboxProviderResponse + (*DeleteSandboxResponse)(nil), // 54: openshell.v1.DeleteSandboxResponse + (*CreateSshSessionRequest)(nil), // 55: openshell.v1.CreateSshSessionRequest + (*CreateSshSessionResponse)(nil), // 56: openshell.v1.CreateSshSessionResponse + (*ExposeServiceRequest)(nil), // 57: openshell.v1.ExposeServiceRequest + (*GetServiceRequest)(nil), // 58: openshell.v1.GetServiceRequest + (*ListServicesRequest)(nil), // 59: openshell.v1.ListServicesRequest + (*ListServicesResponse)(nil), // 60: openshell.v1.ListServicesResponse + (*DeleteServiceRequest)(nil), // 61: openshell.v1.DeleteServiceRequest + (*DeleteServiceResponse)(nil), // 62: openshell.v1.DeleteServiceResponse + (*ServiceEndpoint)(nil), // 63: openshell.v1.ServiceEndpoint + (*ServiceEndpointResponse)(nil), // 64: openshell.v1.ServiceEndpointResponse + (*RevokeSshSessionRequest)(nil), // 65: openshell.v1.RevokeSshSessionRequest + (*RevokeSshSessionResponse)(nil), // 66: openshell.v1.RevokeSshSessionResponse + (*ExecSandboxRequest)(nil), // 67: openshell.v1.ExecSandboxRequest + (*ExecSandboxStdout)(nil), // 68: openshell.v1.ExecSandboxStdout + (*ExecSandboxStderr)(nil), // 69: openshell.v1.ExecSandboxStderr + (*ExecSandboxExit)(nil), // 70: openshell.v1.ExecSandboxExit + (*ExecSandboxEvent)(nil), // 71: openshell.v1.ExecSandboxEvent + (*TcpForwardInit)(nil), // 72: openshell.v1.TcpForwardInit + (*TcpForwardFrame)(nil), // 73: openshell.v1.TcpForwardFrame + (*ExecSandboxInput)(nil), // 74: openshell.v1.ExecSandboxInput + (*ExecSandboxWindowResize)(nil), // 75: openshell.v1.ExecSandboxWindowResize + (*SshSession)(nil), // 76: openshell.v1.SshSession + (*WatchSandboxRequest)(nil), // 77: openshell.v1.WatchSandboxRequest + (*SandboxStreamEvent)(nil), // 78: openshell.v1.SandboxStreamEvent + (*SandboxLogLine)(nil), // 79: openshell.v1.SandboxLogLine + (*SandboxStreamWarning)(nil), // 80: openshell.v1.SandboxStreamWarning + (*CreateProviderRequest)(nil), // 81: openshell.v1.CreateProviderRequest + (*GetProviderRequest)(nil), // 82: openshell.v1.GetProviderRequest + (*ListProvidersRequest)(nil), // 83: openshell.v1.ListProvidersRequest + (*UpdateProviderRequest)(nil), // 84: openshell.v1.UpdateProviderRequest + (*DeleteProviderRequest)(nil), // 85: openshell.v1.DeleteProviderRequest + (*ProviderResponse)(nil), // 86: openshell.v1.ProviderResponse + (*ListProvidersResponse)(nil), // 87: openshell.v1.ListProvidersResponse + (*ListProviderProfilesRequest)(nil), // 88: openshell.v1.ListProviderProfilesRequest + (*GetProviderProfileRequest)(nil), // 89: openshell.v1.GetProviderProfileRequest + (*ProviderProfileImportItem)(nil), // 90: openshell.v1.ProviderProfileImportItem + (*ProviderProfileDiagnostic)(nil), // 91: openshell.v1.ProviderProfileDiagnostic + (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 92: openshell.v1.ProviderCredentialTokenGrantAudienceOverride + (*ProviderCredentialTokenGrant)(nil), // 93: openshell.v1.ProviderCredentialTokenGrant + (*ProviderProfileCredential)(nil), // 94: openshell.v1.ProviderProfileCredential + (*ProviderCredentialRefreshMaterial)(nil), // 95: openshell.v1.ProviderCredentialRefreshMaterial + (*ProviderCredentialRefreshOutput)(nil), // 96: openshell.v1.ProviderCredentialRefreshOutput + (*ProviderCredentialRefresh)(nil), // 97: openshell.v1.ProviderCredentialRefresh + (*ProviderCredentialRefreshStatus)(nil), // 98: openshell.v1.ProviderCredentialRefreshStatus + (*ProviderProfileDiscovery)(nil), // 99: openshell.v1.ProviderProfileDiscovery + (*StoredProviderCredentialRefreshState)(nil), // 100: openshell.v1.StoredProviderCredentialRefreshState + (*StoredRefreshMaterialDeletion)(nil), // 101: openshell.v1.StoredRefreshMaterialDeletion + (*GetProviderRefreshStatusRequest)(nil), // 102: openshell.v1.GetProviderRefreshStatusRequest + (*GetProviderRefreshStatusResponse)(nil), // 103: openshell.v1.GetProviderRefreshStatusResponse + (*ConfigureProviderRefreshRequest)(nil), // 104: openshell.v1.ConfigureProviderRefreshRequest + (*ConfigureProviderRefreshResponse)(nil), // 105: openshell.v1.ConfigureProviderRefreshResponse + (*RotateProviderCredentialRequest)(nil), // 106: openshell.v1.RotateProviderCredentialRequest + (*RotateProviderCredentialResponse)(nil), // 107: openshell.v1.RotateProviderCredentialResponse + (*DeleteProviderRefreshRequest)(nil), // 108: openshell.v1.DeleteProviderRefreshRequest + (*DeleteProviderRefreshResponse)(nil), // 109: openshell.v1.DeleteProviderRefreshResponse + (*ProviderProfile)(nil), // 110: openshell.v1.ProviderProfile + (*StoredProviderProfile)(nil), // 111: openshell.v1.StoredProviderProfile + (*ProviderProfileResponse)(nil), // 112: openshell.v1.ProviderProfileResponse + (*ListProviderProfilesResponse)(nil), // 113: openshell.v1.ListProviderProfilesResponse + (*ImportProviderProfilesRequest)(nil), // 114: openshell.v1.ImportProviderProfilesRequest + (*ImportProviderProfilesResponse)(nil), // 115: openshell.v1.ImportProviderProfilesResponse + (*UpdateProviderProfilesRequest)(nil), // 116: openshell.v1.UpdateProviderProfilesRequest + (*UpdateProviderProfilesResponse)(nil), // 117: openshell.v1.UpdateProviderProfilesResponse + (*LintProviderProfilesRequest)(nil), // 118: openshell.v1.LintProviderProfilesRequest + (*LintProviderProfilesResponse)(nil), // 119: openshell.v1.LintProviderProfilesResponse + (*DeleteProviderResponse)(nil), // 120: openshell.v1.DeleteProviderResponse + (*DeleteProviderProfileRequest)(nil), // 121: openshell.v1.DeleteProviderProfileRequest + (*DeleteProviderProfileResponse)(nil), // 122: openshell.v1.DeleteProviderProfileResponse + (*GetSandboxProviderEnvironmentRequest)(nil), // 123: openshell.v1.GetSandboxProviderEnvironmentRequest + (*StaticCredentialEndpointBinding)(nil), // 124: openshell.v1.StaticCredentialEndpointBinding + (*StaticCredentialBinding)(nil), // 125: openshell.v1.StaticCredentialBinding + (*GetSandboxProviderEnvironmentResponse)(nil), // 126: openshell.v1.GetSandboxProviderEnvironmentResponse + (*UpdateConfigRequest)(nil), // 127: openshell.v1.UpdateConfigRequest + (*PolicyMergeOperation)(nil), // 128: openshell.v1.PolicyMergeOperation + (*AddNetworkRule)(nil), // 129: openshell.v1.AddNetworkRule + (*RemoveNetworkEndpoint)(nil), // 130: openshell.v1.RemoveNetworkEndpoint + (*RemoveNetworkRule)(nil), // 131: openshell.v1.RemoveNetworkRule + (*AddDenyRules)(nil), // 132: openshell.v1.AddDenyRules + (*AddAllowRules)(nil), // 133: openshell.v1.AddAllowRules + (*RemoveNetworkBinary)(nil), // 134: openshell.v1.RemoveNetworkBinary + (*UpdateConfigResponse)(nil), // 135: openshell.v1.UpdateConfigResponse + (*GetSandboxPolicyStatusRequest)(nil), // 136: openshell.v1.GetSandboxPolicyStatusRequest + (*GetSandboxPolicyStatusResponse)(nil), // 137: openshell.v1.GetSandboxPolicyStatusResponse + (*ListSandboxPoliciesRequest)(nil), // 138: openshell.v1.ListSandboxPoliciesRequest + (*ListSandboxPoliciesResponse)(nil), // 139: openshell.v1.ListSandboxPoliciesResponse + (*ReportPolicyStatusRequest)(nil), // 140: openshell.v1.ReportPolicyStatusRequest + (*ReportPolicyStatusResponse)(nil), // 141: openshell.v1.ReportPolicyStatusResponse + (*SandboxPolicyRevision)(nil), // 142: openshell.v1.SandboxPolicyRevision + (*GetSandboxLogsRequest)(nil), // 143: openshell.v1.GetSandboxLogsRequest + (*PushSandboxLogsRequest)(nil), // 144: openshell.v1.PushSandboxLogsRequest + (*PushSandboxLogsResponse)(nil), // 145: openshell.v1.PushSandboxLogsResponse + (*GetSandboxLogsResponse)(nil), // 146: openshell.v1.GetSandboxLogsResponse + (*SupervisorMessage)(nil), // 147: openshell.v1.SupervisorMessage + (*GatewayMessage)(nil), // 148: openshell.v1.GatewayMessage + (*SupervisorHello)(nil), // 149: openshell.v1.SupervisorHello + (*SessionAccepted)(nil), // 150: openshell.v1.SessionAccepted + (*SessionRejected)(nil), // 151: openshell.v1.SessionRejected + (*SupervisorHeartbeat)(nil), // 152: openshell.v1.SupervisorHeartbeat + (*GatewayHeartbeat)(nil), // 153: openshell.v1.GatewayHeartbeat + (*RelayOpen)(nil), // 154: openshell.v1.RelayOpen + (*SshRelayTarget)(nil), // 155: openshell.v1.SshRelayTarget + (*TcpRelayTarget)(nil), // 156: openshell.v1.TcpRelayTarget + (*RelayInit)(nil), // 157: openshell.v1.RelayInit + (*RelayFrame)(nil), // 158: openshell.v1.RelayFrame + (*RelayOpenResult)(nil), // 159: openshell.v1.RelayOpenResult + (*RelayClose)(nil), // 160: openshell.v1.RelayClose + (*L7RequestSample)(nil), // 161: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 162: openshell.v1.DenialSummary + (*DenialGroupCount)(nil), // 163: openshell.v1.DenialGroupCount + (*NetworkActivitySummary)(nil), // 164: openshell.v1.NetworkActivitySummary + (*PolicyChunk)(nil), // 165: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 166: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 167: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 168: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 169: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 170: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 171: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 172: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 173: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 174: openshell.v1.RejectDraftChunkResponse + (*ApproveAllDraftChunksRequest)(nil), // 175: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 176: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 177: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 178: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 179: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 180: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 181: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 182: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 183: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 184: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 185: openshell.v1.GetDraftHistoryResponse + (*PolicyRevisionPayload)(nil), // 186: openshell.v1.PolicyRevisionPayload + (*DraftChunkPayload)(nil), // 187: openshell.v1.DraftChunkPayload + (*StoredPolicyRevision)(nil), // 188: openshell.v1.StoredPolicyRevision + (*StoredDraftChunk)(nil), // 189: openshell.v1.StoredDraftChunk + (*CreateWorkspaceRequest)(nil), // 190: openshell.v1.CreateWorkspaceRequest + (*CreateWorkspaceResponse)(nil), // 191: openshell.v1.CreateWorkspaceResponse + (*GetWorkspaceRequest)(nil), // 192: openshell.v1.GetWorkspaceRequest + (*GetWorkspaceResponse)(nil), // 193: openshell.v1.GetWorkspaceResponse + (*ListWorkspacesRequest)(nil), // 194: openshell.v1.ListWorkspacesRequest + (*ListWorkspacesResponse)(nil), // 195: openshell.v1.ListWorkspacesResponse + (*DeleteWorkspaceRequest)(nil), // 196: openshell.v1.DeleteWorkspaceRequest + (*DeleteWorkspaceResponse)(nil), // 197: openshell.v1.DeleteWorkspaceResponse + (*WorkspaceMember)(nil), // 198: openshell.v1.WorkspaceMember + (*AddWorkspaceMemberRequest)(nil), // 199: openshell.v1.AddWorkspaceMemberRequest + (*AddWorkspaceMemberResponse)(nil), // 200: openshell.v1.AddWorkspaceMemberResponse + (*RemoveWorkspaceMemberRequest)(nil), // 201: openshell.v1.RemoveWorkspaceMemberRequest + (*RemoveWorkspaceMemberResponse)(nil), // 202: openshell.v1.RemoveWorkspaceMemberResponse + (*ListWorkspaceMembersRequest)(nil), // 203: openshell.v1.ListWorkspaceMembersRequest + (*ListWorkspaceMembersResponse)(nil), // 204: openshell.v1.ListWorkspaceMembersResponse + (*ExtensionServiceCredential)(nil), // 205: openshell.v1.ExtensionServiceCredential + nil, // 206: openshell.v1.SandboxSpec.EnvironmentEntry + nil, // 207: openshell.v1.SandboxTemplate.LabelsEntry + nil, // 208: openshell.v1.SandboxTemplate.AnnotationsEntry + nil, // 209: openshell.v1.SandboxTemplate.EnvironmentEntry + nil, // 210: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + nil, // 211: openshell.v1.PlatformEvent.MetadataEntry + nil, // 212: openshell.v1.CreateSandboxRequest.LabelsEntry + nil, // 213: openshell.v1.CreateSandboxRequest.AnnotationsEntry + nil, // 214: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 215: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 216: openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry + nil, // 217: openshell.v1.StoredProviderCredentialRefreshState.MaterialEntry + nil, // 218: openshell.v1.StoredProviderCredentialRefreshState.AdditionalOutputKeysEntry + nil, // 219: openshell.v1.StoredProviderCredentialRefreshState.SecretMaterialHandlesEntry + nil, // 220: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + nil, // 221: openshell.v1.ProviderProfile.AnnotationsEntry + nil, // 222: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + nil, // 223: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry + nil, // 224: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + nil, // 225: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + nil, // 226: openshell.v1.UpdateConfigRequest.AnnotationsEntry + nil, // 227: openshell.v1.UpdateConfigResponse.AnnotationsEntry + nil, // 228: openshell.v1.SandboxPolicyRevision.ProvenanceEntry + nil, // 229: openshell.v1.PolicyRevisionPayload.ProvenanceEntry + nil, // 230: openshell.v1.StoredPolicyRevision.ProvenanceEntry + nil, // 231: openshell.v1.CreateWorkspaceRequest.LabelsEntry + (*datamodelv1.ObjectMeta)(nil), // 232: openshell.datamodel.v1.ObjectMeta + (*sandboxv1.SandboxPolicy)(nil), // 233: openshell.sandbox.v1.SandboxPolicy + (*structpb.Struct)(nil), // 234: google.protobuf.Struct + (*durationpb.Duration)(nil), // 235: google.protobuf.Duration + (*datamodelv1.Provider)(nil), // 236: openshell.datamodel.v1.Provider + (*datamodelv1.CredentialHandle)(nil), // 237: openshell.datamodel.v1.CredentialHandle + (*sandboxv1.NetworkEndpoint)(nil), // 238: openshell.sandbox.v1.NetworkEndpoint + (*sandboxv1.NetworkBinary)(nil), // 239: openshell.sandbox.v1.NetworkBinary + (*sandboxv1.SettingValue)(nil), // 240: openshell.sandbox.v1.SettingValue + (*sandboxv1.NetworkPolicyRule)(nil), // 241: openshell.sandbox.v1.NetworkPolicyRule + (*sandboxv1.L7DenyRule)(nil), // 242: openshell.sandbox.v1.L7DenyRule + (*sandboxv1.L7Rule)(nil), // 243: openshell.sandbox.v1.L7Rule + (*datamodelv1.Workspace)(nil), // 244: openshell.datamodel.v1.Workspace + (*sandboxv1.GetSandboxConfigRequest)(nil), // 245: openshell.sandbox.v1.GetSandboxConfigRequest + (*sandboxv1.GetGatewayConfigRequest)(nil), // 246: openshell.sandbox.v1.GetGatewayConfigRequest + (*sandboxv1.GetSandboxConfigResponse)(nil), // 247: openshell.sandbox.v1.GetSandboxConfigResponse + (*sandboxv1.GetGatewayConfigResponse)(nil), // 248: openshell.sandbox.v1.GetGatewayConfigResponse } var file_openshell_proto_depIdxs = []int32{ - 191, // 0: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential + 205, // 0: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential 4, // 1: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus 4, // 2: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus 16, // 3: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo 17, // 4: openshell.v1.ComputeDriverInfo.capabilities:type_name -> openshell.v1.ComputeDriverCapabilities - 217, // 5: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 232, // 5: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 19, // 6: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec - 23, // 7: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus - 192, // 8: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry - 22, // 9: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate - 218, // 10: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 20, // 11: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements - 21, // 12: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements - 193, // 13: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry - 194, // 14: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry - 195, // 15: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry - 219, // 16: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct - 219, // 17: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct - 24, // 18: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition - 0, // 19: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 196, // 20: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 19, // 21: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 197, // 22: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 198, // 23: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 18, // 24: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 18, // 25: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 220, // 26: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 18, // 27: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 18, // 28: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 50, // 29: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 217, // 30: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 49, // 31: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint - 199, // 32: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 54, // 33: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout - 55, // 34: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr - 56, // 35: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 141, // 36: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 142, // 37: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget - 58, // 38: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit - 53, // 39: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest - 61, // 40: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 217, // 41: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 18, // 42: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox - 65, // 43: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine - 25, // 44: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent - 66, // 45: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 152, // 46: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 200, // 47: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 220, // 48: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 220, // 49: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 201, // 50: openshell.v1.UpdateProviderRequest.credential_expires_at_ms:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry - 220, // 51: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider - 220, // 52: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 96, // 53: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 78, // 54: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride - 83, // 55: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh - 79, // 56: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant - 1, // 57: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 81, // 58: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial - 82, // 59: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput - 1, // 60: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 217, // 61: openshell.v1.StoredProviderCredentialRefreshState.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 1, // 62: openshell.v1.StoredProviderCredentialRefreshState.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 202, // 63: openshell.v1.StoredProviderCredentialRefreshState.material:type_name -> openshell.v1.StoredProviderCredentialRefreshState.MaterialEntry - 203, // 64: openshell.v1.StoredProviderCredentialRefreshState.additional_output_keys:type_name -> openshell.v1.StoredProviderCredentialRefreshState.AdditionalOutputKeysEntry - 204, // 65: openshell.v1.StoredProviderCredentialRefreshState.secret_material_handles:type_name -> openshell.v1.StoredProviderCredentialRefreshState.SecretMaterialHandlesEntry - 87, // 66: openshell.v1.StoredProviderCredentialRefreshState.pending_secret_deletions:type_name -> openshell.v1.StoredRefreshMaterialDeletion - 221, // 67: openshell.v1.StoredRefreshMaterialDeletion.handle:type_name -> openshell.datamodel.v1.CredentialHandle - 84, // 68: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 1, // 69: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 205, // 70: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 84, // 71: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 84, // 72: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 2, // 73: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory - 80, // 74: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 222, // 75: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 223, // 76: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 85, // 77: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 206, // 78: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 217, // 79: openshell.v1.StoredProviderProfile.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 96, // 80: openshell.v1.StoredProviderProfile.profile:type_name -> openshell.v1.ProviderProfile - 96, // 81: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 96, // 82: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 76, // 83: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 77, // 84: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 96, // 85: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 76, // 86: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 77, // 87: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 96, // 88: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 76, // 89: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 77, // 90: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 110, // 91: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 207, // 92: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 208, // 93: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expires_at_ms:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry - 209, // 94: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 210, // 95: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 218, // 96: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 224, // 97: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 114, // 98: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 211, // 99: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 115, // 100: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 116, // 101: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 117, // 102: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 118, // 103: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 119, // 104: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 120, // 105: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 225, // 106: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 226, // 107: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 227, // 108: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 212, // 109: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 128, // 110: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 128, // 111: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 3, // 112: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 3, // 113: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 218, // 114: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 213, // 115: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 65, // 116: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 65, // 117: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 135, // 118: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 138, // 119: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 145, // 120: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 146, // 121: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 136, // 122: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 137, // 123: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 139, // 124: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 140, // 125: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 146, // 126: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 141, // 127: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 142, // 128: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 143, // 129: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 147, // 130: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 149, // 131: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 225, // 132: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 148, // 133: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 151, // 134: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 150, // 135: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 151, // 136: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 225, // 137: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 170, // 138: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 218, // 139: openshell.v1.PolicyRevisionPayload.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 214, // 140: openshell.v1.PolicyRevisionPayload.provenance:type_name -> openshell.v1.PolicyRevisionPayload.ProvenanceEntry - 225, // 141: openshell.v1.DraftChunkPayload.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 215, // 142: openshell.v1.StoredPolicyRevision.provenance:type_name -> openshell.v1.StoredPolicyRevision.ProvenanceEntry - 216, // 143: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 228, // 144: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 228, // 145: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 228, // 146: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 217, // 147: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 5, // 148: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 5, // 149: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 184, // 150: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 184, // 151: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 221, // 152: openshell.v1.StoredProviderCredentialRefreshState.SecretMaterialHandlesEntry.value:type_name -> openshell.datamodel.v1.CredentialHandle - 80, // 153: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 111, // 154: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 10, // 155: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 12, // 156: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 14, // 157: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 26, // 158: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 27, // 159: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 28, // 160: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 29, // 161: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 30, // 162: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 31, // 163: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 32, // 164: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 33, // 165: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 34, // 166: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 41, // 167: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 43, // 168: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 44, // 169: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 45, // 170: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 47, // 171: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 51, // 172: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 53, // 173: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 59, // 174: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 60, // 175: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 67, // 176: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 68, // 177: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 69, // 178: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 74, // 179: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 75, // 180: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 100, // 181: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 102, // 182: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 104, // 183: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 70, // 184: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 88, // 185: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 90, // 186: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 92, // 187: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 94, // 188: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 71, // 189: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 107, // 190: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 229, // 191: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 230, // 192: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 113, // 193: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 122, // 194: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 124, // 195: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 126, // 196: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 109, // 197: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 129, // 198: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 130, // 199: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 133, // 200: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 144, // 201: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 63, // 202: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 153, // 203: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 155, // 204: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 157, // 205: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 159, // 206: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 161, // 207: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 163, // 208: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 165, // 209: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 167, // 210: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 169, // 211: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 6, // 212: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 8, // 213: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 176, // 214: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 178, // 215: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 180, // 216: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 182, // 217: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 185, // 218: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 187, // 219: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 189, // 220: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 11, // 221: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 13, // 222: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 15, // 223: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 35, // 224: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 35, // 225: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 36, // 226: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 37, // 227: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 38, // 228: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 39, // 229: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 40, // 230: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 35, // 231: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 35, // 232: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 42, // 233: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 50, // 234: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 50, // 235: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 46, // 236: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 48, // 237: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 52, // 238: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 57, // 239: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 59, // 240: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 57, // 241: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 72, // 242: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 72, // 243: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 73, // 244: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 99, // 245: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 98, // 246: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 101, // 247: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 103, // 248: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 105, // 249: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 72, // 250: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 89, // 251: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 91, // 252: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 93, // 253: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 95, // 254: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 106, // 255: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 108, // 256: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 231, // 257: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 232, // 258: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 121, // 259: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 123, // 260: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 125, // 261: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 127, // 262: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 112, // 263: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 132, // 264: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 131, // 265: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 134, // 266: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 144, // 267: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 64, // 268: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 154, // 269: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 156, // 270: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 158, // 271: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 160, // 272: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 162, // 273: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 164, // 274: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 166, // 275: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 168, // 276: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 171, // 277: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 7, // 278: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 9, // 279: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 177, // 280: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 179, // 281: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 181, // 282: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 183, // 283: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 186, // 284: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 188, // 285: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 190, // 286: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 221, // [221:287] is the sub-list for method output_type - 155, // [155:221] is the sub-list for method input_type - 155, // [155:155] is the sub-list for extension type_name - 155, // [155:155] is the sub-list for extension extendee - 0, // [0:155] is the sub-list for field type_name + 30, // 7: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus + 29, // 8: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance + 206, // 9: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry + 22, // 10: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate + 233, // 11: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 20, // 12: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements + 21, // 13: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements + 207, // 14: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry + 208, // 15: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry + 209, // 16: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry + 234, // 17: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 234, // 18: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct + 232, // 19: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 24, // 20: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec + 25, // 21: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig + 234, // 22: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct + 27, // 23: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel + 210, // 24: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + 26, // 25: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources + 28, // 26: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup + 235, // 27: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 31, // 28: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition + 0, // 29: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase + 211, // 30: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 19, // 31: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec + 212, // 32: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 213, // 33: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 23, // 34: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 23, // 35: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 23, // 36: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate + 18, // 37: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox + 18, // 38: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox + 236, // 39: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 18, // 40: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 18, // 41: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 64, // 42: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse + 232, // 43: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 63, // 44: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint + 214, // 45: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 68, // 46: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout + 69, // 47: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr + 70, // 48: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit + 155, // 49: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget + 156, // 50: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget + 72, // 51: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit + 67, // 52: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest + 75, // 53: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize + 232, // 54: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 18, // 55: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox + 79, // 56: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine + 32, // 57: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent + 80, // 58: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning + 166, // 59: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 215, // 60: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 236, // 61: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 236, // 62: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 216, // 63: openshell.v1.UpdateProviderRequest.credential_expires_at_ms:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry + 236, // 64: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 236, // 65: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 110, // 66: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile + 92, // 67: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride + 97, // 68: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh + 93, // 69: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant + 1, // 70: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 95, // 71: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial + 96, // 72: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput + 1, // 73: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 232, // 74: openshell.v1.StoredProviderCredentialRefreshState.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 1, // 75: openshell.v1.StoredProviderCredentialRefreshState.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 217, // 76: openshell.v1.StoredProviderCredentialRefreshState.material:type_name -> openshell.v1.StoredProviderCredentialRefreshState.MaterialEntry + 218, // 77: openshell.v1.StoredProviderCredentialRefreshState.additional_output_keys:type_name -> openshell.v1.StoredProviderCredentialRefreshState.AdditionalOutputKeysEntry + 219, // 78: openshell.v1.StoredProviderCredentialRefreshState.secret_material_handles:type_name -> openshell.v1.StoredProviderCredentialRefreshState.SecretMaterialHandlesEntry + 101, // 79: openshell.v1.StoredProviderCredentialRefreshState.pending_secret_deletions:type_name -> openshell.v1.StoredRefreshMaterialDeletion + 237, // 80: openshell.v1.StoredRefreshMaterialDeletion.handle:type_name -> openshell.datamodel.v1.CredentialHandle + 98, // 81: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 1, // 82: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 220, // 83: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 98, // 84: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 98, // 85: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 2, // 86: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory + 94, // 87: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential + 238, // 88: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 239, // 89: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 99, // 90: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery + 221, // 91: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 232, // 92: openshell.v1.StoredProviderProfile.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 110, // 93: openshell.v1.StoredProviderProfile.profile:type_name -> openshell.v1.ProviderProfile + 110, // 94: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile + 110, // 95: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 90, // 96: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 91, // 97: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 110, // 98: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 90, // 99: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem + 91, // 100: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 110, // 101: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile + 90, // 102: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 91, // 103: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 124, // 104: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding + 222, // 105: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 223, // 106: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expires_at_ms:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry + 224, // 107: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 225, // 108: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 233, // 109: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 240, // 110: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 128, // 111: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation + 226, // 112: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 129, // 113: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule + 130, // 114: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint + 131, // 115: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule + 132, // 116: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules + 133, // 117: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules + 134, // 118: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary + 241, // 119: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 242, // 120: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 243, // 121: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 227, // 122: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 142, // 123: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 142, // 124: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 3, // 125: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 3, // 126: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 233, // 127: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 228, // 128: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 79, // 129: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 79, // 130: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 149, // 131: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello + 152, // 132: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat + 159, // 133: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 160, // 134: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 150, // 135: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted + 151, // 136: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected + 153, // 137: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat + 154, // 138: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen + 160, // 139: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 155, // 140: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget + 156, // 141: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget + 157, // 142: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit + 161, // 143: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 163, // 144: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 241, // 145: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 162, // 146: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 165, // 147: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 164, // 148: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 165, // 149: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 241, // 150: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 184, // 151: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 233, // 152: openshell.v1.PolicyRevisionPayload.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 229, // 153: openshell.v1.PolicyRevisionPayload.provenance:type_name -> openshell.v1.PolicyRevisionPayload.ProvenanceEntry + 241, // 154: openshell.v1.DraftChunkPayload.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 230, // 155: openshell.v1.StoredPolicyRevision.provenance:type_name -> openshell.v1.StoredPolicyRevision.ProvenanceEntry + 231, // 156: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 244, // 157: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 244, // 158: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 244, // 159: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 232, // 160: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 5, // 161: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 5, // 162: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 198, // 163: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 198, // 164: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 237, // 165: openshell.v1.StoredProviderCredentialRefreshState.SecretMaterialHandlesEntry.value:type_name -> openshell.datamodel.v1.CredentialHandle + 94, // 166: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 125, // 167: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 10, // 168: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 12, // 169: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 14, // 170: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 33, // 171: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 41, // 172: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 42, // 173: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 34, // 174: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 35, // 175: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 36, // 176: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 37, // 177: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 43, // 178: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 44, // 179: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 45, // 180: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 46, // 181: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 47, // 182: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 48, // 183: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 55, // 184: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 57, // 185: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 58, // 186: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 59, // 187: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 61, // 188: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 65, // 189: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 67, // 190: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 73, // 191: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 74, // 192: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 81, // 193: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 82, // 194: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 83, // 195: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 88, // 196: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 89, // 197: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 114, // 198: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 116, // 199: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 118, // 200: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 84, // 201: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 102, // 202: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 104, // 203: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 106, // 204: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 108, // 205: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 85, // 206: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 121, // 207: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 245, // 208: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 246, // 209: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 127, // 210: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 136, // 211: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 138, // 212: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 140, // 213: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 123, // 214: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 143, // 215: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 144, // 216: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 147, // 217: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 158, // 218: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 77, // 219: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 167, // 220: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 169, // 221: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 171, // 222: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 173, // 223: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 175, // 224: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 177, // 225: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 179, // 226: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 181, // 227: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 183, // 228: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 6, // 229: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 8, // 230: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 190, // 231: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 192, // 232: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 194, // 233: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 196, // 234: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 199, // 235: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 201, // 236: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 203, // 237: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 11, // 238: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 13, // 239: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 15, // 240: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 49, // 241: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 49, // 242: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 50, // 243: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 38, // 244: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 38, // 245: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 39, // 246: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 40, // 247: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 51, // 248: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 52, // 249: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 53, // 250: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 54, // 251: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 49, // 252: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 49, // 253: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 56, // 254: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 64, // 255: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 64, // 256: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 60, // 257: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 62, // 258: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 66, // 259: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 71, // 260: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 73, // 261: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 71, // 262: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 86, // 263: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 86, // 264: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 87, // 265: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 113, // 266: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 112, // 267: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 115, // 268: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 117, // 269: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 119, // 270: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 86, // 271: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 103, // 272: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 105, // 273: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 107, // 274: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 109, // 275: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 120, // 276: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 122, // 277: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 247, // 278: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 248, // 279: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 135, // 280: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 137, // 281: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 139, // 282: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 141, // 283: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 126, // 284: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 146, // 285: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 145, // 286: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 148, // 287: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 158, // 288: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 78, // 289: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 168, // 290: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 170, // 291: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 172, // 292: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 174, // 293: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 176, // 294: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 178, // 295: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 180, // 296: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 182, // 297: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 185, // 298: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 7, // 299: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 9, // 300: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 191, // 301: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 193, // 302: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 195, // 303: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 197, // 304: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 200, // 305: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 202, // 306: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 204, // 307: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 238, // [238:308] is the sub-list for method output_type + 168, // [168:238] is the sub-list for method input_type + 168, // [168:168] is the sub-list for extension type_name + 168, // [168:168] is the sub-list for extension extendee + 0, // [0:168] is the sub-list for field type_name } func init() { file_openshell_proto_init() } @@ -14916,33 +15793,34 @@ func file_openshell_proto_init() { } file_openshell_proto_msgTypes[15].OneofWrappers = []any{} file_openshell_proto_msgTypes[16].OneofWrappers = []any{} - file_openshell_proto_msgTypes[51].OneofWrappers = []any{ + file_openshell_proto_msgTypes[20].OneofWrappers = []any{} + file_openshell_proto_msgTypes[65].OneofWrappers = []any{ (*ExecSandboxEvent_Stdout)(nil), (*ExecSandboxEvent_Stderr)(nil), (*ExecSandboxEvent_Exit)(nil), } - file_openshell_proto_msgTypes[52].OneofWrappers = []any{ + file_openshell_proto_msgTypes[66].OneofWrappers = []any{ (*TcpForwardInit_Ssh)(nil), (*TcpForwardInit_Tcp)(nil), } - file_openshell_proto_msgTypes[53].OneofWrappers = []any{ + file_openshell_proto_msgTypes[67].OneofWrappers = []any{ (*TcpForwardFrame_Init)(nil), (*TcpForwardFrame_Data)(nil), } - file_openshell_proto_msgTypes[54].OneofWrappers = []any{ + file_openshell_proto_msgTypes[68].OneofWrappers = []any{ (*ExecSandboxInput_Start)(nil), (*ExecSandboxInput_Stdin)(nil), (*ExecSandboxInput_Resize)(nil), } - file_openshell_proto_msgTypes[58].OneofWrappers = []any{ + file_openshell_proto_msgTypes[72].OneofWrappers = []any{ (*SandboxStreamEvent_Sandbox)(nil), (*SandboxStreamEvent_Log)(nil), (*SandboxStreamEvent_Event)(nil), (*SandboxStreamEvent_Warning)(nil), (*SandboxStreamEvent_DraftPolicyUpdate)(nil), } - file_openshell_proto_msgTypes[84].OneofWrappers = []any{} - file_openshell_proto_msgTypes[108].OneofWrappers = []any{ + file_openshell_proto_msgTypes[98].OneofWrappers = []any{} + file_openshell_proto_msgTypes[122].OneofWrappers = []any{ (*PolicyMergeOperation_AddRule)(nil), (*PolicyMergeOperation_RemoveEndpoint)(nil), (*PolicyMergeOperation_RemoveRule)(nil), @@ -14950,36 +15828,36 @@ func file_openshell_proto_init() { (*PolicyMergeOperation_AddAllowRules)(nil), (*PolicyMergeOperation_RemoveBinary)(nil), } - file_openshell_proto_msgTypes[127].OneofWrappers = []any{ + file_openshell_proto_msgTypes[141].OneofWrappers = []any{ (*SupervisorMessage_Hello)(nil), (*SupervisorMessage_Heartbeat)(nil), (*SupervisorMessage_RelayOpenResult)(nil), (*SupervisorMessage_RelayClose)(nil), } - file_openshell_proto_msgTypes[128].OneofWrappers = []any{ + file_openshell_proto_msgTypes[142].OneofWrappers = []any{ (*GatewayMessage_SessionAccepted)(nil), (*GatewayMessage_SessionRejected)(nil), (*GatewayMessage_Heartbeat)(nil), (*GatewayMessage_RelayOpen)(nil), (*GatewayMessage_RelayClose)(nil), } - file_openshell_proto_msgTypes[134].OneofWrappers = []any{ + file_openshell_proto_msgTypes[148].OneofWrappers = []any{ (*RelayOpen_Ssh)(nil), (*RelayOpen_Tcp)(nil), } - file_openshell_proto_msgTypes[138].OneofWrappers = []any{ + file_openshell_proto_msgTypes[152].OneofWrappers = []any{ (*RelayFrame_Init)(nil), (*RelayFrame_Data)(nil), } - file_openshell_proto_msgTypes[168].OneofWrappers = []any{} - file_openshell_proto_msgTypes[169].OneofWrappers = []any{} + file_openshell_proto_msgTypes[182].OneofWrappers = []any{} + file_openshell_proto_msgTypes[183].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: 6, - NumMessages: 211, + NumMessages: 226, 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 92c94ef299..298bb1c6b4 100644 --- a/sdk/go/proto/openshellv1/openshell_grpc.pb.go +++ b/sdk/go/proto/openshellv1/openshell_grpc.pb.go @@ -29,6 +29,10 @@ const ( OpenShell_CreateSandbox_FullMethodName = "/openshell.v1.OpenShell/CreateSandbox" OpenShell_GetSandbox_FullMethodName = "/openshell.v1.OpenShell/GetSandbox" OpenShell_ListSandboxes_FullMethodName = "/openshell.v1.OpenShell/ListSandboxes" + OpenShell_CreateSandboxTemplate_FullMethodName = "/openshell.v1.OpenShell/CreateSandboxTemplate" + OpenShell_GetSandboxTemplate_FullMethodName = "/openshell.v1.OpenShell/GetSandboxTemplate" + OpenShell_ListSandboxTemplates_FullMethodName = "/openshell.v1.OpenShell/ListSandboxTemplates" + OpenShell_DeleteSandboxTemplate_FullMethodName = "/openshell.v1.OpenShell/DeleteSandboxTemplate" OpenShell_ListSandboxProviders_FullMethodName = "/openshell.v1.OpenShell/ListSandboxProviders" OpenShell_AttachSandboxProvider_FullMethodName = "/openshell.v1.OpenShell/AttachSandboxProvider" OpenShell_DetachSandboxProvider_FullMethodName = "/openshell.v1.OpenShell/DetachSandboxProvider" @@ -116,6 +120,14 @@ type OpenShellClient interface { GetSandbox(ctx context.Context, in *GetSandboxRequest, opts ...grpc.CallOption) (*SandboxResponse, error) // List sandboxes. ListSandboxes(ctx context.Context, in *ListSandboxesRequest, opts ...grpc.CallOption) (*ListSandboxesResponse, error) + // Create a reusable sandbox workload template. + CreateSandboxTemplate(ctx context.Context, in *CreateSandboxTemplateRequest, opts ...grpc.CallOption) (*SandboxTemplateResponse, error) + // Fetch a reusable sandbox workload template by name. + GetSandboxTemplate(ctx context.Context, in *GetSandboxTemplateRequest, opts ...grpc.CallOption) (*SandboxTemplateResponse, error) + // List reusable sandbox workload templates. + ListSandboxTemplates(ctx context.Context, in *ListSandboxTemplatesRequest, opts ...grpc.CallOption) (*ListSandboxTemplatesResponse, error) + // Delete a reusable sandbox workload template by name. + DeleteSandboxTemplate(ctx context.Context, in *DeleteSandboxTemplateRequest, opts ...grpc.CallOption) (*DeleteSandboxTemplateResponse, error) // List provider records attached to a sandbox. ListSandboxProviders(ctx context.Context, in *ListSandboxProvidersRequest, opts ...grpc.CallOption) (*ListSandboxProvidersResponse, error) // Attach a provider record to an existing sandbox. @@ -345,6 +357,46 @@ func (c *openShellClient) ListSandboxes(ctx context.Context, in *ListSandboxesRe return out, nil } +func (c *openShellClient) CreateSandboxTemplate(ctx context.Context, in *CreateSandboxTemplateRequest, opts ...grpc.CallOption) (*SandboxTemplateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SandboxTemplateResponse) + err := c.cc.Invoke(ctx, OpenShell_CreateSandboxTemplate_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) GetSandboxTemplate(ctx context.Context, in *GetSandboxTemplateRequest, opts ...grpc.CallOption) (*SandboxTemplateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SandboxTemplateResponse) + err := c.cc.Invoke(ctx, OpenShell_GetSandboxTemplate_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) ListSandboxTemplates(ctx context.Context, in *ListSandboxTemplatesRequest, opts ...grpc.CallOption) (*ListSandboxTemplatesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListSandboxTemplatesResponse) + err := c.cc.Invoke(ctx, OpenShell_ListSandboxTemplates_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *openShellClient) DeleteSandboxTemplate(ctx context.Context, in *DeleteSandboxTemplateRequest, opts ...grpc.CallOption) (*DeleteSandboxTemplateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteSandboxTemplateResponse) + err := c.cc.Invoke(ctx, OpenShell_DeleteSandboxTemplate_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *openShellClient) ListSandboxProviders(ctx context.Context, in *ListSandboxProvidersRequest, opts ...grpc.CallOption) (*ListSandboxProvidersResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListSandboxProvidersResponse) @@ -1003,6 +1055,14 @@ type OpenShellServer interface { GetSandbox(context.Context, *GetSandboxRequest) (*SandboxResponse, error) // List sandboxes. ListSandboxes(context.Context, *ListSandboxesRequest) (*ListSandboxesResponse, error) + // Create a reusable sandbox workload template. + CreateSandboxTemplate(context.Context, *CreateSandboxTemplateRequest) (*SandboxTemplateResponse, error) + // Fetch a reusable sandbox workload template by name. + GetSandboxTemplate(context.Context, *GetSandboxTemplateRequest) (*SandboxTemplateResponse, error) + // List reusable sandbox workload templates. + ListSandboxTemplates(context.Context, *ListSandboxTemplatesRequest) (*ListSandboxTemplatesResponse, error) + // Delete a reusable sandbox workload template by name. + DeleteSandboxTemplate(context.Context, *DeleteSandboxTemplateRequest) (*DeleteSandboxTemplateResponse, error) // List provider records attached to a sandbox. ListSandboxProviders(context.Context, *ListSandboxProvidersRequest) (*ListSandboxProvidersResponse, error) // Attach a provider record to an existing sandbox. @@ -1190,6 +1250,18 @@ func (UnimplementedOpenShellServer) GetSandbox(context.Context, *GetSandboxReque func (UnimplementedOpenShellServer) ListSandboxes(context.Context, *ListSandboxesRequest) (*ListSandboxesResponse, error) { return nil, status.Error(codes.Unimplemented, "method ListSandboxes not implemented") } +func (UnimplementedOpenShellServer) CreateSandboxTemplate(context.Context, *CreateSandboxTemplateRequest) (*SandboxTemplateResponse, error) { + return nil, status.Error(codes.Unimplemented, "method CreateSandboxTemplate not implemented") +} +func (UnimplementedOpenShellServer) GetSandboxTemplate(context.Context, *GetSandboxTemplateRequest) (*SandboxTemplateResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetSandboxTemplate not implemented") +} +func (UnimplementedOpenShellServer) ListSandboxTemplates(context.Context, *ListSandboxTemplatesRequest) (*ListSandboxTemplatesResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListSandboxTemplates not implemented") +} +func (UnimplementedOpenShellServer) DeleteSandboxTemplate(context.Context, *DeleteSandboxTemplateRequest) (*DeleteSandboxTemplateResponse, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteSandboxTemplate not implemented") +} func (UnimplementedOpenShellServer) ListSandboxProviders(context.Context, *ListSandboxProvidersRequest) (*ListSandboxProvidersResponse, error) { return nil, status.Error(codes.Unimplemented, "method ListSandboxProviders not implemented") } @@ -1499,6 +1571,78 @@ func _OpenShell_ListSandboxes_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _OpenShell_CreateSandboxTemplate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateSandboxTemplateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).CreateSandboxTemplate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_CreateSandboxTemplate_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).CreateSandboxTemplate(ctx, req.(*CreateSandboxTemplateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_GetSandboxTemplate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSandboxTemplateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).GetSandboxTemplate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_GetSandboxTemplate_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).GetSandboxTemplate(ctx, req.(*GetSandboxTemplateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_ListSandboxTemplates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListSandboxTemplatesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).ListSandboxTemplates(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_ListSandboxTemplates_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).ListSandboxTemplates(ctx, req.(*ListSandboxTemplatesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OpenShell_DeleteSandboxTemplate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSandboxTemplateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).DeleteSandboxTemplate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_DeleteSandboxTemplate_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).DeleteSandboxTemplate(ctx, req.(*DeleteSandboxTemplateRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _OpenShell_ListSandboxProviders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ListSandboxProvidersRequest) if err := dec(in); err != nil { @@ -2541,6 +2685,22 @@ var OpenShell_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListSandboxes", Handler: _OpenShell_ListSandboxes_Handler, }, + { + MethodName: "CreateSandboxTemplate", + Handler: _OpenShell_CreateSandboxTemplate_Handler, + }, + { + MethodName: "GetSandboxTemplate", + Handler: _OpenShell_GetSandboxTemplate_Handler, + }, + { + MethodName: "ListSandboxTemplates", + Handler: _OpenShell_ListSandboxTemplates_Handler, + }, + { + MethodName: "DeleteSandboxTemplate", + Handler: _OpenShell_DeleteSandboxTemplate_Handler, + }, { MethodName: "ListSandboxProviders", Handler: _OpenShell_ListSandboxProviders_Handler, diff --git a/sdk/typescript/src/client.test.ts b/sdk/typescript/src/client.test.ts index 5e72c27ba0..e420aef899 100644 --- a/sdk/typescript/src/client.test.ts +++ b/sdk/typescript/src/client.test.ts @@ -242,6 +242,46 @@ describe('create', () => { expect(created.spec?.providers).toEqual(['claude']); }); + it('createFromTemplate sends the workload template name with governance fields only', async () => { + let created: { + workloadTemplateName?: string; + name?: string; + labels?: Record; + spec?: { + policy?: { version?: number }; + providers?: string[]; + template?: { image?: string }; + }; + } = {}; + const sandbox = client({ + createSandbox: (req) => { + created = req; + return readySandbox('sb', 'sb-id'); + }, + }); + await sandbox.createFromTemplate({ + name: 'job-1', + templateName: 'gpu-kata', + labels: { team: 'runtime' }, + providers: ['github'], + policy: { version: 1, networkPolicies: {} }, + }); + + expect(created.workloadTemplateName).toBe('gpu-kata'); + expect(created.name).toBe('job-1'); + expect(created.labels).toEqual({ team: 'runtime' }); + expect(created.spec?.providers).toEqual(['github']); + expect(created.spec?.policy?.version).toBe(1); + expect(created.spec?.template).toBeUndefined(); + }); + + it('createFromTemplate rejects an empty template name locally', async () => { + const sandbox = client({}); + await expect(sandbox.createFromTemplate({ templateName: ' ' })).rejects.toMatchObject({ + code: 'invalid_config', + }); + }); + it('rejects gateway sandboxes missing required metadata', async () => { const sandbox = client({ getSandbox: () => ({ sandbox: { status: { phase: SandboxPhase.READY } } }), diff --git a/sdk/typescript/src/client.ts b/sdk/typescript/src/client.ts index 4650e3fdde..f8e5915121 100644 --- a/sdk/typescript/src/client.ts +++ b/sdk/typescript/src/client.ts @@ -98,6 +98,18 @@ export interface SandboxSpec { rawSpec?: MessageInitShape; } +export interface SandboxFromTemplateSpec { + name?: string; + templateName: string; + labels?: Record; + providers?: string[]; + /** + * Create-time sandbox policy (the safety boundary). The named workload + * template supplies runtime workload fields. + */ + policy?: MessageInitShape; +} + export interface SandboxRef { id: string; name: string; @@ -575,6 +587,24 @@ export class SandboxClient { } } + async createFromTemplate(spec: SandboxFromTemplateSpec): Promise { + if (spec.templateName.trim() === '') throw new SdkError('invalid_config', 'templateName is required'); + try { + const resp = await this.grpc.createSandbox({ + name: spec.name ?? '', + labels: spec.labels ?? {}, + spec: { + providers: spec.providers ?? [], + policy: spec.policy, + }, + workloadTemplateName: spec.templateName, + }); + return sandboxRef(resp.sandbox); + } catch (e) { + throw fromConnect(e); + } + } + async get(name: string, callOptions?: CallOptions): Promise { try { const resp = await this.grpc.getSandbox({ name }, callOptions); diff --git a/sdk/typescript/src/index.ts b/sdk/typescript/src/index.ts index 6dae221887..463619af8d 100644 --- a/sdk/typescript/src/index.ts +++ b/sdk/typescript/src/index.ts @@ -28,6 +28,7 @@ export type { ProviderChangeOptions, ProviderRef, SandboxConfig, + SandboxFromTemplateSpec, SandboxPhaseName, SandboxPolicy, SandboxRef, From ae73af015ee14b11fab1538d6cf374408f39214c Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 19 Aug 2026 14:23:55 +0100 Subject: [PATCH 2/9] feat(go-sdk): add sandbox workload template support Signed-off-by: Gordon Sim --- sdk/go/docs/src/SUMMARY.md | 1 + sdk/go/docs/src/api/client.md | 7 +- sdk/go/docs/src/api/fake.md | 11 +- sdk/go/docs/src/api/overview.md | 5 +- sdk/go/docs/src/api/sandbox-templates.md | 122 ++++++++ sdk/go/docs/src/api/sandboxes.md | 22 ++ sdk/go/openshell/v1/client.go | 36 ++- sdk/go/openshell/v1/fake/fake.go | 48 +++- sdk/go/openshell/v1/fake/sandbox.go | 82 +++++- sdk/go/openshell/v1/fake/sandbox_template.go | 115 ++++++++ .../v1/fake/sandbox_template_test.go | 202 ++++++++++++++ sdk/go/openshell/v1/fake/sandbox_test.go | 6 +- .../v1/internal/converter/coverage_test.go | 56 ++++ .../v1/internal/converter/sandbox.go | 213 ++++++++++++++ .../v1/internal/converter/sandbox_test.go | 99 +++++++ sdk/go/openshell/v1/sandbox_template.go | 42 +++ .../openshell/v1/sandbox_template_client.go | 93 +++++++ .../v1/sandbox_template_client_test.go | 260 ++++++++++++++++++ sdk/go/openshell/v1/types/sandbox.go | 72 ++++- 19 files changed, 1434 insertions(+), 58 deletions(-) create mode 100644 sdk/go/docs/src/api/sandbox-templates.md create mode 100644 sdk/go/openshell/v1/fake/sandbox_template.go create mode 100644 sdk/go/openshell/v1/fake/sandbox_template_test.go create mode 100644 sdk/go/openshell/v1/sandbox_template.go create mode 100644 sdk/go/openshell/v1/sandbox_template_client.go create mode 100644 sdk/go/openshell/v1/sandbox_template_client_test.go diff --git a/sdk/go/docs/src/SUMMARY.md b/sdk/go/docs/src/SUMMARY.md index 7a0915bfeb..bf500f68eb 100644 --- a/sdk/go/docs/src/SUMMARY.md +++ b/sdk/go/docs/src/SUMMARY.md @@ -15,6 +15,7 @@ - [Overview](api/overview.md) - [Client](api/client.md) - [Sandboxes](api/sandboxes.md) +- [Sandbox Templates](api/sandbox-templates.md) - [Exec](api/exec.md) - [Providers](api/providers.md) - [Profiles](api/profiles.md) diff --git a/sdk/go/docs/src/api/client.md b/sdk/go/docs/src/api/client.md index 748de5327e..9fe8b4aed9 100644 --- a/sdk/go/docs/src/api/client.md +++ b/sdk/go/docs/src/api/client.md @@ -2,14 +2,17 @@ Constructor: `v1.NewClient(config)` -The `ClientInterface` is the root entry point for all SDK operations. It provides -typed accessors for each resource domain and manages the underlying gRPC connection. +`Client` is the root entry point for SDK operations. It provides typed accessors +for each resource domain and manages the underlying gRPC connection. The +`ClientInterface` covers the stable core accessors; additive helpers such as +`SandboxTemplates()` are available on the concrete client. ## Methods | Accessor | Returns | Description | |----------|---------|-------------| | `Sandboxes()` | `SandboxInterface` | Sandbox lifecycle management | +| `SandboxTemplates()` | `SandboxTemplateInterface` | Reusable sandbox template management | | `Providers()` | `ProviderInterface` | Provider CRUD and idempotent ensure | | `Services()` | `ServiceInterface` | Service exposure and management | | `Exec()` | `ExecInterface` | Command execution (run, stream, interactive) | diff --git a/sdk/go/docs/src/api/fake.md b/sdk/go/docs/src/api/fake.md index 084858c542..ae96fc9d39 100644 --- a/sdk/go/docs/src/api/fake.md +++ b/sdk/go/docs/src/api/fake.md @@ -61,6 +61,13 @@ client.AddSandbox("default", &types.Sandbox{ Status: types.SandboxStatus{Phase: types.SandboxReady}, }) +client.AddSandboxTemplate("default", &types.SandboxWorkloadTemplate{ + Name: "gpu-kata", + Spec: types.SandboxWorkloadTemplateSpec{ + Workload: &types.SandboxWorkloadConfig{Image: "python:3.12"}, + }, +}) + client.AddProvider("default", &types.Provider{ Name: "my-provider", Spec: types.ProviderSpec{Type: "docker"}, @@ -78,11 +85,13 @@ insertion does not affect the stored object. ## Sub-Client Coverage -The fake client implements every interface in `v1.ClientInterface`: +The fake client implements every stable accessor in `v1.ClientInterface` plus +additive concrete-client accessors such as `SandboxTemplates()`: | Accessor | Interface | Behavior | |----------|-----------|----------| | `Sandboxes()` | `SandboxInterface` | Full CRUD, Watch, WaitReady | +| `SandboxTemplates()` | `SandboxTemplateInterface` | Full CRUD | | `Providers()` | `ProviderInterface` | Full CRUD, Ensure | | `Workspaces()` | `WorkspaceInterface` | Full CRUD, Members | | `Health()` | `HealthInterface` | Configurable result | diff --git a/sdk/go/docs/src/api/overview.md b/sdk/go/docs/src/api/overview.md index d96bbd747a..0ff01c4ce4 100644 --- a/sdk/go/docs/src/api/overview.md +++ b/sdk/go/docs/src/api/overview.md @@ -1,6 +1,7 @@ # API Overview -The OpenShell Go SDK exposes 12 interfaces through the sub-client pattern. You access each interface through a typed accessor on the `Client`. +The OpenShell Go SDK exposes typed interfaces through the sub-client pattern. +You access each interface through a typed accessor on the concrete `Client`. ## Interface Summary @@ -9,6 +10,7 @@ The OpenShell Go SDK exposes 12 interfaces through the sub-client pattern. You a | Interface | Accessor | Description | |-----------|----------|-------------| | [SandboxInterface](sandboxes.md) | `client.Sandboxes()` | Create, manage, and watch sandbox lifecycle | +| [SandboxTemplateInterface](sandbox-templates.md) | `client.SandboxTemplates()` | Manage reusable sandbox templates | | [ExecInterface](exec.md) | `client.Exec()` | Run commands, stream output, interactive sessions | | [ProviderInterface](providers.md) | `client.Providers()` | Manage compute providers and their lifecycle | | [ServiceInterface](services.md) | `client.Services()` | Expose and manage HTTP services inside sandboxes | @@ -39,6 +41,7 @@ These are accessed through `client.Providers()`: Each interface has a reference page with method signatures and usage examples: - **[Sandboxes](sandboxes.md)**: Create sandboxes, wait for readiness, watch state changes, manage providers, retrieve logs. +- **[Sandbox Templates](sandbox-templates.md)**: Create reusable workload templates and launch sandboxes from them. - **[Exec](exec.md)**: Execute commands with one-shot, streaming, or interactive modes. - **[Providers](providers.md)**: Register and manage compute providers. Includes sub-clients for profiles and credential refresh. - **[Services](services.md)**: Expose and manage HTTP services inside sandboxes. diff --git a/sdk/go/docs/src/api/sandbox-templates.md b/sdk/go/docs/src/api/sandbox-templates.md new file mode 100644 index 0000000000..66bc74fabc --- /dev/null +++ b/sdk/go/docs/src/api/sandbox-templates.md @@ -0,0 +1,122 @@ +# Sandbox Templates + +Accessor: `client.SandboxTemplates()` + +Manage reusable, workspace-scoped sandbox workload templates. Templates own the +portable workload shape and optional driver-specific config. Sandbox creation +can reference a template by name while supplying only governance fields such as +providers or policy. + +The Go SDK names the reusable resource `SandboxWorkloadTemplate` because +`SandboxTemplate` already represents the legacy inline compute template inside +`SandboxSpec`. + +## Create + +Creates a reusable template in a workspace. + +```go +gpuCount := uint32(1) + +template, err := client.SandboxTemplates().Create(ctx, "default", &v1.SandboxWorkloadTemplate{ + Name: "gpu-kata", + Labels: map[string]string{ + "team": "platform", + }, + Spec: v1.SandboxWorkloadTemplateSpec{ + Workload: &v1.SandboxWorkloadConfig{ + Image: "nvcr.io/nvidia/openshell:latest", + Environment: map[string]string{ + "NVIDIA_VISIBLE_DEVICES": "all", + }, + Resources: &v1.SandboxResources{ + CPU: "2", + Memory: "8Gi", + GPUCount: &gpuCount, + }, + }, + DriverConfig: map[string]any{ + "kubernetes": map[string]any{ + "runtimeClassName": "kata", + }, + }, + DesiredServiceLevel: &v1.SandboxServiceLevel{ + Startup: &v1.SandboxStartup{ + ReadyWithin: 45 * time.Second, + MaxBurst: 2, + }, + }, + }, +}) +``` + +## Create a Sandbox From a Template + +Use `CreateSandboxFromTemplate` to create a sandbox from a named reusable +template without changing the legacy `Sandboxes()` interface. + +```go +sb, err := client.CreateSandboxFromTemplate( + ctx, + "default", + "training-run", + "gpu-kata", + &v1.SandboxSpec{ + Providers: []string{"openai"}, + Policy: policy, + }, + map[string]string{"job": "training"}, +) +``` + +When creating from a template, the spec should only include governance fields: +`Providers` and `Policy`. Workload fields such as image, environment, CPU, +memory, GPU, and driver config come from the template. + +## Get + +Retrieves a template by name. + +```go +template, err := client.SandboxTemplates().Get(ctx, "default", "gpu-kata") +fmt.Println(template.Spec.Workload.Image) +``` + +## List + +Lists templates in one workspace or across all workspaces. + +```go +templates, err := client.SandboxTemplates().List(ctx, "default", v1.ListOptions{ + Limit: 50, + Offset: 0, +}) + +allTemplates, err := client.SandboxTemplates().List(ctx, "", v1.ListOptions{ + AllWorkspaces: true, +}) +``` + +## Delete + +Deletes a template by name. Existing sandboxes created from the template are not +deleted. + +```go +err := client.SandboxTemplates().Delete(ctx, "default", "gpu-kata") +``` + +## Fake Client + +The fake client includes the same template sub-client and can be pre-populated +for tests. + +```go +client := fake.NewClient() +client.AddSandboxTemplate("default", &types.SandboxWorkloadTemplate{ + Name: "gpu-kata", + Spec: types.SandboxWorkloadTemplateSpec{ + Workload: &types.SandboxWorkloadConfig{Image: "python:3.12"}, + }, +}) +``` diff --git a/sdk/go/docs/src/api/sandboxes.md b/sdk/go/docs/src/api/sandboxes.md index a9db856786..6f5542f37a 100644 --- a/sdk/go/docs/src/api/sandboxes.md +++ b/sdk/go/docs/src/api/sandboxes.md @@ -20,6 +20,28 @@ sb, err := client.Sandboxes().Create(ctx, "default", "my-sandbox", &v1.SandboxSp }) ``` +## Create From Template + +Creates a new sandbox from a reusable sandbox workload template. The template +provides workload fields such as image, environment, resources, and driver +config. The create request supplies governance fields such as providers and +policy. + +```go +sb, err := client.CreateSandboxFromTemplate(ctx, + "default", + "my-sandbox", + "gpu-kata", + &v1.SandboxSpec{ + Providers: []string{"openai"}, + Policy: policy, + }, + map[string]string{"team": "platform"}, +) +``` + +See [Sandbox Templates](sandbox-templates.md) for template CRUD. + ## Get Retrieves a sandbox by name. diff --git a/sdk/go/openshell/v1/client.go b/sdk/go/openshell/v1/client.go index ec011372a5..0315ba7538 100644 --- a/sdk/go/openshell/v1/client.go +++ b/sdk/go/openshell/v1/client.go @@ -50,18 +50,20 @@ type Client struct { closeOnce sync.Once closeErr error - sandboxes SandboxInterface - providers ProviderInterface - services ServiceInterface - exec ExecInterface - files FileInterface - health HealthInterface - ssh SSHInterface - tcp TCPInterface - cfg ConfigInterface - policy PolicyInterface - workspaces WorkspaceInterface - inference InferenceInterface + sandboxes SandboxInterface + templateCreate SandboxTemplateCreateInterface + templates SandboxTemplateInterface + providers ProviderInterface + services ServiceInterface + exec ExecInterface + files FileInterface + health HealthInterface + ssh SSHInterface + tcp TCPInterface + cfg ConfigInterface + policy PolicyInterface + workspaces WorkspaceInterface + inference InferenceInterface } // NewClient creates a new SDK client connected to the given gateway. @@ -94,7 +96,10 @@ func NewClient(cfg Config) (*Client, error) { config: cfg, } - c.sandboxes = newSandboxClient(conn) + sandboxes := newSandboxClient(conn) + c.sandboxes = sandboxes + c.templateCreate = sandboxes + c.templates = newSandboxTemplateClient(conn) c.providers = newProviderClient(conn) c.services = newServiceClient(conn) c.exec = newExecClient(conn, c.sandboxes) @@ -113,10 +118,13 @@ func NewClient(cfg Config) (*Client, error) { // Sandboxes returns the sandbox sub-client. func (c *Client) Sandboxes() SandboxInterface { return c.sandboxes } +// SandboxTemplates returns the reusable sandbox template sub-client. +func (c *Client) SandboxTemplates() SandboxTemplateInterface { return c.templates } + // CreateSandboxFromTemplate creates a sandbox from a named workload template // without changing the legacy Sandboxes() interface. func (c *Client) CreateSandboxFromTemplate(ctx context.Context, workspace, name, templateName string, spec *SandboxSpec, labels map[string]string, opts ...CreateOptions) (*Sandbox, error) { - return c.sandboxes.(SandboxTemplateCreateInterface).CreateFromTemplate(ctx, workspace, name, templateName, spec, labels, opts...) + return c.templateCreate.CreateFromTemplate(ctx, workspace, name, templateName, spec, labels, opts...) } // Providers returns the provider sub-client. diff --git a/sdk/go/openshell/v1/fake/fake.go b/sdk/go/openshell/v1/fake/fake.go index 7a82c0e1a6..16a35fed8a 100644 --- a/sdk/go/openshell/v1/fake/fake.go +++ b/sdk/go/openshell/v1/fake/fake.go @@ -16,23 +16,26 @@ import ( // real gRPC connection. Create one with NewClient. type Client struct { sandboxStore *objectStore[*types.Sandbox] + templateStore *objectStore[*types.SandboxWorkloadTemplate] providerStore *objectStore[*types.Provider] workspaceStore *objectStore[*types.Workspace] memberStore *objectStore[*types.WorkspaceMember] sandboxBroadcaster *watchBroadcaster[*types.Sandbox] - sandboxes v1.SandboxInterface - providers v1.ProviderInterface - services v1.ServiceInterface - exec v1.ExecInterface - files v1.FileInterface - health v1.HealthInterface - ssh v1.SSHInterface - tcp v1.TCPInterface - cfg v1.ConfigInterface - policy v1.PolicyInterface - workspaces v1.WorkspaceInterface - inference v1.InferenceInterface + sandboxes v1.SandboxInterface + templateCreate v1.SandboxTemplateCreateInterface + templates v1.SandboxTemplateInterface + providers v1.ProviderInterface + services v1.ServiceInterface + exec v1.ExecInterface + files v1.FileInterface + health v1.HealthInterface + ssh v1.SSHInterface + tcp v1.TCPInterface + cfg v1.ConfigInterface + policy v1.PolicyInterface + workspaces v1.WorkspaceInterface + inference v1.InferenceInterface closeOnce sync.Once closed bool @@ -71,13 +74,17 @@ func WithCurrentUser(user *types.CurrentUser) ClientOption { func NewClient(opts ...ClientOption) *Client { fc := &Client{ sandboxStore: newobjectStore(sandboxName, copySandbox), + templateStore: newobjectStore(sandboxWorkloadTemplateName, copySandboxWorkloadTemplate), providerStore: newobjectStore(providerName, copyProvider), workspaceStore: newobjectStore(workspaceName, copyWorkspace), memberStore: newobjectStore(memberName, copyMember), sandboxBroadcaster: newWatchBroadcaster[*types.Sandbox](), } - fc.sandboxes = newFakeSandboxClient(fc.sandboxStore, fc.sandboxBroadcaster, fc.isClosed) + sandboxes := newFakeSandboxClient(fc.sandboxStore, fc.templateStore, fc.sandboxBroadcaster, fc.isClosed) + fc.sandboxes = sandboxes + fc.templateCreate = sandboxes + fc.templates = newFakeSandboxTemplateClient(fc.templateStore, fc.isClosed) fc.providers = newFakeProviderClient(fc.providerStore, fc.isClosed) fc.services = newFakeServiceClient(fc.isClosed) fc.exec = newFakeExecClient(fc.isClosed) @@ -108,10 +115,13 @@ func (fc *Client) isClosed() bool { // Sandboxes returns the sandbox sub-client. func (fc *Client) Sandboxes() v1.SandboxInterface { return fc.sandboxes } +// SandboxTemplates returns the reusable sandbox template sub-client. +func (fc *Client) SandboxTemplates() v1.SandboxTemplateInterface { return fc.templates } + // CreateSandboxFromTemplate creates a sandbox from a named workload template // without changing the legacy Sandboxes() interface. func (fc *Client) CreateSandboxFromTemplate(ctx context.Context, workspace, name, templateName string, spec *types.SandboxSpec, labels map[string]string, opts ...types.CreateOptions) (*types.Sandbox, error) { - return fc.sandboxes.(v1.SandboxTemplateCreateInterface).CreateFromTemplate(ctx, workspace, name, templateName, spec, labels, opts...) + return fc.templateCreate.CreateFromTemplate(ctx, workspace, name, templateName, spec, labels, opts...) } // Providers returns the provider sub-client. @@ -171,6 +181,16 @@ func (fc *Client) AddSandbox(workspace string, sb *types.Sandbox) { fc.sandboxStore.Insert(workspace, sb) } +// AddSandboxTemplate inserts a sandbox workload template directly into the store. +// This is intended for pre-seeding test fixtures before the test begins. The +// template is deep-copied on insert. +func (fc *Client) AddSandboxTemplate(workspace string, template *types.SandboxWorkloadTemplate) { + if template == nil { + return + } + fc.templateStore.Insert(workspace, template) +} + // AddProvider inserts a provider directly into the store without triggering // any side effects. This is intended for pre-seeding test fixtures before // the test begins. The provider is deep-copied on insert. diff --git a/sdk/go/openshell/v1/fake/sandbox.go b/sdk/go/openshell/v1/fake/sandbox.go index f34e44a33f..68474c4e58 100644 --- a/sdk/go/openshell/v1/fake/sandbox.go +++ b/sdk/go/openshell/v1/fake/sandbox.go @@ -32,6 +32,10 @@ func copySandbox(sb *types.Sandbox) *types.Sandbox { t := *sb.DeletionTimestamp cp.DeletionTimestamp = &t } + if sb.CreatedFromWorkloadTemplate != nil { + provenance := *sb.CreatedFromWorkloadTemplate + cp.CreatedFromWorkloadTemplate = &provenance + } cp.Spec = copySandboxSpec(sb.Spec) cp.Status = copySandboxStatus(sb.Status) return &cp @@ -255,9 +259,10 @@ func copyStringSlice(s []string) []string { // fakeSandboxClient implements v1.SandboxInterface backed by an in-memory // objectStore and watchBroadcaster. type fakeSandboxClient struct { - store *objectStore[*types.Sandbox] - broadcaster *watchBroadcaster[*types.Sandbox] - closedFunc func() bool + store *objectStore[*types.Sandbox] + templateStore *objectStore[*types.SandboxWorkloadTemplate] + broadcaster *watchBroadcaster[*types.Sandbox] + closedFunc func() bool } var _ v1.SandboxInterface = (*fakeSandboxClient)(nil) @@ -266,13 +271,15 @@ var _ v1.SandboxTemplateCreateInterface = (*fakeSandboxClient)(nil) // newFakeSandboxClient creates a new fakeSandboxClient. func newFakeSandboxClient( store *objectStore[*types.Sandbox], + templateStore *objectStore[*types.SandboxWorkloadTemplate], broadcaster *watchBroadcaster[*types.Sandbox], closedFunc func() bool, ) *fakeSandboxClient { return &fakeSandboxClient{ - store: store, - broadcaster: broadcaster, - closedFunc: closedFunc, + store: store, + templateStore: templateStore, + broadcaster: broadcaster, + closedFunc: closedFunc, } } @@ -326,6 +333,10 @@ func (c *fakeSandboxClient) CreateFromTemplate(_ context.Context, workspace, nam if templateName == "" { return nil, &types.StatusError{Code: types.ErrorInvalidArgument, Message: "template name is required"} } + template, err := c.templateStore.Get(workspace, templateName) + if err != nil { + return nil, err + } if spec == nil { spec = &types.SandboxSpec{} } @@ -335,15 +346,21 @@ func (c *fakeSandboxClient) CreateFromTemplate(_ context.Context, workspace, nam annotations = copyStringMap(opts[0].Annotations) } + resolvedSpec := sandboxSpecFromWorkloadTemplate(template) + resolvedSpec.Providers = copyStringSlice(spec.Providers) + resolvedSpec.Policy = copySandboxPolicy(spec.Policy) + sb := &types.Sandbox{ - Name: name, - Workspace: workspace, - CreatedAt: time.Now(), - Labels: copyStringMap(labels), - Annotations: annotations, - Spec: types.SandboxSpec{ - Providers: copyStringSlice(spec.Providers), - Policy: copySandboxPolicy(spec.Policy), + Name: name, + Workspace: workspace, + CreatedAt: time.Now(), + Labels: copyStringMap(labels), + Annotations: annotations, + ResourceVersion: 1, + Spec: resolvedSpec, + CreatedFromWorkloadTemplate: &types.SandboxWorkloadTemplateProvenance{ + Name: template.Name, + ResourceVersion: fmt.Sprint(template.ResourceVersion), }, Status: types.SandboxStatus{ SandboxName: name, @@ -364,6 +381,43 @@ func (c *fakeSandboxClient) CreateFromTemplate(_ context.Context, workspace, nam return result, nil } +func sandboxSpecFromWorkloadTemplate(template *types.SandboxWorkloadTemplate) types.SandboxSpec { + var spec types.SandboxSpec + if template == nil || template.Spec.Workload == nil { + return spec + } + + workload := template.Spec.Workload + spec.Environment = copyStringMap(workload.Environment) + spec.Template = &types.SandboxTemplate{ + Image: workload.Image, + Resources: sandboxTemplateResources(workload.Resources), + DriverConfig: copyAnyMap(template.Spec.DriverConfig), + } + if workload.Resources != nil && workload.Resources.GPUCount != nil { + count := *workload.Resources.GPUCount + spec.GPUCount = &count + } + return spec +} + +func sandboxTemplateResources(resources *types.SandboxResources) map[string]any { + if resources == nil { + return nil + } + limits := make(map[string]any) + if resources.CPU != "" { + limits["cpu"] = resources.CPU + } + if resources.Memory != "" { + limits["memory"] = resources.Memory + } + if len(limits) == 0 { + return nil + } + return map[string]any{"limits": limits} +} + // Get retrieves a sandbox by name. func (c *fakeSandboxClient) Get(_ context.Context, workspace, name string) (*types.Sandbox, error) { if c.closedFunc() { diff --git a/sdk/go/openshell/v1/fake/sandbox_template.go b/sdk/go/openshell/v1/fake/sandbox_template.go new file mode 100644 index 0000000000..0cab5f8a95 --- /dev/null +++ b/sdk/go/openshell/v1/fake/sandbox_template.go @@ -0,0 +1,115 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package fake + +import ( + "context" + "time" + + v1 "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1" + "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types" +) + +func sandboxWorkloadTemplateName(template *types.SandboxWorkloadTemplate) string { + return template.Name +} + +func copySandboxWorkloadTemplate(template *types.SandboxWorkloadTemplate) *types.SandboxWorkloadTemplate { + if template == nil { + return nil + } + copied := *template + copied.Labels = copyStringMap(template.Labels) + copied.Annotations = copyStringMap(template.Annotations) + if template.DeletionTimestamp != nil { + t := *template.DeletionTimestamp + copied.DeletionTimestamp = &t + } + copied.Spec = copySandboxWorkloadTemplateSpec(template.Spec) + return &copied +} + +func copySandboxWorkloadTemplateSpec(spec types.SandboxWorkloadTemplateSpec) types.SandboxWorkloadTemplateSpec { + if spec.Workload != nil { + workload := *spec.Workload + workload.Environment = copyStringMap(spec.Workload.Environment) + if spec.Workload.Resources != nil { + resources := *spec.Workload.Resources + if spec.Workload.Resources.GPUCount != nil { + count := *spec.Workload.Resources.GPUCount + resources.GPUCount = &count + } + workload.Resources = &resources + } + spec.Workload = &workload + } + spec.DriverConfig = copyAnyMap(spec.DriverConfig) + if spec.DesiredServiceLevel != nil { + level := *spec.DesiredServiceLevel + if spec.DesiredServiceLevel.Startup != nil { + startup := *spec.DesiredServiceLevel.Startup + level.Startup = &startup + } + spec.DesiredServiceLevel = &level + } + return spec +} + +type fakeSandboxTemplateClient struct { + store *objectStore[*types.SandboxWorkloadTemplate] + closedFunc func() bool +} + +var _ v1.SandboxTemplateInterface = (*fakeSandboxTemplateClient)(nil) + +func newFakeSandboxTemplateClient( + store *objectStore[*types.SandboxWorkloadTemplate], + closedFunc func() bool, +) *fakeSandboxTemplateClient { + return &fakeSandboxTemplateClient{ + store: store, + closedFunc: closedFunc, + } +} + +func (c *fakeSandboxTemplateClient) Create(_ context.Context, workspace string, template *types.SandboxWorkloadTemplate) (*types.SandboxWorkloadTemplate, error) { + if c.closedFunc() { + return nil, &types.StatusError{Code: types.ErrorUnavailable, Message: "client is closed"} + } + if template == nil { + return nil, &types.StatusError{Code: types.ErrorInvalidArgument, Message: "template must not be nil"} + } + + t := copySandboxWorkloadTemplate(template) + t.Workspace = workspace + t.CreatedAt = time.Now() + t.ResourceVersion = 1 + + return c.store.Create(workspace, t) +} + +func (c *fakeSandboxTemplateClient) Get(_ context.Context, workspace, name string) (*types.SandboxWorkloadTemplate, error) { + if c.closedFunc() { + return nil, &types.StatusError{Code: types.ErrorUnavailable, Message: "client is closed"} + } + return c.store.Get(workspace, name) +} + +func (c *fakeSandboxTemplateClient) List(_ context.Context, workspace string, opts ...v1.ListOptions) ([]*types.SandboxWorkloadTemplate, error) { + if c.closedFunc() { + return nil, &types.StatusError{Code: types.ErrorUnavailable, Message: "client is closed"} + } + if len(opts) > 0 && opts[0].AllWorkspaces { + return c.store.ListAll(), nil + } + return c.store.List(workspace), nil +} + +func (c *fakeSandboxTemplateClient) Delete(_ context.Context, workspace, name string) error { + if c.closedFunc() { + return &types.StatusError{Code: types.ErrorUnavailable, Message: "client is closed"} + } + c.store.Delete(workspace, name) + return nil +} diff --git a/sdk/go/openshell/v1/fake/sandbox_template_test.go b/sdk/go/openshell/v1/fake/sandbox_template_test.go new file mode 100644 index 0000000000..b5eab7b69b --- /dev/null +++ b/sdk/go/openshell/v1/fake/sandbox_template_test.go @@ -0,0 +1,202 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package fake + +import ( + "context" + "testing" + "time" + + "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func newTestSandboxTemplateClient() *fakeSandboxTemplateClient { + store := newobjectStore(sandboxWorkloadTemplateName, copySandboxWorkloadTemplate) + return newFakeSandboxTemplateClient(store, func() bool { return false }) +} + +func TestSandboxTemplate_CreateGetListDelete(t *testing.T) { + tc := newTestSandboxTemplateClient() + ctx := context.Background() + + template := &types.SandboxWorkloadTemplate{ + Name: "gpu-kata", + Labels: map[string]string{"team": "platform"}, + Spec: types.SandboxWorkloadTemplateSpec{ + Workload: &types.SandboxWorkloadConfig{Image: "python:3.12"}, + DriverConfig: map[string]any{"kubernetes": map[string]any{"runtime_class_name": "kata"}}, + DesiredServiceLevel: &types.SandboxServiceLevel{ + Startup: &types.SandboxStartup{ReadyWithin: 30 * time.Second, MaxBurst: 4}, + }, + }, + } + + created, err := tc.Create(ctx, "default", template) + require.NoError(t, err) + assert.Equal(t, "gpu-kata", created.Name) + assert.Equal(t, "default", created.Workspace) + assert.Equal(t, uint64(1), created.ResourceVersion) + assert.NotZero(t, created.CreatedAt) + + got, err := tc.Get(ctx, "default", "gpu-kata") + require.NoError(t, err) + assert.Equal(t, "python:3.12", got.Spec.Workload.Image) + assert.Equal(t, "kata", got.Spec.DriverConfig["kubernetes"].(map[string]any)["runtime_class_name"]) + + listed, err := tc.List(ctx, "default") + require.NoError(t, err) + require.Len(t, listed, 1) + assert.Equal(t, "gpu-kata", listed[0].Name) + + err = tc.Delete(ctx, "default", "gpu-kata") + require.NoError(t, err) + _, err = tc.Get(ctx, "default", "gpu-kata") + require.Error(t, err) + assert.True(t, types.IsNotFound(err)) +} + +func TestSandboxTemplate_CreateAlreadyExists(t *testing.T) { + tc := newTestSandboxTemplateClient() + ctx := context.Background() + + template := &types.SandboxWorkloadTemplate{Name: "gpu-kata"} + _, err := tc.Create(ctx, "default", template) + require.NoError(t, err) + + _, err = tc.Create(ctx, "default", template) + require.Error(t, err) + assert.True(t, types.IsAlreadyExists(err)) +} + +func TestSandboxTemplate_ListAllWorkspaces(t *testing.T) { + tc := newTestSandboxTemplateClient() + ctx := context.Background() + + _, _ = tc.Create(ctx, "default", &types.SandboxWorkloadTemplate{Name: "default-template"}) + _, _ = tc.Create(ctx, "team-a", &types.SandboxWorkloadTemplate{Name: "team-template"}) + + listed, err := tc.List(ctx, "default", types.ListOptions{AllWorkspaces: true}) + require.NoError(t, err) + assert.Len(t, listed, 2) +} + +func TestSandboxTemplate_CreateSandboxFromTemplateRequiresExistingTemplate(t *testing.T) { + client := NewClient() + ctx := context.Background() + + _, err := client.CreateSandboxFromTemplate(ctx, "default", "job-1", "missing", nil, nil) + + require.Error(t, err) + assert.True(t, types.IsNotFound(err)) +} + +func TestSandboxTemplate_CreateSandboxFromTemplateResolvesWorkloadAndGovernance(t *testing.T) { + client := NewClient() + ctx := context.Background() + gpuCount := uint32(1) + policy := &types.SandboxPolicy{ + Version: 1, + NetworkPolicies: map[string]types.NetworkPolicyRule{ + "api": {Name: "api"}, + }, + } + client.AddSandboxTemplate("default", &types.SandboxWorkloadTemplate{ + Name: "gpu-kata", + ResourceVersion: 7, + Spec: types.SandboxWorkloadTemplateSpec{ + Workload: &types.SandboxWorkloadConfig{ + Image: "registry.example.com/agent:latest", + Environment: map[string]string{"FEATURE_FLAG": "on"}, + Resources: &types.SandboxResources{ + CPU: "2", + Memory: "4Gi", + GPUCount: &gpuCount, + }, + }, + DriverConfig: map[string]any{ + "kubernetes": map[string]any{"runtime_class_name": "kata-containers"}, + }, + }, + }) + + created, err := client.CreateSandboxFromTemplate( + ctx, + "default", + "job-1", + "gpu-kata", + &types.SandboxSpec{ + Providers: []string{"github"}, + Policy: policy, + }, + map[string]string{"team": "runtime"}, + ) + + require.NoError(t, err) + assert.Equal(t, "job-1", created.Name) + assert.Equal(t, map[string]string{"team": "runtime"}, created.Labels) + assert.Equal(t, map[string]string{"FEATURE_FLAG": "on"}, created.Spec.Environment) + require.NotNil(t, created.Spec.Template) + assert.Equal(t, "registry.example.com/agent:latest", created.Spec.Template.Image) + assert.Equal(t, map[string]any{"limits": map[string]any{"cpu": "2", "memory": "4Gi"}}, created.Spec.Template.Resources) + assert.Equal(t, "kata-containers", created.Spec.Template.DriverConfig["kubernetes"].(map[string]any)["runtime_class_name"]) + require.NotNil(t, created.Spec.GPUCount) + assert.Equal(t, uint32(1), *created.Spec.GPUCount) + assert.Equal(t, []string{"github"}, created.Spec.Providers) + require.NotNil(t, created.Spec.Policy) + assert.Equal(t, uint32(1), created.Spec.Policy.Version) + require.NotNil(t, created.CreatedFromWorkloadTemplate) + assert.Equal(t, "gpu-kata", created.CreatedFromWorkloadTemplate.Name) + assert.Equal(t, "7", created.CreatedFromWorkloadTemplate.ResourceVersion) +} + +func TestSandboxTemplate_DeepCopy(t *testing.T) { + tc := newTestSandboxTemplateClient() + ctx := context.Background() + + template := &types.SandboxWorkloadTemplate{ + Name: "gpu-kata", + Spec: types.SandboxWorkloadTemplateSpec{ + Workload: &types.SandboxWorkloadConfig{ + Image: "python:3.12", + Environment: map[string]string{"KEY": "value"}, + }, + DriverConfig: map[string]any{"kubernetes": map[string]any{"runtime_class_name": "kata"}}, + }, + } + + created, err := tc.Create(ctx, "default", template) + require.NoError(t, err) + + template.Spec.Workload.Image = "mutated" + template.Spec.Workload.Environment["KEY"] = "mutated" + template.Spec.DriverConfig["kubernetes"].(map[string]any)["runtime_class_name"] = "mutated" + created.Spec.Workload.Image = "mutated-return" + + got, err := tc.Get(ctx, "default", "gpu-kata") + require.NoError(t, err) + assert.Equal(t, "python:3.12", got.Spec.Workload.Image) + assert.Equal(t, "value", got.Spec.Workload.Environment["KEY"]) + assert.Equal(t, "kata", got.Spec.DriverConfig["kubernetes"].(map[string]any)["runtime_class_name"]) +} + +func TestSandboxTemplate_CreateNil(t *testing.T) { + tc := newTestSandboxTemplateClient() + ctx := context.Background() + + _, err := tc.Create(ctx, "default", nil) + require.Error(t, err) + assert.True(t, types.IsInvalidArgument(err)) +} + +func TestSandboxTemplate_ClosedReturnsUnavailable(t *testing.T) { + store := newobjectStore(sandboxWorkloadTemplateName, copySandboxWorkloadTemplate) + tc := newFakeSandboxTemplateClient(store, func() bool { return true }) + ctx := context.Background() + + _, err := tc.Create(ctx, "default", &types.SandboxWorkloadTemplate{Name: "gpu-kata"}) + require.Error(t, err) + assert.True(t, types.IsUnavailable(err)) +} diff --git a/sdk/go/openshell/v1/fake/sandbox_test.go b/sdk/go/openshell/v1/fake/sandbox_test.go index b675621891..f36d30686d 100644 --- a/sdk/go/openshell/v1/fake/sandbox_test.go +++ b/sdk/go/openshell/v1/fake/sandbox_test.go @@ -20,8 +20,9 @@ import ( // helper to build a minimal fake sandbox client for testing. func newTestSandboxClient() *fakeSandboxClient { store := newobjectStore(sandboxName, copySandbox) + templateStore := newobjectStore(sandboxWorkloadTemplateName, copySandboxWorkloadTemplate) broadcaster := newWatchBroadcaster[*types.Sandbox]() - return newFakeSandboxClient(store, broadcaster, func() bool { return false }) + return newFakeSandboxClient(store, templateStore, broadcaster, func() bool { return false }) } // --- T008: Sandbox CRUD tests --- @@ -924,8 +925,9 @@ func TestSandbox_GetLogs_ReturnsUnimplemented(t *testing.T) { func TestSandbox_GetLogs_ClosedReturnsUnavailable(t *testing.T) { store := newobjectStore(sandboxName, copySandbox) + templateStore := newobjectStore(sandboxWorkloadTemplateName, copySandboxWorkloadTemplate) broadcaster := newWatchBroadcaster[*types.Sandbox]() - sc := newFakeSandboxClient(store, broadcaster, func() bool { return true }) + sc := newFakeSandboxClient(store, templateStore, broadcaster, func() bool { return true }) _, err := sc.GetLogs(context.Background(), "default", "sb-1") require.Error(t, err) assert.True(t, types.IsUnavailable(err)) diff --git a/sdk/go/openshell/v1/internal/converter/coverage_test.go b/sdk/go/openshell/v1/internal/converter/coverage_test.go index 33edebf64f..107964cd38 100644 --- a/sdk/go/openshell/v1/internal/converter/coverage_test.go +++ b/sdk/go/openshell/v1/internal/converter/coverage_test.go @@ -50,6 +50,62 @@ func TestConverterCoversAllProtoFields_SandboxTemplate(t *testing.T) { assertAllFieldsCovered(t, (&pb.SandboxTemplate{}).ProtoReflect().Descriptor(), handled, nil) } +func TestConverterCoversAllProtoFields_SandboxWorkloadTemplate(t *testing.T) { + handled := fieldSet{ + "metadata": true, + "spec": true, + } + + assertAllFieldsCovered(t, (&pb.SandboxWorkloadTemplate{}).ProtoReflect().Descriptor(), handled, nil) +} + +func TestConverterCoversAllProtoFields_SandboxWorkloadTemplateSpec(t *testing.T) { + handled := fieldSet{ + "workload": true, + "driver_config": true, + "desired_service_level": true, + } + + assertAllFieldsCovered(t, (&pb.SandboxWorkloadTemplateSpec{}).ProtoReflect().Descriptor(), handled, nil) +} + +func TestConverterCoversAllProtoFields_SandboxWorkloadConfig(t *testing.T) { + handled := fieldSet{ + "image": true, + "environment": true, + "resources": true, + } + + assertAllFieldsCovered(t, (&pb.SandboxWorkloadConfig{}).ProtoReflect().Descriptor(), handled, nil) +} + +func TestConverterCoversAllProtoFields_SandboxResources(t *testing.T) { + handled := fieldSet{ + "cpu": true, + "memory": true, + "gpu_count": true, + } + + assertAllFieldsCovered(t, (&pb.SandboxResources{}).ProtoReflect().Descriptor(), handled, nil) +} + +func TestConverterCoversAllProtoFields_SandboxServiceLevel(t *testing.T) { + handled := fieldSet{ + "startup": true, + } + + assertAllFieldsCovered(t, (&pb.SandboxServiceLevel{}).ProtoReflect().Descriptor(), handled, nil) +} + +func TestConverterCoversAllProtoFields_SandboxStartup(t *testing.T) { + handled := fieldSet{ + "ready_within": true, + "max_burst": true, + } + + assertAllFieldsCovered(t, (&pb.SandboxStartup{}).ProtoReflect().Descriptor(), handled, nil) +} + func TestConverterCoversAllProtoFields_SandboxStatus(t *testing.T) { handled := fieldSet{ "sandbox_name": true, diff --git a/sdk/go/openshell/v1/internal/converter/sandbox.go b/sdk/go/openshell/v1/internal/converter/sandbox.go index f44210fd2e..b6e54804b6 100644 --- a/sdk/go/openshell/v1/internal/converter/sandbox.go +++ b/sdk/go/openshell/v1/internal/converter/sandbox.go @@ -5,10 +5,12 @@ package converter import ( "fmt" + "time" "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types" dm "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1" pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1" + "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/structpb" ) @@ -31,6 +33,13 @@ func SandboxFromProto(s *pb.Sandbox) *types.Sandbox { result.DeletionTimestamp = TimeFromMillisPtr(m.GetDeletionTimestampMs()) } + if provenance := s.GetCreatedFromWorkloadTemplate(); provenance != nil { + result.CreatedFromWorkloadTemplate = &types.SandboxWorkloadTemplateProvenance{ + Name: provenance.GetName(), + ResourceVersion: provenance.GetResourceVersion(), + } + } + if spec := s.GetSpec(); spec != nil { result.Spec = sandboxSpecFromProto(spec) } @@ -254,3 +263,207 @@ func SandboxSpecToProtoChecked(spec *types.SandboxSpec) (*pb.SandboxSpec, error) } return result, nil } + +// SandboxWorkloadTemplateFromProto converts a reusable template proto to an SDK template. +func SandboxWorkloadTemplateFromProto(t *pb.SandboxWorkloadTemplate) *types.SandboxWorkloadTemplate { + if t == nil { + return nil + } + + result := &types.SandboxWorkloadTemplate{} + if m := t.GetMetadata(); m != nil { + result.ID = m.GetId() + result.Name = m.GetName() + result.CreatedAt = TimeFromMillis(m.GetCreatedAtMs()) + result.Labels = CopyStringMap(m.GetLabels()) + result.Annotations = CopyStringMap(m.GetAnnotations()) + result.ResourceVersion = m.GetResourceVersion() + result.Workspace = m.GetWorkspace() + result.DeletionTimestamp = TimeFromMillisPtr(m.GetDeletionTimestampMs()) + } + if spec := t.GetSpec(); spec != nil { + result.Spec = SandboxWorkloadTemplateSpecFromProto(spec) + } + return result +} + +// SandboxWorkloadTemplateSpecFromProto converts a reusable template spec proto. +func SandboxWorkloadTemplateSpecFromProto(spec *pb.SandboxWorkloadTemplateSpec) types.SandboxWorkloadTemplateSpec { + result := types.SandboxWorkloadTemplateSpec{} + if spec == nil { + return result + } + result.Workload = SandboxWorkloadConfigFromProto(spec.GetWorkload()) + result.DesiredServiceLevel = SandboxServiceLevelFromProto(spec.GetDesiredServiceLevel()) + if dc := spec.GetDriverConfig(); dc != nil { + result.DriverConfig = dc.AsMap() + } + return result +} + +// SandboxWorkloadConfigFromProto converts a portable workload proto. +func SandboxWorkloadConfigFromProto(workload *pb.SandboxWorkloadConfig) *types.SandboxWorkloadConfig { + if workload == nil { + return nil + } + return &types.SandboxWorkloadConfig{ + Image: workload.GetImage(), + Environment: CopyStringMap(workload.GetEnvironment()), + Resources: SandboxResourcesFromProto(workload.GetResources()), + } +} + +// SandboxResourcesFromProto converts portable resource requirements. +func SandboxResourcesFromProto(resources *pb.SandboxResources) *types.SandboxResources { + if resources == nil { + return nil + } + return &types.SandboxResources{ + CPU: resources.GetCpu(), + Memory: resources.GetMemory(), + GPUCount: CopyUint32Ptr(resources.GpuCount), + } +} + +// SandboxServiceLevelFromProto converts template service-level hints. +func SandboxServiceLevelFromProto(level *pb.SandboxServiceLevel) *types.SandboxServiceLevel { + if level == nil { + return nil + } + return &types.SandboxServiceLevel{ + Startup: SandboxStartupFromProto(level.GetStartup()), + } +} + +// SandboxStartupFromProto converts startup service-level hints. +func SandboxStartupFromProto(startup *pb.SandboxStartup) *types.SandboxStartup { + if startup == nil { + return nil + } + return &types.SandboxStartup{ + ReadyWithin: durationFromProto(startup.GetReadyWithin()), + MaxBurst: startup.GetMaxBurst(), + } +} + +// SandboxWorkloadTemplateToProto converts an SDK reusable template to proto. +func SandboxWorkloadTemplateToProto(t *types.SandboxWorkloadTemplate) *pb.SandboxWorkloadTemplate { + if t == nil { + return nil + } + return &pb.SandboxWorkloadTemplate{ + Metadata: &dm.ObjectMeta{ + Id: t.ID, + Name: t.Name, + CreatedAtMs: MillisFromTime(t.CreatedAt), + Labels: CopyStringMap(t.Labels), + Annotations: CopyStringMap(t.Annotations), + ResourceVersion: t.ResourceVersion, + Workspace: t.Workspace, + DeletionTimestampMs: MillisFromTimePtr(t.DeletionTimestamp), + }, + Spec: SandboxWorkloadTemplateSpecToProto(&t.Spec), + } +} + +// SandboxWorkloadTemplateSpecToProto converts an SDK reusable template spec to proto. +func SandboxWorkloadTemplateSpecToProto(spec *types.SandboxWorkloadTemplateSpec) *pb.SandboxWorkloadTemplateSpec { + if spec == nil { + return nil + } + result := &pb.SandboxWorkloadTemplateSpec{ + Workload: SandboxWorkloadConfigToProto(spec.Workload), + DesiredServiceLevel: SandboxServiceLevelToProto(spec.DesiredServiceLevel), + } + if spec.DriverConfig != nil { + if driverConfig, err := structpb.NewStruct(spec.DriverConfig); err == nil { + result.DriverConfig = driverConfig + } + } + return result +} + +// SandboxWorkloadConfigToProto converts an SDK portable workload to proto. +func SandboxWorkloadConfigToProto(workload *types.SandboxWorkloadConfig) *pb.SandboxWorkloadConfig { + if workload == nil { + return nil + } + return &pb.SandboxWorkloadConfig{ + Image: workload.Image, + Environment: CopyStringMap(workload.Environment), + Resources: SandboxResourcesToProto(workload.Resources), + } +} + +// SandboxResourcesToProto converts portable resource requirements. +func SandboxResourcesToProto(resources *types.SandboxResources) *pb.SandboxResources { + if resources == nil { + return nil + } + return &pb.SandboxResources{ + Cpu: resources.CPU, + Memory: resources.Memory, + GpuCount: CopyUint32Ptr(resources.GPUCount), + } +} + +// SandboxServiceLevelToProto converts template service-level hints. +func SandboxServiceLevelToProto(level *types.SandboxServiceLevel) *pb.SandboxServiceLevel { + if level == nil { + return nil + } + return &pb.SandboxServiceLevel{ + Startup: SandboxStartupToProto(level.Startup), + } +} + +// SandboxStartupToProto converts startup service-level hints. +func SandboxStartupToProto(startup *types.SandboxStartup) *pb.SandboxStartup { + if startup == nil { + return nil + } + return &pb.SandboxStartup{ + ReadyWithin: durationToProto(startup.ReadyWithin), + MaxBurst: startup.MaxBurst, + } +} + +// SandboxWorkloadTemplateToProtoChecked converts an SDK reusable template and +// reports driver config values that protobuf Struct cannot represent. +func SandboxWorkloadTemplateToProtoChecked(t *types.SandboxWorkloadTemplate) (*pb.SandboxWorkloadTemplate, error) { + result := SandboxWorkloadTemplateToProto(t) + if t == nil { + return result, nil + } + if t.Spec.DriverConfig != nil { + driverConfig, err := structpb.NewStruct(t.Spec.DriverConfig) + if err != nil { + return nil, fmt.Errorf("driver config: %w", err) + } + result.Spec.DriverConfig = driverConfig + } + return result, nil +} + +// CopyUint32Ptr returns a copy of a *uint32 pointer. +func CopyUint32Ptr(p *uint32) *uint32 { + if p == nil { + return nil + } + v := *p + return &v +} + +func durationFromProto(d *durationpb.Duration) time.Duration { + if d == nil { + return 0 + } + return d.AsDuration() +} + +func durationToProto(d time.Duration) *durationpb.Duration { + if d == 0 { + return nil + } + return durationpb.New(d) +} diff --git a/sdk/go/openshell/v1/internal/converter/sandbox_test.go b/sdk/go/openshell/v1/internal/converter/sandbox_test.go index b0b721eda1..14952791c7 100644 --- a/sdk/go/openshell/v1/internal/converter/sandbox_test.go +++ b/sdk/go/openshell/v1/internal/converter/sandbox_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/structpb" ) @@ -57,6 +58,10 @@ func TestSandboxFromProto(t *testing.T) { }, }, }, + CreatedFromWorkloadTemplate: &pb.SandboxWorkloadTemplateProvenance{ + Name: "gpu-kata", + ResourceVersion: "7", + }, Status: &pb.SandboxStatus{ SandboxName: "sb-compute-1", AgentPod: "agent-pod-xyz", @@ -88,6 +93,9 @@ func TestSandboxFromProto(t *testing.T) { assert.Equal(t, "prod", s.Workspace) require.NotNil(t, s.DeletionTimestamp) assert.Equal(t, time.UnixMilli(1700000060000).UTC(), *s.DeletionTimestamp) + require.NotNil(t, s.CreatedFromWorkloadTemplate) + assert.Equal(t, "gpu-kata", s.CreatedFromWorkloadTemplate.Name) + assert.Equal(t, "7", s.CreatedFromWorkloadTemplate.ResourceVersion) // Spec assert.Equal(t, "debug", s.Spec.LogLevel) @@ -299,6 +307,97 @@ func TestSandboxToProto_NilTemplate(t *testing.T) { assert.Nil(t, p.Spec.ResourceRequirements) } +func TestSandboxWorkloadTemplateRoundTrip(t *testing.T) { + gpuCount := uint32(2) + delTime := time.UnixMilli(1700000060000).UTC() + original := &v1.SandboxWorkloadTemplate{ + ID: "tmpl-1", + Name: "gpu-kata", + CreatedAt: time.UnixMilli(1700000000000).UTC(), + Labels: map[string]string{"team": "platform"}, + Annotations: map[string]string{"note": "fast-start"}, + ResourceVersion: 9, + Workspace: "prod", + DeletionTimestamp: &delTime, + Spec: v1.SandboxWorkloadTemplateSpec{ + Workload: &v1.SandboxWorkloadConfig{ + Image: "nvcr.io/nvidia/openshell:latest", + Environment: map[string]string{"CUDA_VISIBLE_DEVICES": "all"}, + Resources: &v1.SandboxResources{ + CPU: "2", + Memory: "8Gi", + GPUCount: &gpuCount, + }, + }, + DriverConfig: map[string]any{ + "kubernetes": map[string]any{"runtimeClassName": "kata"}, + }, + DesiredServiceLevel: &v1.SandboxServiceLevel{ + Startup: &v1.SandboxStartup{ + ReadyWithin: 30 * time.Second, + MaxBurst: 3, + }, + }, + }, + } + + protoTemplate, err := SandboxWorkloadTemplateToProtoChecked(original) + require.NoError(t, err) + + require.NotNil(t, protoTemplate.Metadata) + assert.Equal(t, "gpu-kata", protoTemplate.Metadata.Name) + require.NotNil(t, protoTemplate.Spec) + require.NotNil(t, protoTemplate.Spec.Workload) + assert.Equal(t, "nvcr.io/nvidia/openshell:latest", protoTemplate.Spec.Workload.Image) + assert.Equal(t, map[string]string{"CUDA_VISIBLE_DEVICES": "all"}, protoTemplate.Spec.Workload.Environment) + require.NotNil(t, protoTemplate.Spec.Workload.Resources) + assert.Equal(t, "2", protoTemplate.Spec.Workload.Resources.Cpu) + assert.Equal(t, "8Gi", protoTemplate.Spec.Workload.Resources.Memory) + require.NotNil(t, protoTemplate.Spec.Workload.Resources.GpuCount) + assert.Equal(t, uint32(2), *protoTemplate.Spec.Workload.Resources.GpuCount) + require.NotNil(t, protoTemplate.Spec.DriverConfig) + require.NotNil(t, protoTemplate.Spec.DesiredServiceLevel) + require.NotNil(t, protoTemplate.Spec.DesiredServiceLevel.Startup) + assert.Equal(t, durationpb.New(30*time.Second), protoTemplate.Spec.DesiredServiceLevel.Startup.ReadyWithin) + assert.Equal(t, uint32(3), protoTemplate.Spec.DesiredServiceLevel.Startup.MaxBurst) + + back := SandboxWorkloadTemplateFromProto(protoTemplate) + require.NotNil(t, back) + assert.Equal(t, original.ID, back.ID) + assert.Equal(t, original.Name, back.Name) + assert.Equal(t, original.CreatedAt, back.CreatedAt) + assert.Equal(t, original.Labels, back.Labels) + assert.Equal(t, original.Annotations, back.Annotations) + assert.Equal(t, original.ResourceVersion, back.ResourceVersion) + assert.Equal(t, original.Workspace, back.Workspace) + require.NotNil(t, back.DeletionTimestamp) + assert.Equal(t, *original.DeletionTimestamp, *back.DeletionTimestamp) + require.NotNil(t, back.Spec.Workload) + assert.Equal(t, original.Spec.Workload.Image, back.Spec.Workload.Image) + assert.Equal(t, original.Spec.Workload.Environment, back.Spec.Workload.Environment) + require.NotNil(t, back.Spec.Workload.Resources) + assert.Equal(t, original.Spec.Workload.Resources.CPU, back.Spec.Workload.Resources.CPU) + assert.Equal(t, original.Spec.Workload.Resources.Memory, back.Spec.Workload.Resources.Memory) + require.NotNil(t, back.Spec.Workload.Resources.GPUCount) + assert.Equal(t, *original.Spec.Workload.Resources.GPUCount, *back.Spec.Workload.Resources.GPUCount) + assert.Equal(t, "kata", back.Spec.DriverConfig["kubernetes"].(map[string]any)["runtimeClassName"]) + require.NotNil(t, back.Spec.DesiredServiceLevel) + require.NotNil(t, back.Spec.DesiredServiceLevel.Startup) + assert.Equal(t, 30*time.Second, back.Spec.DesiredServiceLevel.Startup.ReadyWithin) + assert.Equal(t, uint32(3), back.Spec.DesiredServiceLevel.Startup.MaxBurst) +} + +func TestSandboxWorkloadTemplateToProtoChecked_RejectsUnrepresentableDriverConfig(t *testing.T) { + _, err := SandboxWorkloadTemplateToProtoChecked(&v1.SandboxWorkloadTemplate{ + Name: "bad", + Spec: v1.SandboxWorkloadTemplateSpec{ + DriverConfig: map[string]any{"invalid": make(chan int)}, + }, + }) + require.Error(t, err) + assert.Contains(t, err.Error(), "driver config") +} + func TestSandboxRoundTrip(t *testing.T) { userNS := false gpuCount := uint32(1) diff --git a/sdk/go/openshell/v1/sandbox_template.go b/sdk/go/openshell/v1/sandbox_template.go new file mode 100644 index 0000000000..bc94aaf741 --- /dev/null +++ b/sdk/go/openshell/v1/sandbox_template.go @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package v1 + +import ( + "context" + + "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types" +) + +// SandboxWorkloadTemplate is a reusable workspace-scoped sandbox template resource. +type SandboxWorkloadTemplate = types.SandboxWorkloadTemplate + +// SandboxWorkloadTemplateSpec holds reusable sandbox template settings. +type SandboxWorkloadTemplateSpec = types.SandboxWorkloadTemplateSpec + +// SandboxWorkloadConfig defines the portable workload for a reusable template. +type SandboxWorkloadConfig = types.SandboxWorkloadConfig + +// SandboxResources defines portable sandbox resource requirements. +type SandboxResources = types.SandboxResources + +// SandboxServiceLevel describes desired operational characteristics. +type SandboxServiceLevel = types.SandboxServiceLevel + +// SandboxStartup describes desired startup characteristics. +type SandboxStartup = types.SandboxStartup + +// SandboxWorkloadTemplateProvenance identifies the reusable template revision used to create a sandbox. +type SandboxWorkloadTemplateProvenance = types.SandboxWorkloadTemplateProvenance + +// SandboxTemplateInterface defines CRUD operations on reusable sandbox templates. +// +// The resource type is named SandboxWorkloadTemplate in the v1 Go SDK so it does +// not collide with the legacy inline SandboxTemplate field on SandboxSpec. +type SandboxTemplateInterface interface { + Create(ctx context.Context, workspace string, template *SandboxWorkloadTemplate) (*SandboxWorkloadTemplate, error) + Get(ctx context.Context, workspace, name string) (*SandboxWorkloadTemplate, error) + List(ctx context.Context, workspace string, opts ...ListOptions) ([]*SandboxWorkloadTemplate, error) + Delete(ctx context.Context, workspace, name string) error +} diff --git a/sdk/go/openshell/v1/sandbox_template_client.go b/sdk/go/openshell/v1/sandbox_template_client.go new file mode 100644 index 0000000000..7ead55395d --- /dev/null +++ b/sdk/go/openshell/v1/sandbox_template_client.go @@ -0,0 +1,93 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package v1 + +import ( + "context" + + "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/internal/converter" + pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1" + "google.golang.org/grpc" +) + +type sandboxTemplateClient struct { + client pb.OpenShellClient +} + +var _ SandboxTemplateInterface = (*sandboxTemplateClient)(nil) + +func newSandboxTemplateClient(conn grpc.ClientConnInterface) *sandboxTemplateClient { + return &sandboxTemplateClient{client: pb.NewOpenShellClient(conn)} +} + +func (s *sandboxTemplateClient) Create(ctx context.Context, workspace string, template *SandboxWorkloadTemplate) (*SandboxWorkloadTemplate, error) { + if template == nil { + return nil, &StatusError{Code: ErrorInvalidArgument, Message: "template must not be nil"} + } + protoTemplate, err := converter.SandboxWorkloadTemplateToProtoChecked(template) + if err != nil { + return nil, &StatusError{Code: ErrorInvalidArgument, Message: err.Error()} + } + resp, err := s.client.CreateSandboxTemplate(ctx, &pb.CreateSandboxTemplateRequest{ + Template: protoTemplate, + Workspace: workspace, + }) + if err != nil { + return nil, converter.FromGRPCError(err) + } + return converter.SandboxWorkloadTemplateFromProto(resp.GetTemplate()), nil +} + +func (s *sandboxTemplateClient) Get(ctx context.Context, workspace, name string) (*SandboxWorkloadTemplate, error) { + resp, err := s.client.GetSandboxTemplate(ctx, &pb.GetSandboxTemplateRequest{ + Name: name, + Workspace: workspace, + }) + if err != nil { + return nil, converter.FromGRPCError(err) + } + return converter.SandboxWorkloadTemplateFromProto(resp.GetTemplate()), nil +} + +func (s *sandboxTemplateClient) List(ctx context.Context, workspace string, opts ...ListOptions) ([]*SandboxWorkloadTemplate, error) { + req := &pb.ListSandboxTemplatesRequest{ + Workspace: workspace, + } + if len(opts) > 0 { + if opts[0].Limit < 0 { + return nil, &StatusError{Code: ErrorInvalidArgument, Message: "limit must not be negative"} + } + if opts[0].Offset < 0 { + return nil, &StatusError{Code: ErrorInvalidArgument, Message: "offset must not be negative"} + } + req.Limit = uint32(opts[0].Limit) + req.Offset = uint32(opts[0].Offset) + req.AllWorkspaces = opts[0].AllWorkspaces + if req.AllWorkspaces { + req.Workspace = "" + } + } + + resp, err := s.client.ListSandboxTemplates(ctx, req) + if err != nil { + return nil, converter.FromGRPCError(err) + } + + templates := make([]*SandboxWorkloadTemplate, 0, len(resp.GetTemplates())) + for _, protoTemplate := range resp.GetTemplates() { + templates = append(templates, converter.SandboxWorkloadTemplateFromProto(protoTemplate)) + } + return templates, nil +} + +func (s *sandboxTemplateClient) Delete(ctx context.Context, workspace, name string) error { + _, err := s.client.DeleteSandboxTemplate(ctx, &pb.DeleteSandboxTemplateRequest{ + Name: name, + Workspace: workspace, + }) + if err != nil { + return converter.FromGRPCError(err) + } + return nil +} diff --git a/sdk/go/openshell/v1/sandbox_template_client_test.go b/sdk/go/openshell/v1/sandbox_template_client_test.go new file mode 100644 index 0000000000..864a13bd5e --- /dev/null +++ b/sdk/go/openshell/v1/sandbox_template_client_test.go @@ -0,0 +1,260 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package v1 + +import ( + "context" + "net" + "sync" + "testing" + "time" + + dm "github.com/NVIDIA/OpenShell/sdk/go/proto/datamodelv1" + pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" + "google.golang.org/grpc/test/bufconn" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" +) + +type mockSandboxTemplateServer struct { + pb.UnimplementedOpenShellServer + mu sync.Mutex + + templates map[string]*pb.SandboxWorkloadTemplate + + createRequest *pb.CreateSandboxTemplateRequest + getRequest *pb.GetSandboxTemplateRequest + listRequest *pb.ListSandboxTemplatesRequest + deleteRequest *pb.DeleteSandboxTemplateRequest + + createErr error + getErr error + listErr error + deleteErr error +} + +func newMockSandboxTemplateServer() *mockSandboxTemplateServer { + return &mockSandboxTemplateServer{ + templates: make(map[string]*pb.SandboxWorkloadTemplate), + } +} + +func (s *mockSandboxTemplateServer) CreateSandboxTemplate(_ context.Context, req *pb.CreateSandboxTemplateRequest) (*pb.SandboxTemplateResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + s.createRequest = proto.Clone(req).(*pb.CreateSandboxTemplateRequest) + if s.createErr != nil { + return nil, s.createErr + } + template := proto.Clone(req.GetTemplate()).(*pb.SandboxWorkloadTemplate) + if template.Metadata == nil { + template.Metadata = &dm.ObjectMeta{} + } + template.Metadata.Workspace = req.GetWorkspace() + template.Metadata.ResourceVersion = 1 + s.templates[template.Metadata.GetName()] = template + return &pb.SandboxTemplateResponse{Template: proto.Clone(template).(*pb.SandboxWorkloadTemplate)}, nil +} + +func (s *mockSandboxTemplateServer) GetSandboxTemplate(_ context.Context, req *pb.GetSandboxTemplateRequest) (*pb.SandboxTemplateResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + s.getRequest = proto.Clone(req).(*pb.GetSandboxTemplateRequest) + if s.getErr != nil { + return nil, s.getErr + } + template, ok := s.templates[req.GetName()] + if !ok { + return nil, status.Errorf(codes.NotFound, "template %q not found", req.GetName()) + } + return &pb.SandboxTemplateResponse{Template: proto.Clone(template).(*pb.SandboxWorkloadTemplate)}, nil +} + +func (s *mockSandboxTemplateServer) ListSandboxTemplates(_ context.Context, req *pb.ListSandboxTemplatesRequest) (*pb.ListSandboxTemplatesResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + s.listRequest = proto.Clone(req).(*pb.ListSandboxTemplatesRequest) + if s.listErr != nil { + return nil, s.listErr + } + templates := make([]*pb.SandboxWorkloadTemplate, 0, len(s.templates)) + for _, template := range s.templates { + templates = append(templates, proto.Clone(template).(*pb.SandboxWorkloadTemplate)) + } + return &pb.ListSandboxTemplatesResponse{Templates: templates}, nil +} + +func (s *mockSandboxTemplateServer) DeleteSandboxTemplate(_ context.Context, req *pb.DeleteSandboxTemplateRequest) (*pb.DeleteSandboxTemplateResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + s.deleteRequest = proto.Clone(req).(*pb.DeleteSandboxTemplateRequest) + if s.deleteErr != nil { + return nil, s.deleteErr + } + delete(s.templates, req.GetName()) + return &pb.DeleteSandboxTemplateResponse{Deleted: true}, nil +} + +func setupSandboxTemplateTest(t *testing.T, mock *mockSandboxTemplateServer) (*sandboxTemplateClient, func()) { + t.Helper() + lis := bufconn.Listen(bufSize) + srv := grpc.NewServer() + pb.RegisterOpenShellServer(srv, mock) + go func() { _ = srv.Serve(lis) }() + + conn, err := grpc.NewClient("passthrough:///bufconn", + grpc.WithContextDialer(func(_ context.Context, _ string) (net.Conn, error) { + return lis.Dial() + }), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + require.NoError(t, err) + + return newSandboxTemplateClient(conn), func() { + _ = conn.Close() + srv.Stop() + } +} + +func TestSandboxTemplateCreate(t *testing.T) { + mock := newMockSandboxTemplateServer() + client, cleanup := setupSandboxTemplateTest(t, mock) + defer cleanup() + gpuCount := uint32(1) + + template, err := client.Create(context.Background(), "default", &SandboxWorkloadTemplate{ + Name: "gpu-kata", + Labels: map[string]string{ + "team": "platform", + }, + Spec: SandboxWorkloadTemplateSpec{ + Workload: &SandboxWorkloadConfig{ + Image: "nvcr.io/nvidia/openshell:latest", + Environment: map[string]string{"NVIDIA_VISIBLE_DEVICES": "all"}, + Resources: &SandboxResources{ + CPU: "2", + Memory: "8Gi", + GPUCount: &gpuCount, + }, + }, + DriverConfig: map[string]any{ + "kubernetes": map[string]any{"runtimeClassName": "kata"}, + }, + DesiredServiceLevel: &SandboxServiceLevel{ + Startup: &SandboxStartup{ + ReadyWithin: 45 * time.Second, + MaxBurst: 2, + }, + }, + }, + }) + + require.NoError(t, err) + require.NotNil(t, template) + assert.Equal(t, "gpu-kata", template.Name) + assert.Equal(t, "default", template.Workspace) + assert.Equal(t, uint64(1), template.ResourceVersion) + mock.mu.Lock() + defer mock.mu.Unlock() + require.NotNil(t, mock.createRequest) + assert.Equal(t, "default", mock.createRequest.Workspace) + assert.Equal(t, "gpu-kata", mock.createRequest.Template.Metadata.Name) + assert.Equal(t, "2", mock.createRequest.Template.Spec.Workload.Resources.Cpu) + assert.Equal(t, "8Gi", mock.createRequest.Template.Spec.Workload.Resources.Memory) + assert.Equal(t, uint32(1), mock.createRequest.Template.Spec.Workload.Resources.GetGpuCount()) + assert.Equal(t, durationpb.New(45*time.Second), mock.createRequest.Template.Spec.DesiredServiceLevel.Startup.ReadyWithin) +} + +func TestSandboxTemplateCreate_RejectsNilTemplate(t *testing.T) { + mock := newMockSandboxTemplateServer() + client, cleanup := setupSandboxTemplateTest(t, mock) + defer cleanup() + + _, err := client.Create(context.Background(), "default", nil) + + require.Error(t, err) + assert.True(t, IsInvalidArgument(err)) +} + +func TestSandboxTemplateCreate_RejectsUnrepresentableDriverConfigBeforeRPC(t *testing.T) { + mock := newMockSandboxTemplateServer() + client, cleanup := setupSandboxTemplateTest(t, mock) + defer cleanup() + + _, err := client.Create(context.Background(), "default", &SandboxWorkloadTemplate{ + Name: "bad", + Spec: SandboxWorkloadTemplateSpec{ + DriverConfig: map[string]any{"invalid": make(chan int)}, + }, + }) + + require.Error(t, err) + assert.True(t, IsInvalidArgument(err)) + mock.mu.Lock() + defer mock.mu.Unlock() + assert.Nil(t, mock.createRequest) +} + +func TestSandboxTemplateGetListDelete(t *testing.T) { + mock := newMockSandboxTemplateServer() + mock.templates["gpu-kata"] = &pb.SandboxWorkloadTemplate{ + Metadata: &dm.ObjectMeta{Name: "gpu-kata", Workspace: "default"}, + Spec: &pb.SandboxWorkloadTemplateSpec{ + Workload: &pb.SandboxWorkloadConfig{Image: "img:v1"}, + }, + } + client, cleanup := setupSandboxTemplateTest(t, mock) + defer cleanup() + + got, err := client.Get(context.Background(), "default", "gpu-kata") + require.NoError(t, err) + assert.Equal(t, "gpu-kata", got.Name) + assert.Equal(t, "img:v1", got.Spec.Workload.Image) + + list, err := client.List(context.Background(), "default", ListOptions{ + Limit: 10, + Offset: 2, + AllWorkspaces: true, + }) + require.NoError(t, err) + require.Len(t, list, 1) + assert.Equal(t, "gpu-kata", list[0].Name) + + err = client.Delete(context.Background(), "default", "gpu-kata") + require.NoError(t, err) + + mock.mu.Lock() + defer mock.mu.Unlock() + require.NotNil(t, mock.getRequest) + assert.Equal(t, "default", mock.getRequest.Workspace) + assert.Equal(t, "gpu-kata", mock.getRequest.Name) + require.NotNil(t, mock.listRequest) + assert.Empty(t, mock.listRequest.Workspace) + assert.Equal(t, uint32(10), mock.listRequest.Limit) + assert.Equal(t, uint32(2), mock.listRequest.Offset) + assert.True(t, mock.listRequest.AllWorkspaces) + require.NotNil(t, mock.deleteRequest) + assert.Equal(t, "default", mock.deleteRequest.Workspace) + assert.Equal(t, "gpu-kata", mock.deleteRequest.Name) +} + +func TestSandboxTemplateList_RejectsNegativePagination(t *testing.T) { + mock := newMockSandboxTemplateServer() + client, cleanup := setupSandboxTemplateTest(t, mock) + defer cleanup() + + _, err := client.List(context.Background(), "default", ListOptions{Limit: -1}) + require.Error(t, err) + assert.True(t, IsInvalidArgument(err)) + + _, err = client.List(context.Background(), "default", ListOptions{Offset: -1}) + require.Error(t, err) + assert.True(t, IsInvalidArgument(err)) +} diff --git a/sdk/go/openshell/v1/types/sandbox.go b/sdk/go/openshell/v1/types/sandbox.go index 5851ff48d7..1629db9999 100644 --- a/sdk/go/openshell/v1/types/sandbox.go +++ b/sdk/go/openshell/v1/types/sandbox.go @@ -7,16 +7,17 @@ import "time" // Sandbox represents a sandbox instance. type Sandbox struct { - ID string - Name string - CreatedAt time.Time - Labels map[string]string - Annotations map[string]string - ResourceVersion uint64 - Workspace string - DeletionTimestamp *time.Time - Spec SandboxSpec - Status SandboxStatus + ID string + Name string + CreatedAt time.Time + Labels map[string]string + Annotations map[string]string + ResourceVersion uint64 + Workspace string + DeletionTimestamp *time.Time + CreatedFromWorkloadTemplate *SandboxWorkloadTemplateProvenance + Spec SandboxSpec + Status SandboxStatus } // SandboxSpec holds the desired state of a sandbox. @@ -43,6 +44,57 @@ type SandboxTemplate struct { DriverConfig map[string]any } +// SandboxWorkloadTemplate is a reusable workspace-scoped sandbox template resource. +type SandboxWorkloadTemplate struct { + ID string + Name string + CreatedAt time.Time + Labels map[string]string + Annotations map[string]string + ResourceVersion uint64 + Workspace string + DeletionTimestamp *time.Time + Spec SandboxWorkloadTemplateSpec +} + +// SandboxWorkloadTemplateSpec holds reusable sandbox template settings. +type SandboxWorkloadTemplateSpec struct { + Workload *SandboxWorkloadConfig + DriverConfig map[string]any + DesiredServiceLevel *SandboxServiceLevel +} + +// SandboxWorkloadConfig defines the portable workload for a reusable template. +type SandboxWorkloadConfig struct { + Image string + Environment map[string]string + Resources *SandboxResources +} + +// SandboxResources defines portable sandbox resource requirements. +type SandboxResources struct { + CPU string + Memory string + GPUCount *uint32 +} + +// SandboxServiceLevel describes desired operational characteristics. +type SandboxServiceLevel struct { + Startup *SandboxStartup +} + +// SandboxStartup describes desired startup characteristics. +type SandboxStartup struct { + ReadyWithin time.Duration + MaxBurst uint32 +} + +// SandboxWorkloadTemplateProvenance identifies the reusable template revision used to create a sandbox. +type SandboxWorkloadTemplateProvenance struct { + Name string + ResourceVersion string +} + // SandboxStatus holds the observed state of a sandbox. type SandboxStatus struct { SandboxName string From 4821ee029e31fd21cd97ec9a4788e69a9c722c38 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 19 Aug 2026 21:10:01 +0100 Subject: [PATCH 3/9] feat(rust-sdk): add sandbox workload template support Signed-off-by: Gordon Sim --- crates/openshell-sdk/README.md | 52 ++++- crates/openshell-sdk/src/client.rs | 147 +++++++++++++- crates/openshell-sdk/src/lib.rs | 9 +- crates/openshell-sdk/src/raw.rs | 8 +- crates/openshell-sdk/src/types.rs | 35 ++++ crates/openshell-sdk/tests/client_mock.rs | 231 +++++++++++++++++++++- 6 files changed, 462 insertions(+), 20 deletions(-) diff --git a/crates/openshell-sdk/README.md b/crates/openshell-sdk/README.md index 93afc5359e..cb42e12dc1 100644 --- a/crates/openshell-sdk/README.md +++ b/crates/openshell-sdk/README.md @@ -9,7 +9,8 @@ gateway-name resolution. ## Two layers - `OpenShellClient` — the curated, sandbox-focused surface: health, sandbox - CRUD, readiness/deletion waits, and non-streaming exec. + CRUD, reusable sandbox template CRUD, readiness/deletion waits, and + non-streaming exec. - `raw` — direct access to the generated tonic clients for RPCs the curated surface doesn't yet cover (inference, providers, policy, logs, settings, SSH, forwarding). @@ -44,10 +45,53 @@ mTLS (client certificates) is not supported. `OpenShellClient::connect(ClientConfig)` returns a connected client exposing `health`, `create_sandbox`, `get_sandbox`, `list_sandboxes`, `delete_sandbox`, +`create_sandbox_from_template`, `create_sandbox_template`, +`get_sandbox_template`, `list_sandbox_templates`, `delete_sandbox_template`, `wait_ready`, `wait_deleted`, and `exec`. Curated types (`SandboxSpec`, -`SandboxRef`, `Health`, `ListOptions`, `ExecOptions`, `SandboxPhase`) use -SDK-shaped enums rather than raw proto integers. Failures map to a typed -`SdkError` with a discriminable kind. +`SandboxRef`, `Health`, `ListOptions`, `SandboxTemplateListOptions`, +`ExecOptions`, `SandboxPhase`) use SDK-shaped enums rather than raw proto +integers where practical. Reusable template resources are exposed as +`SandboxWorkloadTemplate` proto aliases so callers can populate the full +portable workload shape and driver config. Failures map to a typed `SdkError` +with a discriminable kind. + +```rust +use openshell_sdk::{ + ClientConfig, OpenShellClient, SandboxTemplateCreateSpec, + SandboxWorkloadConfig, SandboxWorkloadTemplate, SandboxWorkloadTemplateSpec, +}; + +# async fn run() -> Result<(), openshell_sdk::SdkError> { +let client = OpenShellClient::connect(ClientConfig::new("http://127.0.0.1:8080")).await?; +client + .create_sandbox_template(SandboxWorkloadTemplate { + metadata: Some(openshell_sdk::raw::proto::datamodel::v1::ObjectMeta { + name: "python".to_string(), + ..Default::default() + }), + spec: Some(SandboxWorkloadTemplateSpec { + workload: Some(SandboxWorkloadConfig { + image: "ghcr.io/nvidia/openshell-community/sandboxes/python:latest".to_string(), + ..Default::default() + }), + ..Default::default() + }), + }) + .await?; + +let _sandbox = client + .create_sandbox_from_template(SandboxTemplateCreateSpec { + template_name: "python".to_string(), + policy: Some(openshell_sdk::raw::proto::SandboxPolicy { + version: 1, + ..Default::default() + }), + ..Default::default() + }) + .await?; +# Ok(()) +# } +``` ## Modules diff --git a/crates/openshell-sdk/src/client.rs b/crates/openshell-sdk/src/client.rs index 5e907eb73f..9aa5d7e605 100644 --- a/crates/openshell-sdk/src/client.rs +++ b/crates/openshell-sdk/src/client.rs @@ -16,7 +16,7 @@ use crate::refresh::{RefreshedToken, TokenSource}; use crate::transport; use crate::types::{ ExecOptions, ExecResult, Health, ListOptions, SandboxPhase, SandboxRef, SandboxSpec, - SandboxTemplateCreateSpec, WorkspaceRef, + SandboxTemplateCreateSpec, SandboxTemplateListOptions, SandboxWorkloadTemplate, WorkspaceRef, }; use futures::StreamExt; use openshell_core::proto; @@ -178,6 +178,70 @@ impl OpenShellClient { sandbox_from_response(response.sandbox) } + /// Create a reusable sandbox template in the default workspace. + pub async fn create_sandbox_template( + &self, + template: SandboxWorkloadTemplate, + ) -> Result { + let response = self + .unary(|mut grpc| { + let request = proto::CreateSandboxTemplateRequest { + template: Some(template.clone()), + workspace: String::new(), + }; + async move { grpc.create_sandbox_template(request).await } + }) + .await?; + sandbox_template_from_response(response.template) + } + + /// Fetch a reusable sandbox template by name from the default workspace. + pub async fn get_sandbox_template(&self, name: &str) -> Result { + let response = self + .unary(|mut grpc| { + let request = proto::GetSandboxTemplateRequest { + name: name.to_string(), + workspace: String::new(), + }; + async move { grpc.get_sandbox_template(request).await } + }) + .await?; + sandbox_template_from_response(response.template) + } + + /// List reusable sandbox templates in the default workspace or across all workspaces. + pub async fn list_sandbox_templates( + &self, + opts: SandboxTemplateListOptions, + ) -> Result> { + let response = self + .unary(|mut grpc| { + let request = proto::ListSandboxTemplatesRequest { + limit: opts.limit, + offset: opts.offset, + workspace: String::new(), + all_workspaces: opts.all_workspaces, + }; + async move { grpc.list_sandbox_templates(request).await } + }) + .await?; + Ok(response.templates) + } + + /// Delete a reusable sandbox template by name from the default workspace. + pub async fn delete_sandbox_template(&self, name: &str) -> Result { + let response = self + .unary(|mut grpc| { + let request = proto::DeleteSandboxTemplateRequest { + name: name.to_string(), + workspace: String::new(), + }; + async move { grpc.delete_sandbox_template(request).await } + }) + .await?; + Ok(response.deleted) + } + /// Fetch a sandbox by name. pub async fn get_sandbox(&self, name: &str) -> Result { let response = self @@ -594,6 +658,78 @@ impl WorkspaceScopedClient { sandbox_from_response(response.sandbox) } + /// Create a reusable sandbox template in this workspace. + pub async fn create_sandbox_template( + &self, + template: SandboxWorkloadTemplate, + ) -> Result { + let response = self + .client + .unary(|mut grpc| { + let request = proto::CreateSandboxTemplateRequest { + template: Some(template.clone()), + workspace: self.workspace.clone(), + }; + async move { grpc.create_sandbox_template(request).await } + }) + .await?; + sandbox_template_from_response(response.template) + } + + /// Fetch a reusable sandbox template by name in this workspace. + pub async fn get_sandbox_template(&self, name: &str) -> Result { + let response = self + .client + .unary(|mut grpc| { + let request = proto::GetSandboxTemplateRequest { + name: name.to_string(), + workspace: self.workspace.clone(), + }; + async move { grpc.get_sandbox_template(request).await } + }) + .await?; + sandbox_template_from_response(response.template) + } + + /// List reusable sandbox templates in this workspace, or across all workspaces. + pub async fn list_sandbox_templates( + &self, + opts: SandboxTemplateListOptions, + ) -> Result> { + let response = self + .client + .unary(|mut grpc| { + let request = proto::ListSandboxTemplatesRequest { + limit: opts.limit, + offset: opts.offset, + workspace: if opts.all_workspaces { + String::new() + } else { + self.workspace.clone() + }, + all_workspaces: opts.all_workspaces, + }; + async move { grpc.list_sandbox_templates(request).await } + }) + .await?; + Ok(response.templates) + } + + /// Delete a reusable sandbox template by name in this workspace. + pub async fn delete_sandbox_template(&self, name: &str) -> Result { + let response = self + .client + .unary(|mut grpc| { + let request = proto::DeleteSandboxTemplateRequest { + name: name.to_string(), + workspace: self.workspace.clone(), + }; + async move { grpc.delete_sandbox_template(request).await } + }) + .await?; + Ok(response.deleted) + } + /// Fetch a sandbox by name in this workspace. pub async fn get_sandbox(&self, name: &str) -> Result { let response = self @@ -863,10 +999,12 @@ fn create_sandbox_from_template_request( template_name, labels, providers, + policy, } = spec; proto::CreateSandboxRequest { spec: Some(proto::SandboxSpec { providers, + policy, ..proto::SandboxSpec::default() }), name: name.unwrap_or_default(), @@ -883,6 +1021,13 @@ fn sandbox_from_response(sandbox: Option) -> Result .ok_or_else(|| SdkError::invalid_config("sandbox missing from gateway response")) } +fn sandbox_template_from_response( + template: Option, +) -> Result { + template + .ok_or_else(|| SdkError::invalid_config("sandbox template missing from gateway response")) +} + fn map_status(status: tonic::Status) -> SdkError { let message = status.message().to_string(); match status.code() { diff --git a/crates/openshell-sdk/src/lib.rs b/crates/openshell-sdk/src/lib.rs index 72258e708b..f12faa42e9 100644 --- a/crates/openshell-sdk/src/lib.rs +++ b/crates/openshell-sdk/src/lib.rs @@ -6,7 +6,8 @@ //! Two layers: //! //! - [`OpenShellClient`] — the high-level sandbox-focused MVP surface: -//! health, sandbox CRUD, readiness/deletion waits, non-streaming exec. +//! health, sandbox CRUD, reusable sandbox templates, readiness/deletion +//! waits, and non-streaming exec. //! - [`raw`] — direct access to the generated tonic clients for RPCs the //! curated surface doesn't yet cover (inference, providers, policy, logs, //! settings, SSH, forwarding). @@ -46,6 +47,8 @@ pub use config::{AuthConfig, ClientConfig}; pub use error::SdkError; pub use refresh::{Refresh, RefreshError, RefreshedToken, TokenSource}; pub use types::{ - ExecOptions, ExecResult, Health, ListOptions, SandboxPhase, SandboxRef, SandboxSpec, - SandboxTemplateCreateSpec, ServiceStatus, WorkspaceRef, + ExecOptions, ExecResult, Health, ListOptions, SandboxPhase, SandboxRef, SandboxResources, + SandboxServiceLevel, SandboxSpec, SandboxStartup, SandboxTemplateCreateSpec, + SandboxTemplateListOptions, SandboxWorkloadConfig, SandboxWorkloadTemplate, + SandboxWorkloadTemplateSpec, ServiceStatus, WorkspaceRef, }; diff --git a/crates/openshell-sdk/src/raw.rs b/crates/openshell-sdk/src/raw.rs index 903913e3d6..35d91f3325 100644 --- a/crates/openshell-sdk/src/raw.rs +++ b/crates/openshell-sdk/src/raw.rs @@ -26,9 +26,11 @@ pub use openshell_core::proto::{ DeleteSandboxRequest, DeleteSandboxTemplateRequest, DeleteWorkspaceRequest, ExecSandboxRequest, GetSandboxRequest, GetSandboxTemplateRequest, GetWorkspaceRequest, HealthRequest, ListProvidersRequest, ListSandboxTemplatesRequest, ListSandboxesRequest, ListWorkspacesRequest, - Sandbox, SandboxPhase as ProtoSandboxPhase, SandboxSpec as ProtoSandboxSpec, SandboxTemplate, - SandboxTemplateResponse, SandboxWorkloadTemplate, SandboxWorkloadTemplateSpec, - ServiceStatus as ProtoServiceStatus, StartSandboxRequest, StopSandboxRequest, Workspace, + Sandbox, SandboxPhase as ProtoSandboxPhase, SandboxResources, SandboxServiceLevel, + SandboxSpec as ProtoSandboxSpec, SandboxStartup, SandboxTemplate, SandboxTemplateResponse, + SandboxWorkloadConfig, SandboxWorkloadTemplate, SandboxWorkloadTemplateProvenance, + SandboxWorkloadTemplateSpec, ServiceStatus as ProtoServiceStatus, StartSandboxRequest, + StopSandboxRequest, 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 297f031987..ec0ed6dec8 100644 --- a/crates/openshell-sdk/src/types.rs +++ b/crates/openshell-sdk/src/types.rs @@ -122,6 +122,41 @@ pub struct SandboxTemplateCreateSpec { pub labels: HashMap, /// Provider names to attach. pub providers: Vec, + /// Create-time sandbox policy. The named workload template supplies runtime + /// workload fields; policy remains part of the sandbox's governance spec. + pub policy: Option, +} + +/// Reusable sandbox workload template resource. +/// +/// This is a raw proto alias because template specs intentionally expose the +/// full portable workload shape plus driver-owned config. +pub type SandboxWorkloadTemplate = proto::SandboxWorkloadTemplate; + +/// Desired reusable workload shape for a [`SandboxWorkloadTemplate`]. +pub type SandboxWorkloadTemplateSpec = proto::SandboxWorkloadTemplateSpec; + +/// Portable sandbox workload configuration for template-backed sandboxes. +pub type SandboxWorkloadConfig = proto::SandboxWorkloadConfig; + +/// Portable resource requirements for template-backed sandboxes. +pub type SandboxResources = proto::SandboxResources; + +/// Desired service level for sandboxes created from a template. +pub type SandboxServiceLevel = proto::SandboxServiceLevel; + +/// Startup service-level settings for template-backed sandboxes. +pub type SandboxStartup = proto::SandboxStartup; + +/// Options for listing reusable sandbox templates. +#[derive(Clone, Debug, Default)] +pub struct SandboxTemplateListOptions { + /// Maximum templates to return. `0` defers to the server default. + pub limit: u32, + /// Offset into the result list. + pub offset: u32, + /// List templates across all workspaces. + pub all_workspaces: bool, } /// Reference to a sandbox owned by the gateway. diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index cb923648fb..c63417d721 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -12,7 +12,8 @@ use openshell_core::proto; use openshell_core::proto::open_shell_server::{OpenShell, OpenShellServer}; use openshell_sdk::{ AuthConfig, ClientConfig, ExecOptions, ListOptions, OpenShellClient, Refresh, RefreshError, - RefreshedToken, SandboxPhase, SandboxSpec, ServiceStatus as SdkServiceStatus, + RefreshedToken, SandboxPhase, SandboxSpec, SandboxTemplateCreateSpec, + SandboxTemplateListOptions, ServiceStatus as SdkServiceStatus, }; use std::collections::HashMap; use std::sync::Arc; @@ -29,6 +30,10 @@ struct MockState { last_get_name: Mutex>, last_get_workspace: Mutex>, last_create: Mutex>, + last_template_create: Mutex>, + last_template_get: Mutex>, + last_template_list: Mutex>, + last_template_delete: Mutex>, last_delete_name: Mutex>, last_delete_workspace: Mutex>, last_stop: Mutex>, @@ -99,6 +104,34 @@ fn workspace_proto(name: &str, phase: proto::datamodel::v1::WorkspacePhase) -> p } } +fn workload_template_proto(name: &str, workspace: &str) -> proto::SandboxWorkloadTemplate { + proto::SandboxWorkloadTemplate { + metadata: Some(proto::datamodel::v1::ObjectMeta { + id: format!("template-{workspace}-{name}"), + name: name.to_string(), + created_at_ms: 1_000_000, + labels: HashMap::new(), + annotations: HashMap::new(), + resource_version: 1, + deletion_timestamp_ms: 0, + workspace: workspace.to_string(), + }), + spec: Some(proto::SandboxWorkloadTemplateSpec { + workload: Some(proto::SandboxWorkloadConfig { + image: format!("ghcr.io/test/{name}:latest"), + environment: HashMap::new(), + resources: Some(proto::SandboxResources { + cpu: "1".to_string(), + memory: "512Mi".to_string(), + gpu_count: None, + }), + }), + driver_config: None, + desired_service_level: None, + }), + } +} + #[tonic::async_trait] impl OpenShell for TestOpenShell { async fn get_current_user( @@ -166,30 +199,58 @@ impl OpenShell for TestOpenShell { async fn create_sandbox_template( &self, - _: tonic::Request, + request: tonic::Request, ) -> Result, Status> { - Err(Status::unimplemented("unused")) + let request = request.into_inner(); + let template = request + .template + .clone() + .ok_or_else(|| Status::invalid_argument("missing template"))?; + *self.state.last_template_create.lock().await = Some(request); + Ok(Response::new(proto::SandboxTemplateResponse { + template: Some(template), + })) } async fn get_sandbox_template( &self, - _: tonic::Request, + request: tonic::Request, ) -> Result, Status> { - Err(Status::unimplemented("unused")) + let request = request.into_inner(); + let workspace = if request.workspace.is_empty() { + "default" + } else { + &request.workspace + }; + let template = workload_template_proto(&request.name, workspace); + *self.state.last_template_get.lock().await = Some(request); + Ok(Response::new(proto::SandboxTemplateResponse { + template: Some(template), + })) } async fn list_sandbox_templates( &self, - _: tonic::Request, + request: tonic::Request, ) -> Result, Status> { - Err(Status::unimplemented("unused")) + let request = request.into_inner(); + *self.state.last_template_list.lock().await = Some(request); + Ok(Response::new(proto::ListSandboxTemplatesResponse { + templates: vec![ + workload_template_proto("python", "default"), + workload_template_proto("cuda", "gpu"), + ], + })) } async fn delete_sandbox_template( &self, - _: tonic::Request, + request: tonic::Request, ) -> Result, Status> { - Err(Status::unimplemented("unused")) + *self.state.last_template_delete.lock().await = Some(request.into_inner()); + Ok(Response::new(proto::DeleteSandboxTemplateResponse { + deleted: true, + })) } async fn stop_sandbox( @@ -825,6 +886,87 @@ async fn create_sandbox_passes_spec_through() { ); } +#[tokio::test] +async fn create_sandbox_from_template_passes_template_name() { + let state = Arc::new(MockState::default()); + let endpoint = start_mock(state.clone()).await; + let client = connect(&endpoint).await; + + let sandbox = client + .create_sandbox_from_template(SandboxTemplateCreateSpec { + name: Some("from-template".to_string()), + template_name: "python".to_string(), + providers: vec!["openai".to_string()], + policy: Some(proto::SandboxPolicy { + version: 1, + ..Default::default() + }), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(sandbox.name, "from-template"); + + let observed = state.last_create.lock().await.clone().unwrap(); + assert_eq!(observed.name, "from-template"); + assert_eq!(observed.workload_template_name, "python"); + let observed_spec = observed.spec.unwrap(); + assert_eq!(observed_spec.providers, vec!["openai".to_string()]); + assert_eq!(observed_spec.policy.unwrap().version, 1); +} + +#[tokio::test] +async fn sandbox_template_crud_uses_default_workspace() { + let state = Arc::new(MockState::default()); + let endpoint = start_mock(state.clone()).await; + let client = connect(&endpoint).await; + + let created = client + .create_sandbox_template(workload_template_proto("python", "")) + .await + .unwrap(); + assert_eq!(created.metadata.as_ref().unwrap().name, "python"); + + let observed_create = state.last_template_create.lock().await.clone().unwrap(); + assert!(observed_create.workspace.is_empty()); + assert_eq!( + observed_create + .template + .as_ref() + .and_then(|template| template.metadata.as_ref()) + .unwrap() + .name, + "python" + ); + + let fetched = client.get_sandbox_template("python").await.unwrap(); + assert_eq!(fetched.metadata.as_ref().unwrap().name, "python"); + let observed_get = state.last_template_get.lock().await.clone().unwrap(); + assert_eq!(observed_get.name, "python"); + assert!(observed_get.workspace.is_empty()); + + let listed = client + .list_sandbox_templates(SandboxTemplateListOptions { + limit: 10, + offset: 2, + all_workspaces: true, + }) + .await + .unwrap(); + assert_eq!(listed.len(), 2); + let observed_list = state.last_template_list.lock().await.clone().unwrap(); + assert_eq!(observed_list.limit, 10); + assert_eq!(observed_list.offset, 2); + assert!(observed_list.workspace.is_empty()); + assert!(observed_list.all_workspaces); + + let deleted = client.delete_sandbox_template("python").await.unwrap(); + assert!(deleted); + let observed_delete = state.last_template_delete.lock().await.clone().unwrap(); + assert_eq!(observed_delete.name, "python"); + assert!(observed_delete.workspace.is_empty()); +} + #[tokio::test] async fn get_sandbox_sends_name_and_maps_phase() { let state = Arc::new(MockState { @@ -1110,6 +1252,33 @@ async fn workspace_scoped_create_passes_workspace() { assert_eq!(observed.workspace, "staging"); } +#[tokio::test] +async fn workspace_scoped_create_from_template_passes_workspace() { + let state = Arc::new(MockState::default()); + let endpoint = start_mock(state.clone()).await; + let client = connect(&endpoint).await; + + let sandbox = client + .workspace("staging") + .create_sandbox_from_template(SandboxTemplateCreateSpec { + name: Some("from-template".to_string()), + template_name: "python".to_string(), + policy: Some(proto::SandboxPolicy { + version: 2, + ..Default::default() + }), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(sandbox.name, "from-template"); + + let observed = state.last_create.lock().await.clone().unwrap(); + assert_eq!(observed.workspace, "staging"); + assert_eq!(observed.workload_template_name, "python"); + assert_eq!(observed.spec.unwrap().policy.unwrap().version, 2); +} + #[tokio::test] async fn workspace_scoped_get_passes_workspace() { let state = Arc::new(MockState { @@ -1142,6 +1311,50 @@ async fn workspace_scoped_list_passes_workspace() { assert!(!observed.all_workspaces); } +#[tokio::test] +async fn workspace_scoped_sandbox_template_crud_passes_workspace() { + let state = Arc::new(MockState::default()); + let endpoint = start_mock(state.clone()).await; + let client = connect(&endpoint).await; + let ws = client.workspace("staging"); + + ws.create_sandbox_template(workload_template_proto("python", "staging")) + .await + .unwrap(); + let observed_create = state.last_template_create.lock().await.clone().unwrap(); + assert_eq!(observed_create.workspace, "staging"); + + ws.get_sandbox_template("python").await.unwrap(); + let observed_get = state.last_template_get.lock().await.clone().unwrap(); + assert_eq!(observed_get.name, "python"); + assert_eq!(observed_get.workspace, "staging"); + + let listed = ws + .list_sandbox_templates(SandboxTemplateListOptions::default()) + .await + .unwrap(); + assert_eq!(listed.len(), 2); + let observed_list = state.last_template_list.lock().await.clone().unwrap(); + assert_eq!(observed_list.workspace, "staging"); + assert!(!observed_list.all_workspaces); + + ws.list_sandbox_templates(SandboxTemplateListOptions { + all_workspaces: true, + ..Default::default() + }) + .await + .unwrap(); + let observed_all = state.last_template_list.lock().await.clone().unwrap(); + assert!(observed_all.workspace.is_empty()); + assert!(observed_all.all_workspaces); + + let deleted = ws.delete_sandbox_template("python").await.unwrap(); + assert!(deleted); + let observed_delete = state.last_template_delete.lock().await.clone().unwrap(); + assert_eq!(observed_delete.name, "python"); + assert_eq!(observed_delete.workspace, "staging"); +} + #[tokio::test] async fn workspace_scoped_delete_passes_workspace() { let state = Arc::new(MockState::default()); From aac470abf60ce8bb52d121800e9162c1209b33ef Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 19 Aug 2026 21:23:04 +0100 Subject: [PATCH 4/9] feat(python-sdk): add sandbox workload template support Signed-off-by: Gordon Sim --- docs/sandboxes/manage-sandboxes.mdx | 18 ++++ python/openshell/__init__.py | 2 + python/openshell/openshell_test.py | 4 + python/openshell/sandbox.py | 79 +++++++++++++++++ python/openshell/sandbox_test.py | 130 ++++++++++++++++++++++++++++ 5 files changed, 233 insertions(+) diff --git a/docs/sandboxes/manage-sandboxes.mdx b/docs/sandboxes/manage-sandboxes.mdx index 6ce68189fc..247159ea29 100644 --- a/docs/sandboxes/manage-sandboxes.mdx +++ b/docs/sandboxes/manage-sandboxes.mdx @@ -292,6 +292,24 @@ with SandboxClient.from_active_cluster() as client: assert sandbox.id in {s.id for s in matches} ``` +Create reusable sandbox templates through the Python SDK when several runs +should share the same workload shape: + +```python +from openshell import SandboxClient, SandboxTemplateClient +from openshell._proto import openshell_pb2 + +with SandboxClient.from_active_cluster() as client: + templates = SandboxTemplateClient.from_sandbox_client(client) + + template = openshell_pb2.SandboxWorkloadTemplate() + template.metadata.name = "python" + template.spec.workload.image = "ghcr.io/nvidia/openshell-community/sandboxes/python:latest" + templates.create(workspace="default", template=template) + + sandbox = client.create_from_template(workspace="default", template_name="python") +``` + ## Expose Long Running Services Service forwarding makes a long-running process inside a sandbox reachable through a gateway-managed URL. Use it for development servers, notebooks, dashboards, or other services that keep listening after the sandbox starts. Run the service on loopback inside the sandbox, expose its port, then open the URL printed by OpenShell. diff --git a/python/openshell/__init__.py b/python/openshell/__init__.py index 0aa343ed60..40898560f5 100644 --- a/python/openshell/__init__.py +++ b/python/openshell/__init__.py @@ -16,6 +16,7 @@ SandboxRef, SandboxSession, SandboxStatusRef, + SandboxTemplateClient, TlsConfig, WorkspaceClient, WorkspaceRef, @@ -39,6 +40,7 @@ "SandboxRef", "SandboxSession", "SandboxStatusRef", + "SandboxTemplateClient", "TlsConfig", "WorkspaceClient", "WorkspaceRef", diff --git a/python/openshell/openshell_test.py b/python/openshell/openshell_test.py index 66daac6ee1..101b7b6833 100644 --- a/python/openshell/openshell_test.py +++ b/python/openshell/openshell_test.py @@ -9,3 +9,7 @@ def test_version() -> None: """Test that version is defined.""" assert openshell.__version__ + + +def test_sandbox_template_client_exported() -> None: + assert openshell.SandboxTemplateClient diff --git a/python/openshell/sandbox.py b/python/openshell/sandbox.py index 6af9572be2..4f081426b5 100644 --- a/python/openshell/sandbox.py +++ b/python/openshell/sandbox.py @@ -791,6 +791,85 @@ def exec_python( ) +class SandboxTemplateClient: + """gRPC client for reusable sandbox template lifecycle operations.""" + + def __init__(self, channel: grpc.Channel, *, timeout: float = 30.0) -> None: + self._stub = openshell_pb2_grpc.OpenShellStub(channel) + self._timeout = timeout + + @classmethod + def from_sandbox_client(cls, client: SandboxClient) -> SandboxTemplateClient: + return cls(client._channel, timeout=client._timeout) + + def create( + self, + *, + workspace: str, + template: openshell_pb2.SandboxWorkloadTemplate, + ) -> openshell_pb2.SandboxWorkloadTemplate: + response = self._stub.CreateSandboxTemplate( + openshell_pb2.CreateSandboxTemplateRequest( + workspace=workspace, + template=template, + ), + timeout=self._timeout, + ) + return response.template + + def get( + self, + name: str, + *, + workspace: str, + ) -> openshell_pb2.SandboxWorkloadTemplate: + response = self._stub.GetSandboxTemplate( + openshell_pb2.GetSandboxTemplateRequest(name=name, workspace=workspace), + timeout=self._timeout, + ) + return response.template + + def list( + self, + *, + workspace: str, + limit: int = 100, + offset: int = 0, + ) -> builtins.list[openshell_pb2.SandboxWorkloadTemplate]: + response = self._stub.ListSandboxTemplates( + openshell_pb2.ListSandboxTemplatesRequest( + workspace=workspace, + limit=limit, + offset=offset, + ), + timeout=self._timeout, + ) + return list(response.templates) + + def list_for_all_workspaces( + self, + *, + limit: int = 100, + offset: int = 0, + ) -> builtins.list[openshell_pb2.SandboxWorkloadTemplate]: + response = self._stub.ListSandboxTemplates( + openshell_pb2.ListSandboxTemplatesRequest( + all_workspaces=True, + limit=limit, + offset=offset, + ), + timeout=self._timeout, + ) + return list(response.templates) + + def delete(self, name: str, *, workspace: str) -> bool: + response = self._stub.DeleteSandboxTemplate( + openshell_pb2.DeleteSandboxTemplateRequest(name=name, workspace=workspace), + timeout=self._timeout, + ) + return bool(response.deleted) + + @dataclass(frozen=True) class InferenceRouteConfig: provider_name: str diff --git a/python/openshell/sandbox_test.py b/python/openshell/sandbox_test.py index 95d8e7ed66..f20ab4265a 100644 --- a/python/openshell/sandbox_test.py +++ b/python/openshell/sandbox_test.py @@ -27,6 +27,7 @@ SandboxError, SandboxRef, SandboxStatusRef, + SandboxTemplateClient, TlsConfig, _atomic_replace, _BearerAuthInterceptor, @@ -90,6 +91,13 @@ def _client_with_fake_stub(stub: object) -> SandboxClient: return client +def _template_client_with_fake_stub(stub: object) -> SandboxTemplateClient: + client = cast("SandboxTemplateClient", object.__new__(SandboxTemplateClient)) + client._timeout = 30.0 + client._stub = cast("Any", stub) + return client + + def test_exec_sends_stdin_payload() -> None: stub = _FakeStub() client = _client_with_fake_stub(stub) @@ -1537,6 +1545,20 @@ def _make_sandbox_proto( return sandbox +def _make_workload_template_proto( + name: str, + *, + workspace: str = "default", +) -> openshell_pb2.SandboxWorkloadTemplate: + template = openshell_pb2.SandboxWorkloadTemplate() + template.metadata.name = name + template.metadata.workspace = workspace + template.spec.workload.image = f"ghcr.io/test/{name}:latest" + template.spec.workload.resources.cpu = "1" + template.spec.workload.resources.memory = "512Mi" + return template + + class _FakeSandboxStub: def __init__(self, listed: list[openshell_pb2.Sandbox] | None = None) -> None: self.create_request: openshell_pb2.CreateSandboxRequest | None = None @@ -1545,7 +1567,18 @@ def __init__(self, listed: list[openshell_pb2.Sandbox] | None = None) -> None: 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.create_template_request: ( + openshell_pb2.CreateSandboxTemplateRequest | None + ) = None + self.get_template_request: openshell_pb2.GetSandboxTemplateRequest | None = None + self.list_template_request: openshell_pb2.ListSandboxTemplatesRequest | None = ( + None + ) + self.delete_template_request: ( + openshell_pb2.DeleteSandboxTemplateRequest | None + ) = None self._listed = listed or [] + self._templates: list[openshell_pb2.SandboxWorkloadTemplate] = [] def GetSandbox( self, @@ -1626,6 +1659,48 @@ def ListSandboxes( _ = timeout return SimpleNamespace(sandboxes=list(self._listed)) + def CreateSandboxTemplate( + self, + request: openshell_pb2.CreateSandboxTemplateRequest, + timeout: float | None = None, + ) -> Any: + self.create_template_request = request + _ = timeout + self._templates.append(request.template) + return SimpleNamespace(template=request.template) + + def GetSandboxTemplate( + self, + request: openshell_pb2.GetSandboxTemplateRequest, + timeout: float | None = None, + ) -> Any: + self.get_template_request = request + _ = timeout + return SimpleNamespace( + template=_make_workload_template_proto( + request.name, + workspace=request.workspace or "default", + ) + ) + + def ListSandboxTemplates( + self, + request: openshell_pb2.ListSandboxTemplatesRequest, + timeout: float | None = None, + ) -> Any: + self.list_template_request = request + _ = timeout + return SimpleNamespace(templates=list(self._templates)) + + def DeleteSandboxTemplate( + self, + request: openshell_pb2.DeleteSandboxTemplateRequest, + timeout: float | None = None, + ) -> Any: + self.delete_template_request = request + _ = timeout + return SimpleNamespace(deleted=True) + class _RecordingHighLevelClient: """A stand-in for SandboxClient used to observe high-level forwarding.""" @@ -1725,6 +1800,61 @@ def test_create_from_template_rejects_empty_template_name() -> None: assert stub.create_request is None +def test_sandbox_template_client_crud_forwards_requests() -> None: + stub = _FakeSandboxStub() + client = _template_client_with_fake_stub(stub) + template = _make_workload_template_proto("gpu-kata") + template.spec.driver_config.update({"kubernetes": {"runtime_class_name": "kata"}}) + + created = client.create(workspace="default", template=template) + + assert created.metadata.name == "gpu-kata" + assert stub.create_template_request is not None + assert stub.create_template_request.workspace == "default" + assert ( + stub.create_template_request.template.spec.workload.image + == "ghcr.io/test/gpu-kata:latest" + ) + assert ( + stub.create_template_request.template.spec.driver_config["kubernetes"][ + "runtime_class_name" + ] + == "kata" + ) + + got = client.get("gpu-kata", workspace="default") + assert got.metadata.name == "gpu-kata" + assert stub.get_template_request is not None + assert stub.get_template_request.name == "gpu-kata" + assert stub.get_template_request.workspace == "default" + + listed = client.list(workspace="default", limit=50, offset=10) + assert len(listed) == 1 + assert stub.list_template_request is not None + assert stub.list_template_request.workspace == "default" + assert stub.list_template_request.limit == 50 + assert stub.list_template_request.offset == 10 + assert not stub.list_template_request.all_workspaces + + assert client.delete("gpu-kata", workspace="default") is True + assert stub.delete_template_request is not None + assert stub.delete_template_request.name == "gpu-kata" + assert stub.delete_template_request.workspace == "default" + + +def test_sandbox_template_list_for_all_workspaces_clears_workspace() -> None: + stub = _FakeSandboxStub() + client = _template_client_with_fake_stub(stub) + + client.list_for_all_workspaces(limit=100, offset=5) + + assert stub.list_template_request is not None + assert stub.list_template_request.all_workspaces + assert stub.list_template_request.workspace == "" + assert stub.list_template_request.limit == 100 + assert stub.list_template_request.offset == 5 + + def test_stop_and_start_forward_workspace_and_return_phase() -> None: stub = _FakeSandboxStub() client = _client_with_fake_stub(stub) From 257b4d08d1d786bcf0b148c7c02cdfa72209e71b Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 19 Aug 2026 21:56:03 +0100 Subject: [PATCH 5/9] feat(typescript-sdk): add sandbox workload template support Signed-off-by: Gordon Sim --- sdk/typescript/README.md | 42 +++++++++ sdk/typescript/src/client.test.ts | 137 ++++++++++++++++++++++++++++++ sdk/typescript/src/client.ts | 114 ++++++++++++++++++++++++- sdk/typescript/src/index.ts | 10 ++- 4 files changed, 298 insertions(+), 5 deletions(-) diff --git a/sdk/typescript/README.md b/sdk/typescript/README.md index e12353bdeb..c1a218c623 100644 --- a/sdk/typescript/README.md +++ b/sdk/typescript/README.md @@ -133,11 +133,53 @@ await client.sandbox.setSetting(name, 'feature.enabled', { value: { case: 'boolV Sandbox-scoped `setPolicy` may only change `networkPolicies`; static fields (`filesystem`, `landlock`, `process`) must match the create-time policy. Sandbox-scoped setting deletes are rejected by the gateway, so only upsert (`setSetting`) is exposed here. +## Sandbox templates + +Sandbox workload templates are reusable, workspace-scoped runtime shapes. They +own image, environment, resource, and driver-specific settings; sandbox creation +from a template can still attach labels, providers, and create-time policy. + +```ts +import { OpenShellClient, type SandboxWorkloadTemplate } from '@nvidia/openshell-sdk' + +const client = await OpenShellClient.connect({ gateway, oidcToken }) + +const template: SandboxWorkloadTemplate = await client.sandboxTemplates.create( + { + metadata: { name: 'python', labels: { team: 'runtime' } }, + spec: { + workload: { + image: 'ghcr.io/nvidia/openshell-community/sandboxes/python:latest', + environment: { FEATURE_FLAG: 'on' }, + resources: { cpu: '1', memory: '512Mi' }, + }, + driverConfig: { kubernetes: { runtime_class_name: 'kata-containers' } }, + }, + }, + { workspace: 'default' }, +) + +const sandbox = await client.sandbox.createFromTemplate({ + templateName: template.metadata!.name, + providers: ['github'], + policy: { version: 1, networkPolicies: {} }, +}) + +await client.sandboxTemplates.get('python', { workspace: 'default' }) +await client.sandboxTemplates.list({ workspace: 'default', limit: 100 }) +await client.sandboxTemplates.delete('python', { workspace: 'default' }) +``` + +Use `allWorkspaces: true` on `list()` for a platform-admin view. The SDK clears +the workspace field in that request because the gateway treats `workspace` and +`allWorkspaces` as mutually exclusive. + ## Surface and roadmap The SDK's goal is agent parity: anything the OpenShell gateway can do should be reachable from typed code, not only the CLI. The API is organized as scoped sub-clients over one shared connection, mirroring the CLI's verbs. - `client.sandbox` (`SandboxClient`) is available today: sandbox lifecycle, exec, forward, SSH, sandbox-scoped providers, config, and policy. +- `client.sandboxTemplates` (`SandboxTemplateClient`) is available today: reusable sandbox workload template CRUD. - `client.gateway` (`GatewayClient`) is planned: gateway-scoped config and settings, health, and cluster status. - `client.providers` (`ProviderClient`) is planned: gateway-scoped provider CRUD and profiles. diff --git a/sdk/typescript/src/client.test.ts b/sdk/typescript/src/client.test.ts index e420aef899..d5c7ff3c77 100644 --- a/sdk/typescript/src/client.test.ts +++ b/sdk/typescript/src/client.test.ts @@ -17,6 +17,7 @@ import { POLICY_SOURCE_NAMES, Pushable, SandboxClient, + SandboxTemplateClient, SCOPE_NAMES, STATUS_NAMES, } from './client.js'; @@ -30,6 +31,13 @@ function client(impl: Partial>): SandboxClient { return new SandboxClient(transport); } +function templateClient(impl: Partial>): SandboxTemplateClient { + const transport: Transport = createRouterTransport((router) => { + router.service(OpenShell, impl); + }); + return new SandboxTemplateClient(transport); +} + function readySandbox( name: string, id: string, @@ -290,6 +298,135 @@ describe('create', () => { }); }); +describe('sandbox templates', () => { + it('create sends the template resource and workspace', async () => { + let observed: { + workspace?: string; + template?: { + metadata?: { name?: string; labels?: Record }; + spec?: { + workload?: { + image?: string; + environment?: Record; + resources?: { cpu?: string; memory?: string; gpuCount?: number }; + }; + driverConfig?: Record; + }; + }; + } = {}; + const templates = templateClient({ + createSandboxTemplate: (req) => { + observed = req; + return { + template: { + metadata: { + id: 'template-python', + name: req.template?.metadata?.name ?? '', + labels: req.template?.metadata?.labels ?? {}, + workspace: req.workspace, + resourceVersion: 1n, + }, + spec: req.template?.spec, + }, + }; + }, + }); + + const created = await templates.create( + { + metadata: { name: 'python', labels: { team: 'runtime' } }, + spec: { + workload: { + image: 'ghcr.io/nvidia/openshell-community/sandboxes/python:latest', + environment: { FEATURE_FLAG: 'on' }, + resources: { cpu: '1', memory: '512Mi', gpuCount: 1 }, + }, + driverConfig: { kubernetes: { runtime_class_name: 'kata-containers' } }, + }, + }, + { workspace: 'default' }, + ); + + expect(observed.workspace).toBe('default'); + expect(observed.template?.metadata?.name).toBe('python'); + expect(observed.template?.metadata?.labels).toEqual({ team: 'runtime' }); + expect(observed.template?.spec?.workload?.environment).toEqual({ FEATURE_FLAG: 'on' }); + expect(observed.template?.spec?.workload?.resources?.gpuCount).toBe(1); + expect(created.metadata?.workspace).toBe('default'); + expect(created.metadata?.resourceVersion).toBe(1n); + }); + + it('get list and delete forward workspace and pagination', async () => { + const observed: { + get?: { name?: string; workspace?: string }; + list?: { limit?: number; offset?: number; workspace?: string; allWorkspaces?: boolean }; + delete?: { name?: string; workspace?: string }; + } = {}; + const templates = templateClient({ + getSandboxTemplate: (req) => { + observed.get = req; + return { + template: { + metadata: { id: 'template-gpu-kata', name: req.name, workspace: req.workspace }, + spec: { workload: { image: 'img:v1' } }, + }, + }; + }, + listSandboxTemplates: (req) => { + observed.list = req; + return { + templates: [ + { + metadata: { id: 'template-python', name: 'python', workspace: req.workspace || 'default' }, + spec: { workload: { image: 'img:v1' } }, + }, + ], + }; + }, + deleteSandboxTemplate: (req) => { + observed.delete = req; + return { deleted: true }; + }, + }); + + const got = await templates.get('gpu-kata', { workspace: 'staging' }); + const listed = await templates.list({ workspace: 'staging', limit: 10, offset: 2 }); + const deleted = await templates.delete('gpu-kata', { workspace: 'staging' }); + + expect(got.metadata?.name).toBe('gpu-kata'); + expect(listed).toHaveLength(1); + expect(deleted).toBe(true); + expect(observed.get).toMatchObject({ name: 'gpu-kata', workspace: 'staging' }); + expect(observed.list).toMatchObject({ limit: 10, offset: 2, workspace: 'staging', allWorkspaces: false }); + expect(observed.delete).toMatchObject({ name: 'gpu-kata', workspace: 'staging' }); + }); + + it('list clears workspace when allWorkspaces is set', async () => { + let observed: { workspace?: string; allWorkspaces?: boolean } = {}; + const templates = templateClient({ + listSandboxTemplates: (req) => { + observed = req; + return { templates: [] }; + }, + }); + + await templates.list({ workspace: 'staging', allWorkspaces: true }); + + expect(observed.workspace).toBe(''); + expect(observed.allWorkspaces).toBe(true); + }); + + it('rejects empty names and missing template responses locally', async () => { + const templates = templateClient({ + getSandboxTemplate: () => ({}), + }); + + await expect(templates.get(' ')).rejects.toMatchObject({ code: 'invalid_config' }); + await expect(templates.delete(' ')).rejects.toMatchObject({ code: 'invalid_config' }); + await expect(templates.get('missing-response')).rejects.toMatchObject({ code: 'invalid_config' }); + }); +}); + describe('waits', () => { it('waitReady rejects rather than hanging when get() never resolves', async () => { const sandbox = client({ diff --git a/sdk/typescript/src/client.ts b/sdk/typescript/src/client.ts index f8e5915121..48bb2b6257 100644 --- a/sdk/typescript/src/client.ts +++ b/sdk/typescript/src/client.ts @@ -17,12 +17,13 @@ import type { MessageInitShape } from '@bufbuild/protobuf'; import { type CallOptions, type Client, createClient, type Transport } from '@connectrpc/connect'; import { errorCode, fromConnect, SdkError } from './errors.js'; import type { Provider } from './gen/datamodel_pb.js'; -import type { Sandbox, UpdateConfigResponse } from './gen/openshell_pb.js'; +import type { Sandbox, SandboxWorkloadTemplate, UpdateConfigResponse } from './gen/openshell_pb.js'; import { type ExecSandboxInputSchema, OpenShell, SandboxPhase, type SandboxSpecSchema, + type SandboxWorkloadTemplateSchema, ServiceStatus, type TcpForwardFrameSchema, } from './gen/openshell_pb.js'; @@ -31,9 +32,16 @@ import { PolicySource, type SandboxPolicySchema, SettingScope, type SettingValue import { validateSshResponse } from './ssh-validate.js'; import { buildTransport, type ConnectOptions } from './transport.js'; -// The policy and setting value shapes are the generated protobuf messages; -// re-export them rather than re-curating a parallel surface. Callers round-trip -// `getConfig().policy` back into `setPolicy`, and build `SettingValue`s inline. +// Generated protobuf message shapes that callers need to populate or round-trip +// directly. Re-export these rather than re-curating parallel surfaces. +export type { + SandboxResources, + SandboxServiceLevel, + SandboxStartup, + SandboxWorkloadConfig, + SandboxWorkloadTemplate, + SandboxWorkloadTemplateSpec, +} from './gen/openshell_pb.js'; export type { SandboxPolicy, SettingValue } from './gen/sandbox_pb.js'; export type { ConnectOptions }; export { errorCode }; @@ -125,6 +133,18 @@ export interface ListOptions { labelSelector?: string; } +export interface SandboxTemplateWorkspaceOptions { + /** Workspace scope. Omit or use an empty string for the gateway default workspace. */ + workspace?: string; +} + +export interface SandboxTemplateListOptions extends SandboxTemplateWorkspaceOptions { + limit?: number; + offset?: number; + /** List templates across all workspaces. Requires platform admin permission. */ + allWorkspaces?: boolean; +} + export interface ExecOptions { workdir?: string; environment?: Record; @@ -345,6 +365,11 @@ function sandboxRef(sandbox: Sandbox | undefined): SandboxRef { }; } +function sandboxTemplate(template: SandboxWorkloadTemplate | undefined): SandboxWorkloadTemplate { + if (!template) throw new SdkError('invalid_config', 'sandbox template missing from gateway response'); + return template; +} + function providerRef(provider: Provider): ProviderRef { const meta = provider.metadata; return { @@ -527,6 +552,84 @@ export class Pushable implements AsyncIterable { } } +// ---- sandbox template client ---------------------------------------------- + +// Reusable sandbox workload template lifecycle. Templates intentionally return +// generated proto messages because the resource owns portable workload fields +// plus driver-specific config that should not be lossy in the curated layer. +export class SandboxTemplateClient { + private readonly grpc: Client; + + readonly raw: Client; + readonly transport: Transport; + + constructor(transport: Transport, grpc = createClient(OpenShell, transport)) { + this.transport = transport; + this.grpc = grpc; + this.raw = this.grpc; + } + + static async connect(options: ConnectOptions): Promise { + return new SandboxTemplateClient(buildTransport(options)); + } + + async create( + template: MessageInitShape, + options?: SandboxTemplateWorkspaceOptions | null, + ): Promise { + try { + const resp = await this.grpc.createSandboxTemplate({ + template, + workspace: options?.workspace ?? '', + }); + return sandboxTemplate(resp.template); + } catch (e) { + throw e instanceof SdkError ? e : fromConnect(e); + } + } + + async get(name: string, options?: SandboxTemplateWorkspaceOptions | null): Promise { + if (name.trim() === '') throw new SdkError('invalid_config', 'template name is required'); + try { + const resp = await this.grpc.getSandboxTemplate({ + name, + workspace: options?.workspace ?? '', + }); + return sandboxTemplate(resp.template); + } catch (e) { + throw e instanceof SdkError ? e : fromConnect(e); + } + } + + async list(options?: SandboxTemplateListOptions | null): Promise { + try { + const allWorkspaces = options?.allWorkspaces ?? false; + const resp = await this.grpc.listSandboxTemplates({ + limit: options?.limit ?? 0, + offset: options?.offset ?? 0, + workspace: allWorkspaces ? '' : (options?.workspace ?? ''), + allWorkspaces, + }); + return resp.templates; + } catch (e) { + throw fromConnect(e); + } + } + + async delete(name: string, options?: SandboxTemplateWorkspaceOptions | null): Promise { + if (name.trim() === '') throw new SdkError('invalid_config', 'template name is required'); + try { + const resp = await this.grpc.deleteSandboxTemplate({ + name, + workspace: options?.workspace ?? '', + }); + return resp.deleted; + } catch (e) { + throw fromConnect(e); + } + } +} + // ---- sandbox client -------------------------------------------------------- // Sandbox lifecycle + exec. Usable standalone via `SandboxClient.connect()`, @@ -1223,6 +1326,8 @@ export class SandboxClient { export class OpenShellClient { /** Sandbox lifecycle + exec: create/get/list/delete, waitReady/waitDeleted, exec. */ readonly sandbox: SandboxClient; + /** Reusable sandbox workload template lifecycle. */ + readonly sandboxTemplates: SandboxTemplateClient; /** * Advanced escape hatch: a generated client for every gateway RPC, including @@ -1242,6 +1347,7 @@ export class OpenShellClient { this.grpc = createClient(OpenShell, transport); this.raw = this.grpc; this.sandbox = new SandboxClient(transport, this.grpc); + this.sandboxTemplates = new SandboxTemplateClient(transport, this.grpc); } /** diff --git a/sdk/typescript/src/index.ts b/sdk/typescript/src/index.ts index 463619af8d..190af39b97 100644 --- a/sdk/typescript/src/index.ts +++ b/sdk/typescript/src/index.ts @@ -32,7 +32,15 @@ export type { SandboxPhaseName, SandboxPolicy, SandboxRef, + SandboxResources, + SandboxServiceLevel, SandboxSpec, + SandboxStartup, + SandboxTemplateListOptions, + SandboxTemplateWorkspaceOptions, + SandboxWorkloadConfig, + SandboxWorkloadTemplate, + SandboxWorkloadTemplateSpec, SetPolicyOptions, SettingScopeName, SettingValue, @@ -40,6 +48,6 @@ export type { UpdateConfigResult, WaitOptions, } from './client.js'; -export { errorCode, OpenShellClient, SandboxClient } from './client.js'; +export { errorCode, OpenShellClient, SandboxClient, SandboxTemplateClient } from './client.js'; export type { SdkErrorCode } from './errors.js'; export { SdkError } from './errors.js'; From b4a179ed57eeccac1495f62920659ea152287104 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Wed, 19 Aug 2026 22:49:52 +0100 Subject: [PATCH 6/9] docs(agents): document sandbox workload templates Signed-off-by: Gordon Sim --- .agents/skills/openshell-cli/SKILL.md | 43 ++++++++++++- .agents/skills/openshell-cli/cli-reference.md | 64 +++++++++++++++++-- docs/sandboxes/manage-sandboxes.mdx | 4 ++ 3 files changed, 106 insertions(+), 5 deletions(-) diff --git a/.agents/skills/openshell-cli/SKILL.md b/.agents/skills/openshell-cli/SKILL.md index 8aae80fd0a..159da32cea 100644 --- a/.agents/skills/openshell-cli/SKILL.md +++ b/.agents/skills/openshell-cli/SKILL.md @@ -228,6 +228,7 @@ Key flags: - `--gpu [COUNT]`: Request the driver's default GPU selection or a specific GPU count - `--cpu`, `--memory`: Set per-sandbox compute sizing. Docker/Podman apply limits; Kubernetes applies matching requests and limits. - `--driver-config-json`: Pass experimental driver-specific sandbox configuration +- `--template NAME`: Create from a named sandbox workload template. Conflicts with inline workload flags such as `--from`, `--gpu`, `--cpu`, `--memory`, `--env`, and `--driver-config-json`. - `--label KEY=VALUE`: Add labels for later selection (repeatable) - `--env KEY=VALUE`: Set non-secret sandbox environment variables (repeatable); use `--provider` for credentials - `--approval-mode manual|auto`: Control handling of agent-authored policy proposals; `manual` is the default @@ -237,6 +238,44 @@ Key flags: - `--forward [BIND_ADDRESS:]PORT`: Forward a local port and keep the sandbox alive - `--editor vscode|cursor`: Open a remote editor after creation and keep the sandbox alive +Create from a reusable workload template when several sandboxes should share +image, environment, sizing, or driver-specific configuration: + +```bash +openshell sandbox template create gpu-kata \ + --image ghcr.io/nvidia/openshell-community/sandboxes/python:latest \ + --cpu 2 \ + --memory 4Gi \ + --gpu 1 \ + --driver-config-json '{"kubernetes":{"pod":{"node_selector":{"pool":"gpu"}}}}' + +openshell sandbox create --name my-sandbox --template gpu-kata --provider my-github -- claude +``` + +Direct `sandbox create --driver-config-json` remains valid for one-off +creates. Put driver config on a template only when it should be reused. + +### Manage sandbox workload templates + +```bash +openshell sandbox template create gpu-kata \ + --image ghcr.io/nvidia/openshell-community/sandboxes/python:latest \ + --cpu 2 \ + --memory 4Gi \ + --gpu 1 \ + --label team=runtime \ + --env FEATURE_FLAG=on +openshell sandbox template list +openshell sandbox template list --all-workspaces --output json +openshell sandbox template get gpu-kata +openshell sandbox template delete gpu-kata +``` + +Template `--image` accepts an OCI image reference. If omitted, the gateway +applies its default sandbox image when creating a sandbox from the template. +Create-time policy, providers, labels, uploads, forwarding, editor launch, and +the initial command stay on `sandbox create`. + ### List and inspect sandboxes ```bash @@ -714,7 +753,7 @@ The CLI help is always authoritative. If the help output contradicts this skill, ```bash $ openshell sandbox --help -# Shows: create, get, list, stop, start, delete, exec, connect, upload, download, ssh-config, provider +# Shows: create, get, list, stop, start, delete, exec, connect, upload, download, ssh-config, provider, template $ openshell sandbox upload --help # Shows: positional arguments (name, path, dest), usage examples @@ -735,6 +774,8 @@ $ openshell sandbox upload --help | Create sandbox with tool | `openshell sandbox create -- claude` | | Create sandbox with GPUs | `openshell sandbox create --gpu 1` | | Create with custom policy | `openshell sandbox create --policy ./p.yaml` | +| Create from template | `openshell sandbox create --template gpu-kata` | +| Create workload template | `openshell sandbox template create gpu-kata --image python:3.12` | | Connect to sandbox | `openshell sandbox connect ` | | Stop sandbox compute | `openshell sandbox stop [name]` | | Start sandbox compute | `openshell sandbox start [name]` | diff --git a/.agents/skills/openshell-cli/cli-reference.md b/.agents/skills/openshell-cli/cli-reference.md index 2cd5881ab9..f688aea8e4 100644 --- a/.agents/skills/openshell-cli/cli-reference.md +++ b/.agents/skills/openshell-cli/cli-reference.md @@ -56,10 +56,15 @@ openshell │ ├── upload [dest] │ ├── download [dest] │ ├── ssh-config [name] -│ └── provider -│ ├── list [name] -│ ├── attach -│ └── detach +│ ├── provider +│ │ ├── list [name] +│ │ ├── attach +│ │ └── detach +│ └── template +│ ├── create [opts] +│ ├── get +│ ├── list [opts] +│ └── delete ... ├── forward │ ├── start [name] [-d] │ ├── stop [name] @@ -216,6 +221,7 @@ Create a sandbox through the selected gateway, wait for readiness, then connect, | `--cpu ` | CPU limit (for example: `500m`, `1`, `2.5`) | | `--memory ` | Memory limit (for example: `512Mi`, `4Gi`, `8G`) | | `--driver-config-json ` | Experimental driver-keyed configuration object | +| `--template ` | Create from a named sandbox workload template | | `--provider ` | Provider to attach (repeatable) | | `--policy ` | Custom policy YAML; overrides the built-in default and `OPENSHELL_SANDBOX_POLICY` | | `--forward <[BIND:]PORT>` | Start a local port forward and keep the sandbox alive | @@ -229,6 +235,56 @@ Create a sandbox through the selected gateway, wait for readiness, then connect, | `--no-git-ignore` | Disable `.gitignore` filtering for `--upload` | | `[-- COMMAND...]` | Initial command (defaults to an interactive shell) | +`--template` uses the named template workload, so it conflicts with inline +workload flags: `--from`, `--gpu`, `--cpu`, `--memory`, `--env`, and +`--driver-config-json`. Direct `sandbox create --driver-config-json` remains +valid when `--template` is not set. + +### `openshell sandbox template create NAME [OPTIONS]` + +Create a reusable sandbox workload template. Templates hold image, +environment, resource, startup, and driver-specific configuration for later +`sandbox create --template NAME` calls. + +| Flag | Description | +|------|-------------| +| `--image ` | OCI image reference; when omitted, the gateway default image is applied at sandbox create time | +| `--env ` | Set a non-secret template workload environment variable (repeatable) | +| `--cpu ` | CPU limit for sandboxes created from the template | +| `--memory ` | Memory limit for sandboxes created from the template | +| `--gpu [COUNT]` | Request the driver's default GPU selection or a specific GPU count for sandboxes created from the template | +| `--driver-config-json ` | Experimental driver-keyed configuration object owned by the template | +| `--ready-within ` | Target startup readiness duration, for example `30s`, `5m`, or `1h` | +| `--max-burst ` | Maximum startup burst associated with this template | +| `--label ` | Attach a template label (repeatable) | +| `--annotation ` | Attach a template annotation (repeatable) | +| `--output table|yaml|json` | Output format | + +### `openshell sandbox template get NAME` + +Show a sandbox workload template. + +| Flag | Description | +|------|-------------| +| `--output table|yaml|json` | Output format | + +### `openshell sandbox template list` + +List sandbox workload templates. + +| Flag | Default | Description | +|------|---------|-------------| +| `--limit ` | 100 | Maximum templates | +| `--offset ` | 0 | Pagination offset | +| `--names` | false | Print only template names | +| `--all-workspaces` | false | List templates across all workspaces; requires platform-admin permissions | +| `--output table|yaml|json` | `table` | Output format | + +### `openshell sandbox template delete NAME...` + +Delete one or more sandbox workload templates by name. Existing sandboxes +created from a template are not deleted. + ### `openshell sandbox get [name]` Show sandbox details and the active policy. Metadata identifies sandbox or global policy source and the corresponding revision. The name defaults to the last-used sandbox. diff --git a/docs/sandboxes/manage-sandboxes.mdx b/docs/sandboxes/manage-sandboxes.mdx index 247159ea29..c763376914 100644 --- a/docs/sandboxes/manage-sandboxes.mdx +++ b/docs/sandboxes/manage-sandboxes.mdx @@ -144,6 +144,10 @@ openshell sandbox template create gpu-kata \ --env FEATURE_FLAG=on ``` +Use `--gpu` without a count when the template should request the active +driver's default GPU assignment. Use `--gpu COUNT` when the template needs a +specific number of GPUs. + Add driver-specific settings when the active compute driver needs them: ```shell From 5435491d5d59d1709fbcd29fbee1bb40ee41fcda Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Thu, 20 Aug 2026 09:14:37 +0100 Subject: [PATCH 7/9] fix(cli): support default GPU requests in sandbox templates Signed-off-by: Gordon Sim --- crates/openshell-cli/src/main.rs | 39 +- crates/openshell-cli/src/run.rs | 33 +- .../sandbox_create_lifecycle_integration.rs | 4 +- crates/openshell-sdk/tests/client_mock.rs | 2 +- crates/openshell-server/src/grpc/sandbox.rs | 83 ++- proto/openshell.proto | 6 +- sdk/go/docs/src/api/sandbox-templates.md | 9 +- sdk/go/openshell/v1/fake/sandbox.go | 4 +- sdk/go/openshell/v1/fake/sandbox_template.go | 10 +- .../v1/fake/sandbox_template_test.go | 31 +- .../v1/internal/converter/coverage_test.go | 6 +- .../v1/internal/converter/sandbox.go | 26 +- .../v1/internal/converter/sandbox_test.go | 38 +- sdk/go/openshell/v1/sandbox_template.go | 3 + .../v1/sandbox_template_client_test.go | 10 +- sdk/go/openshell/v1/types/sandbox.go | 13 +- sdk/go/proto/openshellv1/openshell.pb.go | 598 +++++++++--------- sdk/typescript/src/client.test.ts | 6 +- 18 files changed, 545 insertions(+), 376 deletions(-) diff --git a/crates/openshell-cli/src/main.rs b/crates/openshell-cli/src/main.rs index 6c51debc0e..5212e8e883 100644 --- a/crates/openshell-cli/src/main.rs +++ b/crates/openshell-cli/src/main.rs @@ -1724,9 +1724,12 @@ enum SandboxTemplateCommands { #[arg(long)] memory: Option, - /// Number of GPUs requested by this template. - #[arg(long, value_name = "COUNT", value_parser = clap::value_parser!(u32).range(1..))] - gpu: Option, + /// Request GPU resources for sandboxes created from this template. + /// + /// Omit COUNT for the driver's default GPU selection, or pass COUNT + /// to request a specific number of GPUs. + #[arg(long, num_args = 0..=1, value_name = "COUNT", default_missing_value = "", value_parser = parse_gpu_request)] + gpu: Option, /// Experimental driver-keyed JSON object for driver-specific sandbox settings. #[arg(long, value_name = "JSON")] @@ -3407,13 +3410,15 @@ async fn run_async() -> Result<()> { let annotations = run::parse_key_value_pairs(&annotations, "--annotation")?; let environment = run::parse_env_pairs(&envs)?; + let gpu_requirements: Option = + gpu.map(Into::into); run::sandbox_template_create( endpoint, &name, image.as_deref(), cpu.as_deref(), memory.as_deref(), - gpu, + gpu_requirements, driver_config_json.as_deref(), ready_within.as_deref(), max_burst, @@ -5558,7 +5563,7 @@ mod tests { assert_eq!(image.as_deref(), Some("registry.example.com/agent:latest")); assert_eq!(cpu.as_deref(), Some("2")); assert_eq!(memory.as_deref(), Some("4Gi")); - assert_eq!(gpu, Some(1)); + assert_eq!(gpu, Some(GpuCliRequest::Count(1))); assert_eq!(driver_config_json.as_deref(), Some(json)); assert_eq!(ready_within.as_deref(), Some("5m")); assert_eq!(max_burst, Some(3)); @@ -5639,6 +5644,30 @@ mod tests { } } + #[test] + fn sandbox_template_create_gpu_parses_driver_default() { + let cli = Cli::try_parse_from([ + "openshell", + "sandbox", + "template", + "create", + "gpu-kata", + "--gpu", + ]) + .expect("sandbox template create --gpu should parse"); + + match cli.command { + Some(Commands::Sandbox { + command: + Some(SandboxCommands::Template(SandboxTemplateCommands::Create { gpu, .. })), + .. + }) => { + assert_eq!(gpu, Some(GpuCliRequest::DriverDefault)); + } + other => panic!("expected SandboxTemplateCommands::Create, got: {other:?}"), + } + } + #[test] fn sandbox_create_gpu_parses_driver_default() { let cli = Cli::try_parse_from(["openshell", "sandbox", "create", "--gpu"]) diff --git a/crates/openshell-cli/src/run.rs b/crates/openshell-cli/src/run.rs index 1faede71dd..2637196196 100644 --- a/crates/openshell-cli/src/run.rs +++ b/crates/openshell-cli/src/run.rs @@ -2391,7 +2391,7 @@ pub async fn sandbox_template_create( image: Option<&str>, cpu: Option<&str>, memory: Option<&str>, - gpu_count: Option, + gpu_requirements: Option, driver_config_json: Option<&str>, ready_within: Option<&str>, max_burst: Option, @@ -2402,7 +2402,7 @@ pub async fn sandbox_template_create( workspace: &str, tls: &TlsOptions, ) -> Result<()> { - let resources = if cpu.is_some() || memory.is_some() || gpu_count.is_some() { + let resources = if cpu.is_some() || memory.is_some() || gpu_requirements.is_some() { Some(SandboxResources { cpu: cpu .map(validate_cpu_quantity) @@ -2412,7 +2412,7 @@ pub async fn sandbox_template_create( .map(validate_memory_quantity) .transpose()? .unwrap_or_default(), - gpu_count, + gpu: gpu_requirements, }) } else { None @@ -2653,8 +2653,11 @@ fn sandbox_template_to_json(template: &SandboxWorkloadTemplate) -> serde_json::V resources_json .insert("memory".to_string(), serde_json::json!(resources.memory)); } - if let Some(gpu_count) = resources.gpu_count { - resources_json.insert("gpu_count".to_string(), serde_json::json!(gpu_count)); + if let Some(gpu) = &resources.gpu { + let value = gpu + .count + .map_or_else(|| serde_json::json!(true), serde_json::Value::from); + resources_json.insert("gpu".to_string(), value); } if !resources_json.is_empty() { obj.insert( @@ -2754,10 +2757,8 @@ fn print_sandbox_template_detail(template: &SandboxWorkloadTemplate) { ); println!( " {} {}", - "GPU count:".dimmed(), - resources - .gpu_count - .map_or_else(|| "".to_string(), |count| count.to_string()) + "GPU:".dimmed(), + template_resources_gpu_display(resources).unwrap_or_else(|| "".to_string()) ); } } @@ -2844,8 +2845,8 @@ fn print_sandbox_template_table(templates: &[SandboxWorkloadTemplate], show_work .filter(|memory| !memory.is_empty()) .unwrap_or("-"); let gpu = resources - .and_then(|resources| resources.gpu_count) - .map_or_else(|| "-".to_string(), |count| count.to_string()); + .and_then(template_resources_gpu_display) + .unwrap_or_else(|| "-".to_string()); let image = truncate_status_field(&template_image(template), image_width); let startup = template_startup(template); let ready = startup @@ -2908,6 +2909,16 @@ fn template_resources(template: &SandboxWorkloadTemplate) -> Option<&SandboxReso .and_then(|workload| workload.resources.as_ref()) } +fn template_resources_gpu_display(resources: &SandboxResources) -> Option { + if let Some(gpu) = &resources.gpu { + return Some( + gpu.count + .map_or_else(|| "default".to_string(), |count| count.to_string()), + ); + } + None +} + fn template_startup(template: &SandboxWorkloadTemplate) -> Option<&SandboxStartup> { template .spec diff --git a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs index 0bed792b0d..b954e0b15c 100644 --- a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs +++ b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs @@ -1561,7 +1561,7 @@ async fn sandbox_template_create_sends_workload_template_resource() { Some("registry.example.com/agent:latest"), Some("2"), Some("4Gi"), - Some(1), + Some(GpuResourceRequirements { count: Some(1) }), Some(r#"{"kubernetes":{"pod":{"node_selector":{"pool":"gpu"}}}}"#), Some("5m"), Some(3), @@ -1602,7 +1602,7 @@ async fn sandbox_template_create_sends_workload_template_resource() { .expect("resources should be sent"); assert_eq!(resources.cpu, "2"); assert_eq!(resources.memory, "4Gi"); - assert_eq!(resources.gpu_count, Some(1)); + assert_eq!(resources.gpu.as_ref().and_then(|gpu| gpu.count), Some(1)); assert!(spec.driver_config.is_some()); let startup = spec .desired_service_level diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index c63417d721..21ca04b581 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -123,7 +123,7 @@ fn workload_template_proto(name: &str, workspace: &str) -> proto::SandboxWorkloa resources: Some(proto::SandboxResources { cpu: "1".to_string(), memory: "512Mi".to_string(), - gpu_count: None, + ..proto::SandboxResources::default() }), }), driver_config: None, diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index 420b85e6f0..d1448c00d2 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -23,14 +23,14 @@ use openshell_core::proto::{ DeleteSandboxRequest, DeleteSandboxResponse, DeleteSandboxTemplateRequest, DeleteSandboxTemplateResponse, DetachSandboxProviderRequest, DetachSandboxProviderResponse, ExecSandboxEvent, ExecSandboxExit, ExecSandboxInput, ExecSandboxRequest, ExecSandboxStderr, - ExecSandboxStdout, GetSandboxRequest, GetSandboxTemplateRequest, GpuResourceRequirements, - ListSandboxProvidersRequest, ListSandboxProvidersResponse, ListSandboxTemplatesRequest, - ListSandboxTemplatesResponse, ListSandboxesRequest, ListSandboxesResponse, Provider, - ResourceRequirements, RevokeSshSessionRequest, RevokeSshSessionResponse, SandboxResources, - SandboxResponse, SandboxSpec, SandboxStreamEvent, SandboxTemplateResponse, - SandboxWorkloadTemplate, SandboxWorkloadTemplateProvenance, SshRelayTarget, - StartSandboxRequest, StopSandboxRequest, TcpForwardFrame, TcpForwardInit, TcpRelayTarget, - WatchSandboxRequest, relay_open, tcp_forward_init, + ExecSandboxStdout, GetSandboxRequest, GetSandboxTemplateRequest, ListSandboxProvidersRequest, + ListSandboxProvidersResponse, ListSandboxTemplatesRequest, ListSandboxTemplatesResponse, + ListSandboxesRequest, ListSandboxesResponse, Provider, ResourceRequirements, + RevokeSshSessionRequest, RevokeSshSessionResponse, SandboxResources, SandboxResponse, + SandboxSpec, SandboxStreamEvent, SandboxTemplateResponse, SandboxWorkloadTemplate, + SandboxWorkloadTemplateProvenance, SshRelayTarget, StartSandboxRequest, StopSandboxRequest, + TcpForwardFrame, TcpForwardInit, TcpRelayTarget, WatchSandboxRequest, relay_open, + tcp_forward_init, }; use openshell_core::proto::{Sandbox, SandboxPhase, SandboxTemplate, SshSession}; use openshell_core::telemetry::{ @@ -475,20 +475,17 @@ fn sandbox_spec_from_workload_template( driver_config: spec.driver_config.clone(), ..SandboxTemplate::default() }), - resource_requirements: resources.and_then(|resources| { - resources - .gpu_count - .is_some() - .then_some(ResourceRequirements { - gpu: Some(GpuResourceRequirements { - count: resources.gpu_count, - }), - }) - }), + resource_requirements: resources.and_then(template_gpu_requirements), ..SandboxSpec::default() }) } +fn template_gpu_requirements(resources: &SandboxResources) -> Option { + Some(ResourceRequirements { + gpu: Some(resources.gpu?), + }) +} + fn template_resource_struct(resources: &SandboxResources) -> Option { let mut limits = std::collections::BTreeMap::new(); if !resources.cpu.is_empty() { @@ -2771,6 +2768,7 @@ mod tests { use crate::grpc::test_support::{ authed_request, test_server_state, test_server_state_with_driver, }; + use openshell_core::proto::GpuResourceRequirements; use openshell_core::proto::datamodel::v1::ObjectMeta; // ---- shell_escape ---- @@ -3200,7 +3198,7 @@ mod tests { resources: Some(SandboxResources { cpu: "2".to_string(), memory: "4Gi".to_string(), - gpu_count: Some(1), + gpu: Some(GpuResourceRequirements { count: Some(1) }), }), }), driver_config: None, @@ -4260,6 +4258,53 @@ mod tests { assert_eq!(image, state.compute.default_image()); } + #[tokio::test] + async fn create_sandbox_from_workload_template_preserves_default_gpu_request() { + let state = test_server_state().await; + let mut template = test_workload_template("default-gpu"); + template + .spec + .as_mut() + .and_then(|spec| spec.workload.as_mut()) + .and_then(|workload| workload.resources.as_mut()) + .expect("test template resources") + .gpu = Some(GpuResourceRequirements { count: None }); + handle_create_sandbox_template( + &state, + authed_request(CreateSandboxTemplateRequest { + template: Some(template), + workspace: "default".to_string(), + }), + ) + .await + .expect("template create should succeed"); + + let created = handle_create_sandbox( + &state, + authed_request(CreateSandboxRequest { + name: "from-template".to_string(), + spec: Some(SandboxSpec::default()), + labels: HashMap::new(), + annotations: HashMap::new(), + workspace: "default".to_string(), + workload_template_name: "default-gpu".to_string(), + }), + ) + .await + .expect("sandbox create from template should succeed") + .into_inner() + .sandbox + .expect("created sandbox"); + + let gpu = created + .spec + .as_ref() + .and_then(|spec| spec.resource_requirements.as_ref()) + .and_then(|requirements| requirements.gpu.as_ref()) + .expect("default GPU request should be preserved"); + assert_eq!(gpu.count, None); + } + #[tokio::test] async fn create_sandbox_from_workload_template_rejects_inline_workload_overrides() { let state = test_server_state().await; diff --git a/proto/openshell.proto b/proto/openshell.proto index ad4a41b9ff..edb5723d8b 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -946,8 +946,10 @@ message SandboxResources { string cpu = 1; // Portable memory quantity, for example "512Mi" or "2Gi". string memory = 2; - // Optional number of GPUs requested. - optional uint32 gpu_count = 3; + // GPU requirements for the sandbox workload. Presence indicates a GPU + // request. When count is omitted, the request uses the selected driver's + // default GPU assignment behavior. + GpuResourceRequirements gpu = 3; } message SandboxServiceLevel { diff --git a/sdk/go/docs/src/api/sandbox-templates.md b/sdk/go/docs/src/api/sandbox-templates.md index 66bc74fabc..d190d59e75 100644 --- a/sdk/go/docs/src/api/sandbox-templates.md +++ b/sdk/go/docs/src/api/sandbox-templates.md @@ -30,9 +30,9 @@ template, err := client.SandboxTemplates().Create(ctx, "default", &v1.SandboxWor "NVIDIA_VISIBLE_DEVICES": "all", }, Resources: &v1.SandboxResources{ - CPU: "2", - Memory: "8Gi", - GPUCount: &gpuCount, + CPU: "2", + Memory: "8Gi", + GPU: &v1.SandboxGPURequirements{Count: &gpuCount}, }, }, DriverConfig: map[string]any{ @@ -50,6 +50,9 @@ template, err := client.SandboxTemplates().Create(ctx, "default", &v1.SandboxWor }) ``` +Set `GPU: &v1.SandboxGPURequirements{}` to request the active driver's default +GPU assignment without specifying a count. + ## Create a Sandbox From a Template Use `CreateSandboxFromTemplate` to create a sandbox from a named reusable diff --git a/sdk/go/openshell/v1/fake/sandbox.go b/sdk/go/openshell/v1/fake/sandbox.go index 68474c4e58..95d5e4c428 100644 --- a/sdk/go/openshell/v1/fake/sandbox.go +++ b/sdk/go/openshell/v1/fake/sandbox.go @@ -394,8 +394,8 @@ func sandboxSpecFromWorkloadTemplate(template *types.SandboxWorkloadTemplate) ty Resources: sandboxTemplateResources(workload.Resources), DriverConfig: copyAnyMap(template.Spec.DriverConfig), } - if workload.Resources != nil && workload.Resources.GPUCount != nil { - count := *workload.Resources.GPUCount + if workload.Resources != nil && workload.Resources.GPU != nil && workload.Resources.GPU.Count != nil { + count := *workload.Resources.GPU.Count spec.GPUCount = &count } return spec diff --git a/sdk/go/openshell/v1/fake/sandbox_template.go b/sdk/go/openshell/v1/fake/sandbox_template.go index 0cab5f8a95..ee9870ff4d 100644 --- a/sdk/go/openshell/v1/fake/sandbox_template.go +++ b/sdk/go/openshell/v1/fake/sandbox_template.go @@ -36,9 +36,13 @@ func copySandboxWorkloadTemplateSpec(spec types.SandboxWorkloadTemplateSpec) typ workload.Environment = copyStringMap(spec.Workload.Environment) if spec.Workload.Resources != nil { resources := *spec.Workload.Resources - if spec.Workload.Resources.GPUCount != nil { - count := *spec.Workload.Resources.GPUCount - resources.GPUCount = &count + if spec.Workload.Resources.GPU != nil { + gpu := *spec.Workload.Resources.GPU + if spec.Workload.Resources.GPU.Count != nil { + count := *spec.Workload.Resources.GPU.Count + gpu.Count = &count + } + resources.GPU = &gpu } workload.Resources = &resources } diff --git a/sdk/go/openshell/v1/fake/sandbox_template_test.go b/sdk/go/openshell/v1/fake/sandbox_template_test.go index b5eab7b69b..bc8010fa31 100644 --- a/sdk/go/openshell/v1/fake/sandbox_template_test.go +++ b/sdk/go/openshell/v1/fake/sandbox_template_test.go @@ -111,9 +111,9 @@ func TestSandboxTemplate_CreateSandboxFromTemplateResolvesWorkloadAndGovernance( Image: "registry.example.com/agent:latest", Environment: map[string]string{"FEATURE_FLAG": "on"}, Resources: &types.SandboxResources{ - CPU: "2", - Memory: "4Gi", - GPUCount: &gpuCount, + CPU: "2", + Memory: "4Gi", + GPU: &types.SandboxGPURequirements{Count: &gpuCount}, }, }, DriverConfig: map[string]any{ @@ -152,6 +152,31 @@ func TestSandboxTemplate_CreateSandboxFromTemplateResolvesWorkloadAndGovernance( assert.Equal(t, "7", created.CreatedFromWorkloadTemplate.ResourceVersion) } +func TestSandboxTemplate_DefaultGpuRequestRoundTripsTemplate(t *testing.T) { + tc := newTestSandboxTemplateClient() + ctx := context.Background() + + created, err := tc.Create(ctx, "default", &types.SandboxWorkloadTemplate{ + Name: "default-gpu", + Spec: types.SandboxWorkloadTemplateSpec{ + Workload: &types.SandboxWorkloadConfig{ + Resources: &types.SandboxResources{ + GPU: &types.SandboxGPURequirements{}, + }, + }, + }, + }) + + require.NoError(t, err) + require.NotNil(t, created.Spec.Workload.Resources.GPU) + assert.Nil(t, created.Spec.Workload.Resources.GPU.Count) + + got, err := tc.Get(ctx, "default", "default-gpu") + require.NoError(t, err) + require.NotNil(t, got.Spec.Workload.Resources.GPU) + assert.Nil(t, got.Spec.Workload.Resources.GPU.Count) +} + func TestSandboxTemplate_DeepCopy(t *testing.T) { tc := newTestSandboxTemplateClient() ctx := context.Background() diff --git a/sdk/go/openshell/v1/internal/converter/coverage_test.go b/sdk/go/openshell/v1/internal/converter/coverage_test.go index 107964cd38..c20015c59a 100644 --- a/sdk/go/openshell/v1/internal/converter/coverage_test.go +++ b/sdk/go/openshell/v1/internal/converter/coverage_test.go @@ -81,9 +81,9 @@ func TestConverterCoversAllProtoFields_SandboxWorkloadConfig(t *testing.T) { func TestConverterCoversAllProtoFields_SandboxResources(t *testing.T) { handled := fieldSet{ - "cpu": true, - "memory": true, - "gpu_count": true, + "cpu": true, + "memory": true, + "gpu": true, } assertAllFieldsCovered(t, (&pb.SandboxResources{}).ProtoReflect().Descriptor(), handled, nil) diff --git a/sdk/go/openshell/v1/internal/converter/sandbox.go b/sdk/go/openshell/v1/internal/converter/sandbox.go index b6e54804b6..b75ee060bb 100644 --- a/sdk/go/openshell/v1/internal/converter/sandbox.go +++ b/sdk/go/openshell/v1/internal/converter/sandbox.go @@ -319,9 +319,9 @@ func SandboxResourcesFromProto(resources *pb.SandboxResources) *types.SandboxRes return nil } return &types.SandboxResources{ - CPU: resources.GetCpu(), - Memory: resources.GetMemory(), - GPUCount: CopyUint32Ptr(resources.GpuCount), + CPU: resources.GetCpu(), + Memory: resources.GetMemory(), + GPU: sandboxResourceGpuFromProto(resources), } } @@ -401,12 +401,26 @@ func SandboxResourcesToProto(resources *types.SandboxResources) *pb.SandboxResou return nil } return &pb.SandboxResources{ - Cpu: resources.CPU, - Memory: resources.Memory, - GpuCount: CopyUint32Ptr(resources.GPUCount), + Cpu: resources.CPU, + Memory: resources.Memory, + Gpu: sandboxResourceGpuToProto(resources), } } +func sandboxResourceGpuToProto(resources *types.SandboxResources) *pb.GpuResourceRequirements { + if resources == nil || resources.GPU == nil { + return nil + } + return &pb.GpuResourceRequirements{Count: CopyUint32Ptr(resources.GPU.Count)} +} + +func sandboxResourceGpuFromProto(resources *pb.SandboxResources) *types.SandboxGPURequirements { + if resources == nil || resources.GetGpu() == nil { + return nil + } + return &types.SandboxGPURequirements{Count: CopyUint32Ptr(resources.GetGpu().Count)} +} + // SandboxServiceLevelToProto converts template service-level hints. func SandboxServiceLevelToProto(level *types.SandboxServiceLevel) *pb.SandboxServiceLevel { if level == nil { diff --git a/sdk/go/openshell/v1/internal/converter/sandbox_test.go b/sdk/go/openshell/v1/internal/converter/sandbox_test.go index 14952791c7..f12390f0a4 100644 --- a/sdk/go/openshell/v1/internal/converter/sandbox_test.go +++ b/sdk/go/openshell/v1/internal/converter/sandbox_test.go @@ -324,9 +324,9 @@ func TestSandboxWorkloadTemplateRoundTrip(t *testing.T) { Image: "nvcr.io/nvidia/openshell:latest", Environment: map[string]string{"CUDA_VISIBLE_DEVICES": "all"}, Resources: &v1.SandboxResources{ - CPU: "2", - Memory: "8Gi", - GPUCount: &gpuCount, + CPU: "2", + Memory: "8Gi", + GPU: &v1.SandboxGPURequirements{Count: &gpuCount}, }, }, DriverConfig: map[string]any{ @@ -353,8 +353,9 @@ func TestSandboxWorkloadTemplateRoundTrip(t *testing.T) { require.NotNil(t, protoTemplate.Spec.Workload.Resources) assert.Equal(t, "2", protoTemplate.Spec.Workload.Resources.Cpu) assert.Equal(t, "8Gi", protoTemplate.Spec.Workload.Resources.Memory) - require.NotNil(t, protoTemplate.Spec.Workload.Resources.GpuCount) - assert.Equal(t, uint32(2), *protoTemplate.Spec.Workload.Resources.GpuCount) + require.NotNil(t, protoTemplate.Spec.Workload.Resources.Gpu) + require.NotNil(t, protoTemplate.Spec.Workload.Resources.Gpu.Count) + assert.Equal(t, uint32(2), *protoTemplate.Spec.Workload.Resources.Gpu.Count) require.NotNil(t, protoTemplate.Spec.DriverConfig) require.NotNil(t, protoTemplate.Spec.DesiredServiceLevel) require.NotNil(t, protoTemplate.Spec.DesiredServiceLevel.Startup) @@ -378,8 +379,9 @@ func TestSandboxWorkloadTemplateRoundTrip(t *testing.T) { require.NotNil(t, back.Spec.Workload.Resources) assert.Equal(t, original.Spec.Workload.Resources.CPU, back.Spec.Workload.Resources.CPU) assert.Equal(t, original.Spec.Workload.Resources.Memory, back.Spec.Workload.Resources.Memory) - require.NotNil(t, back.Spec.Workload.Resources.GPUCount) - assert.Equal(t, *original.Spec.Workload.Resources.GPUCount, *back.Spec.Workload.Resources.GPUCount) + require.NotNil(t, back.Spec.Workload.Resources.GPU) + require.NotNil(t, back.Spec.Workload.Resources.GPU.Count) + assert.Equal(t, *original.Spec.Workload.Resources.GPU.Count, *back.Spec.Workload.Resources.GPU.Count) assert.Equal(t, "kata", back.Spec.DriverConfig["kubernetes"].(map[string]any)["runtimeClassName"]) require.NotNil(t, back.Spec.DesiredServiceLevel) require.NotNil(t, back.Spec.DesiredServiceLevel.Startup) @@ -387,6 +389,28 @@ func TestSandboxWorkloadTemplateRoundTrip(t *testing.T) { assert.Equal(t, uint32(3), back.Spec.DesiredServiceLevel.Startup.MaxBurst) } +func TestSandboxWorkloadTemplateRoundTrip_DefaultGpuRequest(t *testing.T) { + original := &v1.SandboxWorkloadTemplate{ + Name: "default-gpu", + Spec: v1.SandboxWorkloadTemplateSpec{ + Workload: &v1.SandboxWorkloadConfig{ + Resources: &v1.SandboxResources{ + GPU: &v1.SandboxGPURequirements{}, + }, + }, + }, + } + + protoTemplate, err := SandboxWorkloadTemplateToProtoChecked(original) + require.NoError(t, err) + require.NotNil(t, protoTemplate.GetSpec().GetWorkload().GetResources().GetGpu()) + assert.Nil(t, protoTemplate.GetSpec().GetWorkload().GetResources().GetGpu().Count) + + back := SandboxWorkloadTemplateFromProto(protoTemplate) + require.NotNil(t, back.Spec.Workload.Resources.GPU) + assert.Nil(t, back.Spec.Workload.Resources.GPU.Count) +} + func TestSandboxWorkloadTemplateToProtoChecked_RejectsUnrepresentableDriverConfig(t *testing.T) { _, err := SandboxWorkloadTemplateToProtoChecked(&v1.SandboxWorkloadTemplate{ Name: "bad", diff --git a/sdk/go/openshell/v1/sandbox_template.go b/sdk/go/openshell/v1/sandbox_template.go index bc94aaf741..e2fc8c22b1 100644 --- a/sdk/go/openshell/v1/sandbox_template.go +++ b/sdk/go/openshell/v1/sandbox_template.go @@ -21,6 +21,9 @@ type SandboxWorkloadConfig = types.SandboxWorkloadConfig // SandboxResources defines portable sandbox resource requirements. type SandboxResources = types.SandboxResources +// SandboxGPURequirements defines template GPU requirements. +type SandboxGPURequirements = types.SandboxGPURequirements + // SandboxServiceLevel describes desired operational characteristics. type SandboxServiceLevel = types.SandboxServiceLevel diff --git a/sdk/go/openshell/v1/sandbox_template_client_test.go b/sdk/go/openshell/v1/sandbox_template_client_test.go index 864a13bd5e..b58f1a089d 100644 --- a/sdk/go/openshell/v1/sandbox_template_client_test.go +++ b/sdk/go/openshell/v1/sandbox_template_client_test.go @@ -139,9 +139,9 @@ func TestSandboxTemplateCreate(t *testing.T) { Image: "nvcr.io/nvidia/openshell:latest", Environment: map[string]string{"NVIDIA_VISIBLE_DEVICES": "all"}, Resources: &SandboxResources{ - CPU: "2", - Memory: "8Gi", - GPUCount: &gpuCount, + CPU: "2", + Memory: "8Gi", + GPU: &SandboxGPURequirements{Count: &gpuCount}, }, }, DriverConfig: map[string]any{ @@ -168,7 +168,9 @@ func TestSandboxTemplateCreate(t *testing.T) { assert.Equal(t, "gpu-kata", mock.createRequest.Template.Metadata.Name) assert.Equal(t, "2", mock.createRequest.Template.Spec.Workload.Resources.Cpu) assert.Equal(t, "8Gi", mock.createRequest.Template.Spec.Workload.Resources.Memory) - assert.Equal(t, uint32(1), mock.createRequest.Template.Spec.Workload.Resources.GetGpuCount()) + require.NotNil(t, mock.createRequest.Template.Spec.Workload.Resources.Gpu) + require.NotNil(t, mock.createRequest.Template.Spec.Workload.Resources.Gpu.Count) + assert.Equal(t, uint32(1), *mock.createRequest.Template.Spec.Workload.Resources.Gpu.Count) assert.Equal(t, durationpb.New(45*time.Second), mock.createRequest.Template.Spec.DesiredServiceLevel.Startup.ReadyWithin) } diff --git a/sdk/go/openshell/v1/types/sandbox.go b/sdk/go/openshell/v1/types/sandbox.go index 1629db9999..d352d07594 100644 --- a/sdk/go/openshell/v1/types/sandbox.go +++ b/sdk/go/openshell/v1/types/sandbox.go @@ -73,9 +73,16 @@ type SandboxWorkloadConfig struct { // SandboxResources defines portable sandbox resource requirements. type SandboxResources struct { - CPU string - Memory string - GPUCount *uint32 + CPU string + Memory string + // GPU requests GPU resources for template-backed sandboxes. A non-nil GPU + // with nil Count requests the active driver's default GPU assignment. + GPU *SandboxGPURequirements +} + +// SandboxGPURequirements defines template GPU requirements. +type SandboxGPURequirements struct { + Count *uint32 } // SandboxServiceLevel describes desired operational characteristics. diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index 5122689899..5bbfbb56e5 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -1613,8 +1613,10 @@ type SandboxResources struct { Cpu string `protobuf:"bytes,1,opt,name=cpu,proto3" json:"cpu,omitempty"` // Portable memory quantity, for example "512Mi" or "2Gi". Memory string `protobuf:"bytes,2,opt,name=memory,proto3" json:"memory,omitempty"` - // Optional number of GPUs requested. - GpuCount *uint32 `protobuf:"varint,3,opt,name=gpu_count,json=gpuCount,proto3,oneof" json:"gpu_count,omitempty"` + // GPU requirements for the sandbox workload. Presence indicates a GPU + // request. When count is omitted, the request uses the selected driver's + // default GPU assignment behavior. + Gpu *GpuResourceRequirements `protobuf:"bytes,3,opt,name=gpu,proto3" json:"gpu,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1663,11 +1665,11 @@ func (x *SandboxResources) GetMemory() string { return "" } -func (x *SandboxResources) GetGpuCount() uint32 { - if x != nil && x.GpuCount != nil { - return *x.GpuCount +func (x *SandboxResources) GetGpu() *GpuResourceRequirements { + if x != nil { + return x.Gpu } - return 0 + return nil } type SandboxServiceLevel struct { @@ -14055,13 +14057,11 @@ const file_openshell_proto_rawDesc = "" + "\tresources\x18\x03 \x01(\v2\x1e.openshell.v1.SandboxResourcesR\tresources\x1a>\n" + "\x10EnvironmentEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"l\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"u\n" + "\x10SandboxResources\x12\x10\n" + "\x03cpu\x18\x01 \x01(\tR\x03cpu\x12\x16\n" + - "\x06memory\x18\x02 \x01(\tR\x06memory\x12 \n" + - "\tgpu_count\x18\x03 \x01(\rH\x00R\bgpuCount\x88\x01\x01B\f\n" + - "\n" + - "_gpu_count\"M\n" + + "\x06memory\x18\x02 \x01(\tR\x06memory\x127\n" + + "\x03gpu\x18\x03 \x01(\v2%.openshell.v1.GpuResourceRequirementsR\x03gpu\"M\n" + "\x13SandboxServiceLevel\x126\n" + "\astartup\x18\x01 \x01(\v2\x1c.openshell.v1.SandboxStartupR\astartup\"k\n" + "\x0eSandboxStartup\x12<\n" + @@ -15497,293 +15497,294 @@ var file_openshell_proto_depIdxs = []int32{ 27, // 23: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel 210, // 24: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry 26, // 25: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources - 28, // 26: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup - 235, // 27: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration - 31, // 28: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition - 0, // 29: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 211, // 30: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 19, // 31: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 212, // 32: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 213, // 33: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 23, // 34: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 23, // 35: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 23, // 36: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate - 18, // 37: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 18, // 38: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 236, // 39: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 18, // 40: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 18, // 41: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 64, // 42: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 232, // 43: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 63, // 44: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint - 214, // 45: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 68, // 46: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout - 69, // 47: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr - 70, // 48: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 155, // 49: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 156, // 50: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget - 72, // 51: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit - 67, // 52: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest - 75, // 53: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 232, // 54: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 18, // 55: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox - 79, // 56: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine - 32, // 57: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent - 80, // 58: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 166, // 59: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 215, // 60: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 236, // 61: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 236, // 62: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 216, // 63: openshell.v1.UpdateProviderRequest.credential_expires_at_ms:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry - 236, // 64: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider - 236, // 65: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 110, // 66: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 92, // 67: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride - 97, // 68: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh - 93, // 69: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant - 1, // 70: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 95, // 71: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial - 96, // 72: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput - 1, // 73: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 232, // 74: openshell.v1.StoredProviderCredentialRefreshState.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 1, // 75: openshell.v1.StoredProviderCredentialRefreshState.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 217, // 76: openshell.v1.StoredProviderCredentialRefreshState.material:type_name -> openshell.v1.StoredProviderCredentialRefreshState.MaterialEntry - 218, // 77: openshell.v1.StoredProviderCredentialRefreshState.additional_output_keys:type_name -> openshell.v1.StoredProviderCredentialRefreshState.AdditionalOutputKeysEntry - 219, // 78: openshell.v1.StoredProviderCredentialRefreshState.secret_material_handles:type_name -> openshell.v1.StoredProviderCredentialRefreshState.SecretMaterialHandlesEntry - 101, // 79: openshell.v1.StoredProviderCredentialRefreshState.pending_secret_deletions:type_name -> openshell.v1.StoredRefreshMaterialDeletion - 237, // 80: openshell.v1.StoredRefreshMaterialDeletion.handle:type_name -> openshell.datamodel.v1.CredentialHandle - 98, // 81: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 1, // 82: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 220, // 83: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 98, // 84: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 98, // 85: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 2, // 86: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory - 94, // 87: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 238, // 88: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 239, // 89: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 99, // 90: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 221, // 91: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 232, // 92: openshell.v1.StoredProviderProfile.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 110, // 93: openshell.v1.StoredProviderProfile.profile:type_name -> openshell.v1.ProviderProfile - 110, // 94: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 110, // 95: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 90, // 96: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 91, // 97: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 110, // 98: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 90, // 99: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 91, // 100: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 110, // 101: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 90, // 102: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 91, // 103: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 124, // 104: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 222, // 105: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 223, // 106: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expires_at_ms:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry - 224, // 107: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 225, // 108: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 233, // 109: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 240, // 110: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 128, // 111: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 226, // 112: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 129, // 113: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 130, // 114: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 131, // 115: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 132, // 116: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 133, // 117: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 134, // 118: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 241, // 119: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 242, // 120: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 243, // 121: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 227, // 122: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 142, // 123: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 142, // 124: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 3, // 125: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 3, // 126: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 233, // 127: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 228, // 128: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 79, // 129: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 79, // 130: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 149, // 131: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 152, // 132: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 159, // 133: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 160, // 134: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 150, // 135: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 151, // 136: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 153, // 137: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 154, // 138: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 160, // 139: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 155, // 140: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 156, // 141: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 157, // 142: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 161, // 143: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 163, // 144: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 241, // 145: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 162, // 146: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 165, // 147: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 164, // 148: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 165, // 149: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 241, // 150: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 184, // 151: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 233, // 152: openshell.v1.PolicyRevisionPayload.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 229, // 153: openshell.v1.PolicyRevisionPayload.provenance:type_name -> openshell.v1.PolicyRevisionPayload.ProvenanceEntry - 241, // 154: openshell.v1.DraftChunkPayload.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 230, // 155: openshell.v1.StoredPolicyRevision.provenance:type_name -> openshell.v1.StoredPolicyRevision.ProvenanceEntry - 231, // 156: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 244, // 157: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 244, // 158: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 244, // 159: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 232, // 160: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 5, // 161: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 5, // 162: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 198, // 163: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 198, // 164: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 237, // 165: openshell.v1.StoredProviderCredentialRefreshState.SecretMaterialHandlesEntry.value:type_name -> openshell.datamodel.v1.CredentialHandle - 94, // 166: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 125, // 167: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 10, // 168: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 12, // 169: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 14, // 170: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 33, // 171: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 41, // 172: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 42, // 173: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 34, // 174: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 35, // 175: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 36, // 176: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 37, // 177: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 43, // 178: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 44, // 179: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 45, // 180: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 46, // 181: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 47, // 182: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 48, // 183: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 55, // 184: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 57, // 185: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 58, // 186: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 59, // 187: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 61, // 188: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 65, // 189: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 67, // 190: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 73, // 191: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 74, // 192: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 81, // 193: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 82, // 194: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 83, // 195: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 88, // 196: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 89, // 197: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 114, // 198: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 116, // 199: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 118, // 200: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 84, // 201: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 102, // 202: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 104, // 203: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 106, // 204: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 108, // 205: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 85, // 206: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 121, // 207: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 245, // 208: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 246, // 209: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 127, // 210: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 136, // 211: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 138, // 212: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 140, // 213: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 123, // 214: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 143, // 215: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 144, // 216: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 147, // 217: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 158, // 218: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 77, // 219: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 167, // 220: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 169, // 221: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 171, // 222: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 173, // 223: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 175, // 224: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 177, // 225: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 179, // 226: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 181, // 227: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 183, // 228: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 6, // 229: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 8, // 230: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 190, // 231: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 192, // 232: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 194, // 233: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 196, // 234: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 199, // 235: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 201, // 236: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 203, // 237: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 11, // 238: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 13, // 239: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 15, // 240: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 49, // 241: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 49, // 242: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 50, // 243: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 38, // 244: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 38, // 245: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 39, // 246: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 40, // 247: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 51, // 248: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 52, // 249: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 53, // 250: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 54, // 251: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 49, // 252: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 49, // 253: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 56, // 254: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 64, // 255: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 64, // 256: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 60, // 257: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 62, // 258: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 66, // 259: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 71, // 260: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 73, // 261: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 71, // 262: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 86, // 263: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 86, // 264: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 87, // 265: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 113, // 266: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 112, // 267: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 115, // 268: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 117, // 269: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 119, // 270: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 86, // 271: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 103, // 272: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 105, // 273: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 107, // 274: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 109, // 275: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 120, // 276: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 122, // 277: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 247, // 278: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 248, // 279: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 135, // 280: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 137, // 281: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 139, // 282: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 141, // 283: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 126, // 284: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 146, // 285: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 145, // 286: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 148, // 287: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 158, // 288: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 78, // 289: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 168, // 290: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 170, // 291: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 172, // 292: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 174, // 293: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 176, // 294: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 178, // 295: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 180, // 296: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 182, // 297: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 185, // 298: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 7, // 299: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 9, // 300: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 191, // 301: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 193, // 302: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 195, // 303: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 197, // 304: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 200, // 305: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 202, // 306: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 204, // 307: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 238, // [238:308] is the sub-list for method output_type - 168, // [168:238] is the sub-list for method input_type - 168, // [168:168] is the sub-list for extension type_name - 168, // [168:168] is the sub-list for extension extendee - 0, // [0:168] is the sub-list for field type_name + 21, // 26: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements + 28, // 27: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup + 235, // 28: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 31, // 29: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition + 0, // 30: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase + 211, // 31: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 19, // 32: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec + 212, // 33: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 213, // 34: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 23, // 35: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 23, // 36: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 23, // 37: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate + 18, // 38: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox + 18, // 39: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox + 236, // 40: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 18, // 41: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 18, // 42: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 64, // 43: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse + 232, // 44: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 63, // 45: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint + 214, // 46: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 68, // 47: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout + 69, // 48: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr + 70, // 49: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit + 155, // 50: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget + 156, // 51: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget + 72, // 52: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit + 67, // 53: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest + 75, // 54: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize + 232, // 55: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 18, // 56: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox + 79, // 57: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine + 32, // 58: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent + 80, // 59: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning + 166, // 60: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 215, // 61: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 236, // 62: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 236, // 63: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 216, // 64: openshell.v1.UpdateProviderRequest.credential_expires_at_ms:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry + 236, // 65: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 236, // 66: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 110, // 67: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile + 92, // 68: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride + 97, // 69: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh + 93, // 70: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant + 1, // 71: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 95, // 72: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial + 96, // 73: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput + 1, // 74: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 232, // 75: openshell.v1.StoredProviderCredentialRefreshState.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 1, // 76: openshell.v1.StoredProviderCredentialRefreshState.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 217, // 77: openshell.v1.StoredProviderCredentialRefreshState.material:type_name -> openshell.v1.StoredProviderCredentialRefreshState.MaterialEntry + 218, // 78: openshell.v1.StoredProviderCredentialRefreshState.additional_output_keys:type_name -> openshell.v1.StoredProviderCredentialRefreshState.AdditionalOutputKeysEntry + 219, // 79: openshell.v1.StoredProviderCredentialRefreshState.secret_material_handles:type_name -> openshell.v1.StoredProviderCredentialRefreshState.SecretMaterialHandlesEntry + 101, // 80: openshell.v1.StoredProviderCredentialRefreshState.pending_secret_deletions:type_name -> openshell.v1.StoredRefreshMaterialDeletion + 237, // 81: openshell.v1.StoredRefreshMaterialDeletion.handle:type_name -> openshell.datamodel.v1.CredentialHandle + 98, // 82: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 1, // 83: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 220, // 84: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 98, // 85: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 98, // 86: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 2, // 87: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory + 94, // 88: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential + 238, // 89: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 239, // 90: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 99, // 91: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery + 221, // 92: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 232, // 93: openshell.v1.StoredProviderProfile.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 110, // 94: openshell.v1.StoredProviderProfile.profile:type_name -> openshell.v1.ProviderProfile + 110, // 95: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile + 110, // 96: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 90, // 97: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 91, // 98: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 110, // 99: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 90, // 100: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem + 91, // 101: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 110, // 102: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile + 90, // 103: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 91, // 104: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 124, // 105: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding + 222, // 106: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 223, // 107: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expires_at_ms:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry + 224, // 108: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 225, // 109: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 233, // 110: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 240, // 111: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 128, // 112: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation + 226, // 113: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 129, // 114: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule + 130, // 115: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint + 131, // 116: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule + 132, // 117: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules + 133, // 118: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules + 134, // 119: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary + 241, // 120: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 242, // 121: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 243, // 122: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 227, // 123: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 142, // 124: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 142, // 125: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 3, // 126: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 3, // 127: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 233, // 128: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 228, // 129: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 79, // 130: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 79, // 131: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 149, // 132: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello + 152, // 133: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat + 159, // 134: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 160, // 135: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 150, // 136: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted + 151, // 137: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected + 153, // 138: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat + 154, // 139: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen + 160, // 140: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 155, // 141: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget + 156, // 142: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget + 157, // 143: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit + 161, // 144: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 163, // 145: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 241, // 146: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 162, // 147: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 165, // 148: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 164, // 149: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 165, // 150: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 241, // 151: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 184, // 152: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 233, // 153: openshell.v1.PolicyRevisionPayload.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 229, // 154: openshell.v1.PolicyRevisionPayload.provenance:type_name -> openshell.v1.PolicyRevisionPayload.ProvenanceEntry + 241, // 155: openshell.v1.DraftChunkPayload.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 230, // 156: openshell.v1.StoredPolicyRevision.provenance:type_name -> openshell.v1.StoredPolicyRevision.ProvenanceEntry + 231, // 157: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 244, // 158: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 244, // 159: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 244, // 160: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 232, // 161: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 5, // 162: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 5, // 163: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 198, // 164: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 198, // 165: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 237, // 166: openshell.v1.StoredProviderCredentialRefreshState.SecretMaterialHandlesEntry.value:type_name -> openshell.datamodel.v1.CredentialHandle + 94, // 167: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 125, // 168: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 10, // 169: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 12, // 170: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 14, // 171: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 33, // 172: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 41, // 173: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 42, // 174: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 34, // 175: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 35, // 176: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 36, // 177: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 37, // 178: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 43, // 179: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 44, // 180: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 45, // 181: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 46, // 182: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 47, // 183: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 48, // 184: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 55, // 185: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 57, // 186: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 58, // 187: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 59, // 188: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 61, // 189: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 65, // 190: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 67, // 191: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 73, // 192: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 74, // 193: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 81, // 194: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 82, // 195: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 83, // 196: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 88, // 197: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 89, // 198: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 114, // 199: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 116, // 200: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 118, // 201: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 84, // 202: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 102, // 203: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 104, // 204: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 106, // 205: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 108, // 206: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 85, // 207: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 121, // 208: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 245, // 209: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 246, // 210: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 127, // 211: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 136, // 212: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 138, // 213: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 140, // 214: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 123, // 215: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 143, // 216: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 144, // 217: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 147, // 218: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 158, // 219: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 77, // 220: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 167, // 221: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 169, // 222: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 171, // 223: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 173, // 224: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 175, // 225: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 177, // 226: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 179, // 227: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 181, // 228: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 183, // 229: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 6, // 230: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 8, // 231: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 190, // 232: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 192, // 233: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 194, // 234: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 196, // 235: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 199, // 236: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 201, // 237: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 203, // 238: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 11, // 239: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 13, // 240: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 15, // 241: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 49, // 242: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 49, // 243: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 50, // 244: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 38, // 245: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 38, // 246: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 39, // 247: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 40, // 248: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 51, // 249: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 52, // 250: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 53, // 251: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 54, // 252: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 49, // 253: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 49, // 254: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 56, // 255: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 64, // 256: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 64, // 257: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 60, // 258: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 62, // 259: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 66, // 260: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 71, // 261: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 73, // 262: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 71, // 263: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 86, // 264: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 86, // 265: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 87, // 266: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 113, // 267: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 112, // 268: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 115, // 269: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 117, // 270: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 119, // 271: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 86, // 272: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 103, // 273: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 105, // 274: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 107, // 275: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 109, // 276: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 120, // 277: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 122, // 278: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 247, // 279: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 248, // 280: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 135, // 281: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 137, // 282: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 139, // 283: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 141, // 284: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 126, // 285: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 146, // 286: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 145, // 287: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 148, // 288: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 158, // 289: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 78, // 290: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 168, // 291: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 170, // 292: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 172, // 293: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 174, // 294: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 176, // 295: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 178, // 296: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 180, // 297: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 182, // 298: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 185, // 299: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 7, // 300: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 9, // 301: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 191, // 302: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 193, // 303: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 195, // 304: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 197, // 305: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 200, // 306: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 202, // 307: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 204, // 308: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 239, // [239:309] is the sub-list for method output_type + 169, // [169:239] is the sub-list for method input_type + 169, // [169:169] is the sub-list for extension type_name + 169, // [169:169] is the sub-list for extension extendee + 0, // [0:169] is the sub-list for field type_name } func init() { file_openshell_proto_init() } @@ -15793,7 +15794,6 @@ func file_openshell_proto_init() { } file_openshell_proto_msgTypes[15].OneofWrappers = []any{} file_openshell_proto_msgTypes[16].OneofWrappers = []any{} - file_openshell_proto_msgTypes[20].OneofWrappers = []any{} file_openshell_proto_msgTypes[65].OneofWrappers = []any{ (*ExecSandboxEvent_Stdout)(nil), (*ExecSandboxEvent_Stderr)(nil), diff --git a/sdk/typescript/src/client.test.ts b/sdk/typescript/src/client.test.ts index d5c7ff3c77..71b9f68d25 100644 --- a/sdk/typescript/src/client.test.ts +++ b/sdk/typescript/src/client.test.ts @@ -308,7 +308,7 @@ describe('sandbox templates', () => { workload?: { image?: string; environment?: Record; - resources?: { cpu?: string; memory?: string; gpuCount?: number }; + resources?: { cpu?: string; memory?: string; gpu?: { count?: number } }; }; driverConfig?: Record; }; @@ -339,7 +339,7 @@ describe('sandbox templates', () => { workload: { image: 'ghcr.io/nvidia/openshell-community/sandboxes/python:latest', environment: { FEATURE_FLAG: 'on' }, - resources: { cpu: '1', memory: '512Mi', gpuCount: 1 }, + resources: { cpu: '1', memory: '512Mi', gpu: { count: 1 } }, }, driverConfig: { kubernetes: { runtime_class_name: 'kata-containers' } }, }, @@ -351,7 +351,7 @@ describe('sandbox templates', () => { expect(observed.template?.metadata?.name).toBe('python'); expect(observed.template?.metadata?.labels).toEqual({ team: 'runtime' }); expect(observed.template?.spec?.workload?.environment).toEqual({ FEATURE_FLAG: 'on' }); - expect(observed.template?.spec?.workload?.resources?.gpuCount).toBe(1); + expect(observed.template?.spec?.workload?.resources?.gpu?.count).toBe(1); expect(created.metadata?.workspace).toBe('default'); expect(created.metadata?.resourceVersion).toBe(1n); }); From 18781f5d84aba8218595fac451298816a2897f5d Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Thu, 20 Aug 2026 10:33:00 +0100 Subject: [PATCH 8/9] fix(server): cap sandbox templates per workspace Signed-off-by: Gordon Sim --- crates/openshell-server/src/grpc/sandbox.rs | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index d1448c00d2..8369be6618 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -67,6 +67,7 @@ use super::{MAX_PAGE_SIZE, MAX_PROVIDERS, MAX_ROUTABLE_NAME_LEN, clamp_limit}; use crate::persistence::current_time_ms; const TCP_FORWARD_CHUNK_SIZE: usize = 64 * 1024; +const MAX_TEMPLATES_PER_WORKSPACE: u32 = 1000; #[derive(Debug)] pub struct WatchSandboxStream { @@ -668,6 +669,17 @@ pub(super) async fn handle_create_sandbox_template( }); validate_sandbox_workload_template(&resolved)?; + let template_count = state + .store + .count_in_workspace(SandboxWorkloadTemplate::object_type(), &workspace) + .await + .map_err(|e| Status::internal(format!("count sandbox templates failed: {e}")))?; + if template_count >= u64::from(MAX_TEMPLATES_PER_WORKSPACE) { + return Err(Status::resource_exhausted(format!( + "workspace has reached the maximum of {MAX_TEMPLATES_PER_WORKSPACE} sandbox templates" + ))); + } + let labels_map = resolved.object_labels(); let labels_json = if labels_map.as_ref().is_none_or(HashMap::is_empty) { None @@ -4123,6 +4135,31 @@ mod tests { assert!(listed.is_empty()); } + #[tokio::test] + async fn sandbox_template_create_rejects_workspace_quota() { + let state = test_server_state().await; + for index in 0..MAX_TEMPLATES_PER_WORKSPACE { + let mut template = test_workload_template(&format!("tmpl-{index}")); + let metadata = template.metadata.as_mut().expect("metadata"); + metadata.id = format!("template-{index}"); + metadata.workspace = "default".to_string(); + state.store.put_message(&template).await.unwrap(); + } + + let err = handle_create_sandbox_template( + &state, + authed_request(CreateSandboxTemplateRequest { + template: Some(test_workload_template("overflow")), + workspace: "default".to_string(), + }), + ) + .await + .expect_err("template create must reject a full workspace"); + + assert_eq!(err.code(), tonic::Code::ResourceExhausted); + assert!(err.message().contains("1000 sandbox templates")); + } + #[tokio::test] async fn create_sandbox_from_workload_template_resolves_workload_and_preserves_governance() { let state = test_server_state().await; From 2d65e59db4dfeb0d6026a59cd54ced9203fe0976 Mon Sep 17 00:00:00 2001 From: Gordon Sim Date: Thu, 20 Aug 2026 12:00:09 +0100 Subject: [PATCH 9/9] docs(architecture): document sandbox workload template boundaries Signed-off-by: Gordon Sim --- architecture/compute-runtimes.md | 10 ++++++++ architecture/gateway.md | 44 ++++++++++++++++++++------------ architecture/sandbox-limits.md | 9 +++++++ architecture/sandbox.md | 6 +++++ 4 files changed, 52 insertions(+), 17 deletions(-) diff --git a/architecture/compute-runtimes.md b/architecture/compute-runtimes.md index 9c91df496e..632a4b5427 100644 --- a/architecture/compute-runtimes.md +++ b/architecture/compute-runtimes.md @@ -154,6 +154,16 @@ template resource limits. Docker and Podman apply them as runtime limits. Kubernetes mirrors each limit into the matching request. VM accepts the fields but currently ignores them. +Reusable sandbox workload templates are resolved before the compute-driver +boundary. Drivers do not receive a separate template resource; the gateway +lowers the selected `SandboxWorkloadTemplate` into the existing sandbox spec +and validates that spec before calling `ValidateSandboxCreate` or +`CreateSandbox`. Template CPU and memory become the same typed resource limits +described above. Template GPU settings become `ResourceRequirements`, preserving +the driver's default GPU assignment when the count is omitted. Template +`driver_config` remains a driver-keyed envelope until the compute layer selects +the active driver block and forwards only that block to the driver. + Docker and Podman also accept per-sandbox driver-config mounts for existing runtime-managed named volumes and tmpfs mounts. Podman additionally accepts image mounts through its image-volume API. User-supplied bind and volume mounts diff --git a/architecture/gateway.md b/architecture/gateway.md index 0c428526d8..9d485ff7d8 100644 --- a/architecture/gateway.md +++ b/architecture/gateway.md @@ -317,23 +317,33 @@ default WAL journal mode), which mirror the same sensitive contents. Persisted state includes sandboxes, providers, provider credential refresh state, SSH sessions, policy revisions, settings, inference configuration, and -deployment records. Provider refresh state is stored as a separate object -scoped to the provider instance through `objects.scope`. Its non-secret -configuration remains inline, while refresh tokens, client secrets, private -keys, and other secret source material are stored through the active credential -driver and represented by opaque handles. The provider record keeps only the -current injectable credential handles and optional per-credential expiry -timestamps. A refresh normally mints one credential, but a strategy may -co-mint several (AWS STS mints the access key, secret key, and session token in -one call); the refresh state pins the resolved set of env keys it owns so -collision checks reserve all of them before the first mint. Provider records -keep inline credential values only for legacy records created before credential -driver storage. New provider and refresh-material writes keep driver-owned -credential handles. When no external credential driver is configured, gateways -use server-owned encrypted database credential storage for defense in depth. -Multi-replica deployments can use that default with a shared database and -shared key-encryption key, or opt into an external backend such as Vault or -Kubernetes Secrets. +deployment records, and reusable sandbox workload templates. Provider refresh +state is stored as a separate object scoped to the provider instance through +`objects.scope`. Its non-secret configuration remains inline, while refresh +tokens, client secrets, private keys, and other secret source material are +stored through the active credential driver and represented by opaque handles. +The provider record keeps only the current injectable credential handles and +optional per-credential expiry timestamps. A refresh normally mints one +credential, but a strategy may co-mint several (AWS STS mints the access key, +secret key, and session token in one call); the refresh state pins the resolved +set of env keys it owns so collision checks reserve all of them before the +first mint. Provider records keep inline credential values only for legacy +records created before credential driver storage. New provider and +refresh-material writes keep driver-owned credential handles. When no external +credential driver is configured, gateways use server-owned encrypted database +credential storage for defense in depth. Multi-replica deployments can use that +default with a shared database and shared key-encryption key, or opt into an +external backend such as Vault or Kubernetes Secrets. + +Sandbox workload templates are workspace-scoped gateway resources. Workspace +admins create and delete them; workspace users can read and list them. A +template owns reusable workload intent: image, environment, CPU and memory +limits, GPU request, driver-specific config, and service-level hints. A sandbox +created from a template resolves that resource once and persists an ordinary +`SandboxSpec` snapshot. The create request still owns per-sandbox governance: +name, labels, annotations, provider attachments, and policy. The sandbox stores +template provenance as the template name and resource version used for the +snapshot, so later template edits or deletes do not mutate existing sandboxes. Credential handles remain bound to the driver that created them. Before the 0.1.0 compatibility boundary, gateways do not migrate inline refresh material diff --git a/architecture/sandbox-limits.md b/architecture/sandbox-limits.md index 49f1ab7ce9..9635bc1c30 100644 --- a/architecture/sandbox-limits.md +++ b/architecture/sandbox-limits.md @@ -40,6 +40,15 @@ New limits should follow these rules: query parameters, or external free-form diagnostics. - Test time bounds with simulated time and test shared budgets under saturation. +## Gateway Sandbox Resources + +Gateway-owned sandbox resources also carry admission limits before they can +produce supervisor work. Reusable workload templates are capped at 1000 per +workspace. Template payloads reuse sandbox spec validation for environment +entry count and size, image and resource field sizes, driver-config serialized +size, and GPU count. Template names use the same DNS-style resource-name rules +as other named gateway resources. + ## Middleware Middleware limits are process-wide per sandbox. Registry replacement preserves diff --git a/architecture/sandbox.md b/architecture/sandbox.md index 698f88a80a..dd0d11a755 100644 --- a/architecture/sandbox.md +++ b/architecture/sandbox.md @@ -215,6 +215,12 @@ own DNS view, e.g. DoH tunneled via CONNECT, is a possible future enhancement and out of scope.) The workload child's proxy variables are unaffected — they are always rewritten to point at the local policy proxy. +Template environment is treated like user-provided sandbox environment. It can +shape the workload child, but it cannot override driver-controlled identity, +gateway callback, TLS, relay socket, proxy, provider, or supervisor coordination +variables. Drivers and the supervisor rewrite those reserved values after image +and template environment are considered. + The configuration is fail-closed: a setting that is present but invalid — an empty value, an unsupported or malformed proxy URL, an unreadable auth file, a malformed credential, or an auth file or `NO_PROXY` list set while no proxy