diff --git a/TESTING.md b/TESTING.md index 59031f242f..bce0f36a62 100644 --- a/TESTING.md +++ b/TESTING.md @@ -178,6 +178,35 @@ Rust-based e2e tests that exercise the `openshell` CLI binary as a subprocess. They live in the `openshell-e2e` crate and use a shared harness for sandbox lifecycle management, output parsing, and cleanup. +Exposed service URLs use virtual hostnames for gateway routing. Host-side tests +must connect the TCP socket directly to a reachable gateway listener address, +normally loopback, and send the service URL authority in the HTTP `Host` +header. Do not resolve `*.openshell.localhost`; resolver support for arbitrary +`.localhost` subdomains varies across local and CI environments. + +Treat the advertised service URL scheme as authoritative. For HTTPS, use the +virtual service hostname for TLS SNI and the configured gateway trust roots. +When the listener requires mTLS, present the active gateway client identity; +the local e2e wrappers register these materials under +`$XDG_CONFIG_HOME/openshell/gateways/$OPENSHELL_GATEWAY/mtls/`. Do not downgrade +an HTTPS service URL to plaintext when dialing loopback. Parse the URL and load +TLS material before entering a readiness loop so permanent configuration +errors fail immediately. Retry only transient connection failures and +documented readiness responses, and include the last observation in timeout +diagnostics. + +Verify exposed-service tests in both the default local mode and the +CI-equivalent HTTPS mode: + +```shell +mise run e2e:rust +OPENSHELL_ENABLE_LOOPBACK_SERVICE_HTTP=false mise run e2e:rust +``` + +When more than one test needs this behavior, put the transport in the shared +Rust e2e harness and require callers to use it instead of duplicating DNS, +HTTP `Host`, TLS SNI, and mTLS handling. + Suites: - Common suite (`--features e2e`) - driver-neutral CLI behavior, sandbox lifecycle, sync, port forwarding, policy, and provider tests. diff --git a/crates/openshell-cli/src/main.rs b/crates/openshell-cli/src/main.rs index f656fd8833..522df26d41 100644 --- a/crates/openshell-cli/src/main.rs +++ b/crates/openshell-cli/src/main.rs @@ -19,7 +19,7 @@ use openshell_bootstrap::{ use openshell_cli::completers; use openshell_cli::run; use openshell_cli::tls::TlsOptions; -use openshell_core::proto::GpuResourceRequirements; +use openshell_core::proto::{GpuResourceRequirements, ServiceAuthorizationMode}; /// Resolved gateway context: name + gateway endpoint. struct GatewayContext { @@ -770,6 +770,22 @@ enum OutputFormat { Json, } +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, ValueEnum)] +enum CliServiceAuthorizationMode { + #[default] + Strip, + BearerPassthrough, +} + +impl From for ServiceAuthorizationMode { + fn from(value: CliServiceAuthorizationMode) -> Self { + match value { + CliServiceAuthorizationMode::Strip => Self::Strip, + CliServiceAuthorizationMode::BearerPassthrough => Self::BearerPassthrough, + } + } +} + #[derive(Clone, Debug, ValueEnum)] enum CliProviderRefreshStrategy { Oauth2RefreshToken, @@ -1520,6 +1536,10 @@ enum SandboxCommands { )] expose: Option, + /// Handling for an incoming application Authorization header. + #[arg(long, value_enum, default_value_t, requires = "expose")] + expose_authorization_mode: CliServiceAuthorizationMode, + /// Allocate a pseudo-terminal for the remote command. /// Defaults to auto-detection (on when stdin and stdout are terminals). /// Use --tty to force a PTY even when auto-detection fails, or @@ -2364,6 +2384,10 @@ enum ServiceCommands { /// Service name. service: Option, + + /// Handling for an incoming application Authorization header. + #[arg(long, value_enum, default_value_t)] + authorization_mode: CliServiceAuthorizationMode, }, /// List exposed sandbox service endpoints. @@ -2909,6 +2933,7 @@ async fn run_async() -> Result<()> { sandbox, service, target_port, + authorization_mode, } => { let service = service.unwrap_or_default(); run::service_expose( @@ -2916,6 +2941,7 @@ async fn run_async() -> Result<()> { &sandbox, &service, target_port, + authorization_mode.into(), &cli.workspace, &tls, ) @@ -3319,6 +3345,7 @@ async fn run_async() -> Result<()> { policy, forward, expose, + expose_authorization_mode, tty, no_tty, detach, @@ -3416,6 +3443,7 @@ async fn run_async() -> Result<()> { policy: policy.as_deref(), forward, expose, + expose_authorization_mode: expose_authorization_mode.into(), command: &command, tty_override, auto_providers_override, @@ -6626,9 +6654,19 @@ mod tests { match cli.command { Some(Commands::Sandbox { - command: Some(SandboxCommands::Create { expose, detach, .. }), + command: + Some(SandboxCommands::Create { + expose, + expose_authorization_mode, + detach, + .. + }), }) => { assert_eq!(expose, Some(4500)); + assert_eq!( + expose_authorization_mode, + CliServiceAuthorizationMode::Strip + ); assert!(detach); } other => panic!("expected SandboxCommands::Create, got: {other:?}"), @@ -6656,6 +6694,44 @@ mod tests { assert!(result.is_err()); } + #[test] + fn sandbox_create_parses_bearer_passthrough_and_requires_expose() { + let cli = Cli::try_parse_from([ + "openshell", + "sandbox", + "create", + "--expose", + "4500", + "--expose-authorization-mode", + "bearer-passthrough", + ]) + .expect("create-time authorization mode should parse with --expose"); + match cli.command { + Some(Commands::Sandbox { + command: + Some(SandboxCommands::Create { + expose_authorization_mode, + .. + }), + }) => assert_eq!( + expose_authorization_mode, + CliServiceAuthorizationMode::BearerPassthrough + ), + other => panic!("expected SandboxCommands::Create, got: {other:?}"), + } + + assert!( + Cli::try_parse_from([ + "openshell", + "sandbox", + "create", + "--expose-authorization-mode", + "bearer-passthrough", + ]) + .is_err() + ); + } + #[test] fn service_expose_accepts_positional_target_port_and_service() { let cli = Cli::try_parse_from([ @@ -6675,11 +6751,13 @@ mod tests { sandbox, target_port, service, + authorization_mode, }), }) => { assert_eq!(sandbox, "my-sandbox"); assert_eq!(target_port, 8080); assert_eq!(service.as_deref(), Some("api")); + assert_eq!(authorization_mode, CliServiceAuthorizationMode::Strip); } other => panic!("expected service expose command, got: {other:?}"), } @@ -6697,16 +6775,45 @@ mod tests { sandbox, target_port, service, + authorization_mode, }), }) => { assert_eq!(sandbox, "my-sandbox"); assert_eq!(target_port, 8080); assert_eq!(service, None); + assert_eq!(authorization_mode, CliServiceAuthorizationMode::Strip); } other => panic!("expected service expose command, got: {other:?}"), } } + #[test] + fn service_expose_parses_bearer_passthrough() { + let cli = Cli::try_parse_from([ + "openshell", + "service", + "expose", + "my-sandbox", + "4500", + "--authorization-mode", + "bearer-passthrough", + ]) + .expect("service authorization mode should parse"); + + match cli.command { + Some(Commands::Service { + command: + Some(ServiceCommands::Expose { + authorization_mode, .. + }), + }) => assert_eq!( + authorization_mode, + CliServiceAuthorizationMode::BearerPassthrough + ), + other => panic!("expected service expose command, got: {other:?}"), + } + } + #[test] fn service_alias_parses_service_commands() { let cli = Cli::try_parse_from(["openshell", "svc", "expose", "my-sandbox", "8080"]) @@ -6719,6 +6826,7 @@ mod tests { sandbox, target_port, service, + .. }), }) => { assert_eq!(sandbox, "my-sandbox"); diff --git a/crates/openshell-cli/src/run.rs b/crates/openshell-cli/src/run.rs index ce63bc9f7b..02c806c421 100644 --- a/crates/openshell-cli/src/run.rs +++ b/crates/openshell-cli/src/run.rs @@ -58,9 +58,9 @@ use openshell_core::proto::{ RevokeSshSessionRequest, Sandbox, SandboxCondition, SandboxPhase, SandboxPolicy, SandboxResources, SandboxRestartPolicy, SandboxServiceExposure, SandboxServiceLevel, SandboxSpec, SandboxStartup, SandboxTemplate, SandboxWorkloadConfig, SandboxWorkloadTemplate, - SandboxWorkloadTemplateSpec, ServiceEndpointResponse, SettingScope, StartSandboxRequest, - StopSandboxRequest, TcpForwardFrame, TcpForwardInit, TcpRelayTarget, UpdateConfigRequest, - WatchSandboxRequest, exec_sandbox_event, tcp_forward_init, + SandboxWorkloadTemplateSpec, ServiceAuthorizationMode, ServiceEndpointResponse, SettingScope, + StartSandboxRequest, StopSandboxRequest, TcpForwardFrame, TcpForwardInit, TcpRelayTarget, + UpdateConfigRequest, WatchSandboxRequest, exec_sandbox_event, tcp_forward_init, }; use openshell_core::settings; use openshell_core::{ObjectId, ObjectName, ObjectWorkspace}; @@ -443,6 +443,7 @@ pub struct SandboxCreateConfig<'a> { pub policy: Option<&'a str>, pub forward: Option, pub expose: Option, + pub expose_authorization_mode: ServiceAuthorizationMode, pub command: &'a [String], pub tty_override: Option, pub auto_providers_override: Option, @@ -472,6 +473,7 @@ impl Default for SandboxCreateConfig<'_> { policy: None, forward: None, expose: None, + expose_authorization_mode: ServiceAuthorizationMode::Strip, command: &[], tty_override: None, auto_providers_override: None, @@ -509,6 +511,7 @@ pub async fn sandbox_create( policy, forward, expose, + expose_authorization_mode, command, tty_override, auto_providers_override, @@ -693,6 +696,7 @@ pub async fn sandbox_create( .map(|target_port| SandboxServiceExposure { service: String::new(), target_port: u32::from(target_port), + authorization_mode: expose_authorization_mode as i32, }) .into_iter() .collect(), @@ -3823,11 +3827,20 @@ pub async fn service_expose( sandbox: &str, service: &str, target_port: u16, + authorization_mode: ServiceAuthorizationMode, workspace: &str, tls: &TlsOptions, ) -> Result<()> { - let response = - expose_service_endpoint(server, sandbox, service, target_port, workspace, tls).await?; + let response = expose_service_endpoint( + server, + sandbox, + service, + target_port, + authorization_mode, + workspace, + tls, + ) + .await?; if service.is_empty() { println!( @@ -3857,6 +3870,7 @@ async fn expose_service_endpoint( sandbox: &str, service: &str, target_port: u16, + authorization_mode: ServiceAuthorizationMode, workspace: &str, tls: &TlsOptions, ) -> Result { @@ -3868,6 +3882,7 @@ async fn expose_service_endpoint( name: service.to_string(), target_port: u32::from(target_port), domain: true, + authorization_mode: authorization_mode as i32, workspace_scope: Some(openshell_core::proto::workspace_selector( workspace.to_string(), )), @@ -4040,6 +4055,7 @@ fn print_service_endpoint_table( .map_or("", |m| m.workspace.as_str()); let service = service_display_name(&endpoint.name).to_string(); let target = format!("127.0.0.1:{}", endpoint.target_port); + let authorization = service_authorization_mode_name(endpoint.authorization_mode); let url = if response.url.is_empty() { String::new() } else { @@ -4050,6 +4066,7 @@ fn print_service_endpoint_table( endpoint.sandbox.clone(), service, target, + authorization, url, )) }) @@ -4061,7 +4078,7 @@ fn print_service_endpoint_table( let ws_width = if all_workspaces { rows.iter() - .map(|(ws, _, _, _, _)| ws.len()) + .map(|(ws, _, _, _, _, _)| ws.len()) .max() .unwrap_or(9) .max(9) @@ -4070,50 +4087,52 @@ fn print_service_endpoint_table( }; let sandbox_width = rows .iter() - .map(|(_, sandbox, _, _, _)| sandbox.len()) + .map(|(_, sandbox, _, _, _, _)| sandbox.len()) .max() .unwrap_or(7) .max(7); let service_width = rows .iter() - .map(|(_, _, service, _, _)| service.len()) + .map(|(_, _, service, _, _, _)| service.len()) .max() .unwrap_or(7) .max(7); let target_width = rows .iter() - .map(|(_, _, _, target, _)| target.len()) + .map(|(_, _, _, target, _, _)| target.len()) .max() .unwrap_or(6) .max(6); if all_workspaces { println!( - "{: &str { if service.is_empty() { "-" } else { service } } +fn service_authorization_mode_name(mode: i32) -> &'static str { + match ServiceAuthorizationMode::try_from(mode).unwrap_or(ServiceAuthorizationMode::Strip) { + ServiceAuthorizationMode::BearerPassthrough => "bearer_passthrough", + ServiceAuthorizationMode::Unspecified | ServiceAuthorizationMode::Strip => "strip", + } +} + /// Read gcloud Application Default Credentials from disk. /// /// Returns `(client_id, client_secret, refresh_token)`. @@ -6521,8 +6548,9 @@ mod tests { PolicySource, PolicyStatus, ResourceRequirements, Sandbox, SandboxCondition, SandboxPhase, SandboxPolicy, SandboxPolicyRevision, SandboxResources, SandboxRestartPolicy, SandboxSpec, SandboxStatus, SandboxWorkloadConfig, SandboxWorkloadTemplate, - SandboxWorkloadTemplateProvenance, SandboxWorkloadTemplateSpec, ServiceEndpoint, - ServiceEndpointResponse, WorkspaceMember, WorkspaceRole, datamodel::v1::ObjectMeta, + SandboxWorkloadTemplateProvenance, SandboxWorkloadTemplateSpec, ServiceAuthorizationMode, + ServiceEndpoint, ServiceEndpointResponse, WorkspaceMember, WorkspaceRole, + datamodel::v1::ObjectMeta, }; #[test] @@ -6639,6 +6667,7 @@ mod tests { sandbox: "api".to_string(), name: String::new(), target_port: 8080, + authorization_mode: ServiceAuthorizationMode::BearerPassthrough as i32, ..Default::default() }), url: "https://api.openshell.localhost:3000/".to_string(), @@ -6653,6 +6682,7 @@ mod tests { "sandbox": "api", "service": "", "target_port": 8080, + "authorization_mode": "bearer_passthrough", "url": "https://api.openshell.localhost:17670/", }) ); diff --git a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs index 0b638d5694..964559a8ad 100644 --- a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs +++ b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs @@ -2784,6 +2784,8 @@ async fn sandbox_create_exposes_service_after_ready_and_keeps_sandbox() { name: Some("sandbox"), keep: false, expose: Some(4500), + expose_authorization_mode: + openshell_core::proto::ServiceAuthorizationMode::BearerPassthrough, detach: true, ..test_config() }, @@ -2799,9 +2801,38 @@ async fn sandbox_create_exposes_service_after_ready_and_keeps_sandbox() { assert_eq!(create_requests[0].service_exposures.len(), 1); assert_eq!(create_requests[0].service_exposures[0].service, ""); assert_eq!(create_requests[0].service_exposures[0].target_port, 4500); + assert_eq!( + create_requests[0].service_exposures[0].authorization_mode(), + openshell_core::proto::ServiceAuthorizationMode::BearerPassthrough + ); assert!(expose_service_requests(&server).await.is_empty()); } +#[tokio::test] +async fn service_expose_forwards_bearer_passthrough_mode() { + let server = run_server().await; + let tls = test_tls(&server); + + run::service_expose( + &server.endpoint, + "sandbox", + "codex", + 4500, + openshell_core::proto::ServiceAuthorizationMode::BearerPassthrough, + "default", + &tls, + ) + .await + .expect("service expose should succeed"); + + let requests = expose_service_requests(&server).await; + assert_eq!(requests.len(), 1); + assert_eq!( + requests[0].authorization_mode(), + openshell_core::proto::ServiceAuthorizationMode::BearerPassthrough + ); +} + #[tokio::test] async fn sandbox_forward_background_tracks_owned_child_when_pid_discovery_fails() { let server = run_server().await; diff --git a/crates/openshell-sdk/README.md b/crates/openshell-sdk/README.md index 4f721cbece..68c95e0c5b 100644 --- a/crates/openshell-sdk/README.md +++ b/crates/openshell-sdk/README.md @@ -56,8 +56,10 @@ portable workload shape and driver config. Failures map to a typed `SdkError` with a discriminable kind. Set `SandboxSpec::service_exposures` to register named or unnamed loopback HTTP -services during creation. Each `ServiceExposure` contains a service name and a -target port; an empty name selects the unnamed endpoint. The returned +services during creation. Each `ServiceExposure` contains a service name, a +target port, and an authorization mode; an empty name selects the unnamed +endpoint. Authorization is stripped by default. Select `BearerPassthrough` only +when the sandbox application validates its own bearer credential. The returned `SandboxRef::service_urls` map contains each routed URL under the same name. Curated calls without a workspace argument explicitly select the `default` diff --git a/crates/openshell-sdk/src/client.rs b/crates/openshell-sdk/src/client.rs index 081ce94f89..69b75ffbd2 100644 --- a/crates/openshell-sdk/src/client.rs +++ b/crates/openshell-sdk/src/client.rs @@ -1359,6 +1359,9 @@ fn create_sandbox_request(spec: SandboxSpec) -> proto::CreateSandboxRequest { .map(|exposure| proto::SandboxServiceExposure { service: exposure.service, target_port: u32::from(exposure.target_port), + authorization_mode: proto::ServiceAuthorizationMode::from( + exposure.authorization_mode, + ) as i32, }) .collect(), } @@ -1397,6 +1400,9 @@ fn create_sandbox_from_template_request( .map(|exposure| proto::SandboxServiceExposure { service: exposure.service, target_port: u32::from(exposure.target_port), + authorization_mode: proto::ServiceAuthorizationMode::from( + exposure.authorization_mode, + ) as i32, }) .collect(), } diff --git a/crates/openshell-sdk/src/lib.rs b/crates/openshell-sdk/src/lib.rs index 2d79b28cc6..5459fa7532 100644 --- a/crates/openshell-sdk/src/lib.rs +++ b/crates/openshell-sdk/src/lib.rs @@ -54,6 +54,6 @@ pub use types::{ LogLine, PlatformEvent, SandboxPhase, SandboxRef, SandboxResources, SandboxRestartPolicy, SandboxServiceLevel, SandboxSpec, SandboxStartup, SandboxTemplateCreateSpec, SandboxTemplateListOptions, SandboxWorkloadConfig, SandboxWorkloadTemplate, - SandboxWorkloadTemplateProvenance, SandboxWorkloadTemplateSpec, ServiceExposure, ServiceStatus, - WatchEvent, WatchOptions, WorkspaceRef, + SandboxWorkloadTemplateProvenance, SandboxWorkloadTemplateSpec, ServiceAuthorizationMode, + ServiceExposure, ServiceStatus, WatchEvent, WatchOptions, WorkspaceRef, }; diff --git a/crates/openshell-sdk/src/types.rs b/crates/openshell-sdk/src/types.rs index b7297a3fee..aa2bc71bf9 100644 --- a/crates/openshell-sdk/src/types.rs +++ b/crates/openshell-sdk/src/types.rs @@ -296,6 +296,27 @@ pub struct ServiceExposure { pub service: String, /// Loopback TCP port inside the sandbox. pub target_port: u16, + /// Whether the gateway strips or forwards an application bearer credential. + pub authorization_mode: ServiceAuthorizationMode, +} + +/// Handling for an incoming application `Authorization` header. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub enum ServiceAuthorizationMode { + /// Remove the header before proxying to the sandbox service. + #[default] + Strip, + /// Forward one syntactically valid bearer credential unchanged. + BearerPassthrough, +} + +impl From for proto::ServiceAuthorizationMode { + fn from(value: ServiceAuthorizationMode) -> Self { + match value { + ServiceAuthorizationMode::Strip => Self::Strip, + ServiceAuthorizationMode::BearerPassthrough => Self::BearerPassthrough, + } + } } /// Caller intent for creating a sandbox from a named workload template. diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index 1c86ada7dd..9506160f07 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -13,8 +13,8 @@ use openshell_core::proto::open_shell_server::{OpenShell, OpenShellServer}; use openshell_sdk::{ AuthConfig, ClientConfig, ExecOptions, ListOptions, OpenShellClient, Refresh, RefreshError, RefreshedToken, SandboxPhase, SandboxSpec, SandboxTemplateCreateSpec, - SandboxTemplateListOptions, ServiceExposure, ServiceStatus as SdkServiceStatus, WatchEvent, - WatchOptions, + SandboxTemplateListOptions, ServiceAuthorizationMode, ServiceExposure, + ServiceStatus as SdkServiceStatus, WatchEvent, WatchOptions, }; use std::collections::HashMap; use std::sync::Arc; @@ -1139,6 +1139,7 @@ async fn create_sandbox_passes_spec_through() { service_exposures: vec![ServiceExposure { service: "web".to_string(), target_port: 8080, + authorization_mode: ServiceAuthorizationMode::BearerPassthrough, }], ..Default::default() }; @@ -1158,6 +1159,10 @@ async fn create_sandbox_passes_spec_through() { assert_eq!(observed.service_exposures.len(), 1); assert_eq!(observed.service_exposures[0].service, "web"); assert_eq!(observed.service_exposures[0].target_port, 8080); + assert_eq!( + observed.service_exposures[0].authorization_mode(), + proto::ServiceAuthorizationMode::BearerPassthrough + ); let observed_spec = observed.spec.unwrap(); assert!( observed_spec diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index da0ebffef0..d2e9642263 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -25,6 +25,8 @@ use hyper_util::rt::TokioIo; use openshell_core::extension_protocol::{ ExtensionFamily, NegotiatedExtension, gateway_metadata, negotiate, }; +#[cfg(test)] +use openshell_core::proto::ServiceAuthorizationMode; use openshell_core::proto::compute::v1::{ AuthenticateSandboxRequest, CreateSandboxRequest, DeleteSandboxRequest, DeleteWorkspaceRequest, DeleteWorkspaceResponse, DriverCondition, DriverPlatformEvent, DriverResourceRequirements, @@ -9509,6 +9511,7 @@ mod tests { name: "web".to_string(), target_port: 8080, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, } } diff --git a/crates/openshell-server/src/grpc/mutation_replay/tests.rs b/crates/openshell-server/src/grpc/mutation_replay/tests.rs index 28dfc688f2..7b784213b6 100644 --- a/crates/openshell-server/src/grpc/mutation_replay/tests.rs +++ b/crates/openshell-server/src/grpc/mutation_replay/tests.rs @@ -7,7 +7,8 @@ use openshell_core::proto::datamodel::v1::ObjectMeta; use openshell_core::proto::open_shell_server::OpenShell; use openshell_core::proto::{ CreateSandboxRequest, SandboxServiceExposure, SandboxSpec, SandboxWorkloadConfig, - SandboxWorkloadTemplate, SandboxWorkloadTemplateSpec, WorkspaceMember, WorkspaceRole, + SandboxWorkloadTemplate, SandboxWorkloadTemplateSpec, ServiceAuthorizationMode, + WorkspaceMember, WorkspaceRole, }; use openshell_core::rpc_error::StatusExt; use std::collections::HashMap; @@ -113,6 +114,7 @@ async fn create_sandbox_replay_preserves_service_urls() { service_exposures: vec![SandboxServiceExposure { service: "web".into(), target_port: 8080, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }], request_id: uuid::Uuid::new_v4().to_string(), ..Default::default() @@ -124,13 +126,26 @@ async fn create_sandbox_replay_preserves_service_urls() { .unwrap() .into_inner(); let replay = service - .create_sandbox(authed_request(request)) + .create_sandbox(authed_request(request.clone())) .await .unwrap(); assert_eq!(replay.metadata().get("openshell-replayed").unwrap(), "true"); assert_eq!(replay.get_ref().service_urls, original.service_urls); assert_eq!(replay.into_inner(), original); + + let mut changed_authorization = request; + changed_authorization.service_exposures[0].authorization_mode = + ServiceAuthorizationMode::BearerPassthrough as i32; + assert_eq!( + reason( + &service + .create_sandbox(authed_request(changed_authorization)) + .await + .unwrap_err() + ), + "REQUEST_ID_PAYLOAD_MISMATCH" + ); } async fn exercise_backend(url: &str) { diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index 8e3aa58372..074b2590e0 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -680,6 +680,11 @@ async fn handle_create_sandbox_inner( &sandbox, &exposure.service, exposure.target_port, + super::service::validate_service_exposure_request( + &exposure.service, + exposure.target_port, + exposure.authorization_mode, + )?, ) .await { @@ -741,7 +746,11 @@ fn validate_create_sandbox_request_pre_io( } let mut service_names = HashSet::with_capacity(request.service_exposures.len()); for exposure in &request.service_exposures { - super::service::validate_service_exposure_request(&exposure.service, exposure.target_port)?; + super::service::validate_service_exposure_request( + &exposure.service, + exposure.target_port, + exposure.authorization_mode, + )?; if !service_names.insert(exposure.service.as_str()) { return Err(Status::invalid_argument(format!( "duplicate service exposure name: '{}'", @@ -3924,7 +3933,9 @@ mod tests { test_server_state_with_driver, }; use openshell_core::proto::datamodel::v1::ObjectMeta; - use openshell_core::proto::{GpuResourceRequirements, SandboxServiceExposure, ServiceEndpoint}; + use openshell_core::proto::{ + GpuResourceRequirements, SandboxServiceExposure, ServiceAuthorizationMode, ServiceEndpoint, + }; // ---- shell_escape ---- @@ -6720,10 +6731,12 @@ mod tests { SandboxServiceExposure { service: String::new(), target_port: 4500, + authorization_mode: ServiceAuthorizationMode::Unspecified as i32, }, SandboxServiceExposure { service: "metrics".to_string(), target_port: 9090, + authorization_mode: ServiceAuthorizationMode::BearerPassthrough as i32, }, ], ..Default::default() @@ -6756,9 +6769,46 @@ mod tests { assert_eq!(endpoint.name, service); assert_eq!(endpoint.target_port, target_port); assert!(endpoint.domain); + let expected_mode = if service.is_empty() { + ServiceAuthorizationMode::Strip + } else { + ServiceAuthorizationMode::BearerPassthrough + }; + assert_eq!(endpoint.authorization_mode(), expected_mode); } } + #[tokio::test] + async fn create_sandbox_rejects_unknown_service_authorization_mode_before_persisting() { + let state = test_server_state().await; + let error = handle_create_sandbox( + &state, + authed_request(CreateSandboxRequest { + name: "invalid-service-authorization".to_string(), + spec: Some(SandboxSpec::default()), + workspace_scope: Some(openshell_core::proto::workspace_selector("default")), + service_exposures: vec![SandboxServiceExposure { + service: String::new(), + target_port: 4500, + authorization_mode: 99, + }], + ..Default::default() + }), + ) + .await + .expect_err("unknown service authorization mode should be rejected"); + + assert_eq!(error.code(), tonic::Code::InvalidArgument); + assert!( + state + .store + .get_message_by_name::("default", "invalid-service-authorization") + .await + .expect("sandbox lookup should succeed") + .is_none() + ); + } + #[tokio::test] async fn create_sandbox_begins_rollback_when_service_exposure_fails() { let state = test_server_state().await; @@ -6788,10 +6838,12 @@ mod tests { SandboxServiceExposure { service: "web".to_string(), target_port: 8080, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }, SandboxServiceExposure { service: "metrics".to_string(), target_port: 9090, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }, ], ..Default::default() @@ -6875,10 +6927,12 @@ mod tests { SandboxServiceExposure { service: "web".to_string(), target_port: 8080, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }, SandboxServiceExposure { service: "web".to_string(), target_port: 8081, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }, ], ..Default::default() diff --git a/crates/openshell-server/src/grpc/service.rs b/crates/openshell-server/src/grpc/service.rs index 675b695656..bb44f395b8 100644 --- a/crates/openshell-server/src/grpc/service.rs +++ b/crates/openshell-server/src/grpc/service.rs @@ -7,7 +7,8 @@ use std::sync::Arc; use openshell_core::proto::datamodel::v1::ObjectMeta; use openshell_core::proto::{ DeleteServiceRequest, DeleteServiceResponse, ExposeServiceRequest, GetServiceRequest, - ListServicesRequest, ListServicesResponse, Sandbox, ServiceEndpoint, ServiceEndpointResponse, + ListServicesRequest, ListServicesResponse, Sandbox, ServiceAuthorizationMode, ServiceEndpoint, + ServiceEndpointResponse, }; use openshell_core::{GetResourceVersion, ObjectId, ObjectName, ObjectWorkspace}; use prost::Message as _; @@ -49,19 +50,37 @@ pub(super) async fn handle_expose_service( super::workspace::resolve_workspace(state.store.as_ref(), sandbox.object_workspace()) .await? .ensure_active()?; - validate_service_exposure_request(&req.name, req.target_port)?; - expose_service_endpoint(state, &workspace, &sandbox, &req.name, req.target_port).await + let authorization_mode = + validate_service_exposure_request(&req.name, req.target_port, req.authorization_mode)?; + expose_service_endpoint( + state, + &workspace, + &sandbox, + &req.name, + req.target_port, + authorization_mode, + ) + .await } pub(super) fn validate_service_exposure_request( service: &str, target_port: u32, -) -> Result<(), Status> { + authorization_mode: i32, +) -> Result { validate_optional_endpoint_name("service", service, MAX_SERVICE_NAME_LEN)?; if target_port == 0 || target_port > u32::from(u16::MAX) { return Err(Status::invalid_argument("target_port must be in 1..=65535")); } - Ok(()) + match ServiceAuthorizationMode::try_from(authorization_mode) { + Ok(ServiceAuthorizationMode::Unspecified | ServiceAuthorizationMode::Strip) => { + Ok(ServiceAuthorizationMode::Strip) + } + Ok(ServiceAuthorizationMode::BearerPassthrough) => { + Ok(ServiceAuthorizationMode::BearerPassthrough) + } + Err(_) => Err(Status::invalid_argument("authorization_mode is invalid")), + } } pub(super) async fn expose_service_endpoint( @@ -70,6 +89,7 @@ pub(super) async fn expose_service_endpoint( sandbox: &Sandbox, service: &str, target_port: u32, + authorization_mode: ServiceAuthorizationMode, ) -> Result, Status> { let sandbox_name = sandbox.object_name(); @@ -132,6 +152,7 @@ pub(super) async fn expose_service_endpoint( name: service.to_string(), target_port, domain: true, + authorization_mode: authorization_mode as i32, }; // Single-attempt CAS write: fails with ABORTED on concurrent modification @@ -344,8 +365,16 @@ async fn get_service_endpoint( fn service_endpoint_response( state: &Arc, - endpoint: ServiceEndpoint, + mut endpoint: ServiceEndpoint, ) -> ServiceEndpointResponse { + endpoint.authorization_mode = + match ServiceAuthorizationMode::try_from(endpoint.authorization_mode) { + Ok(ServiceAuthorizationMode::BearerPassthrough) => { + ServiceAuthorizationMode::BearerPassthrough as i32 + } + Ok(ServiceAuthorizationMode::Unspecified | ServiceAuthorizationMode::Strip) + | Err(_) => ServiceAuthorizationMode::Strip as i32, + }; let workspace = endpoint.object_workspace(); let url = service_routing::endpoint_url(&state.config, workspace, &endpoint.sandbox, &endpoint.name) @@ -456,6 +485,100 @@ mod tests { assert!(validate_endpoint_name("service", "Web", 28).is_err()); } + #[test] + fn authorization_mode_defaults_to_strip_and_rejects_unknown_values() { + assert_eq!( + validate_service_exposure_request("web", 8080, 0).unwrap(), + ServiceAuthorizationMode::Strip + ); + assert_eq!( + validate_service_exposure_request( + "web", + 8080, + ServiceAuthorizationMode::BearerPassthrough as i32, + ) + .unwrap(), + ServiceAuthorizationMode::BearerPassthrough + ); + assert_eq!( + validate_service_exposure_request("web", 8080, 99) + .unwrap_err() + .code(), + tonic::Code::InvalidArgument + ); + } + + #[tokio::test] + async fn unknown_authorization_mode_is_rejected_before_persistence() { + let state = test_server_state().await; + seed_sandbox(&state, "my-sandbox").await; + + let error = handle_expose_service( + &state, + authed_request(ExposeServiceRequest { + sandbox: "my-sandbox".to_string(), + workspace_scope: Some(openshell_core::proto::workspace_selector("default")), + name: "web".to_string(), + target_port: 8080, + authorization_mode: 99, + ..Default::default() + }), + ) + .await + .unwrap_err(); + + assert_eq!(error.code(), tonic::Code::InvalidArgument); + assert!( + get_service_endpoint(&state, "default", "my-sandbox", "web") + .await + .unwrap() + .is_none() + ); + } + + #[tokio::test] + async fn legacy_unspecified_authorization_mode_is_reported_as_strip() { + let state = test_server_state().await; + seed_sandbox(&state, "my-sandbox").await; + + handle_expose_service( + &state, + authed_request(ExposeServiceRequest { + sandbox: "my-sandbox".to_string(), + workspace_scope: Some(openshell_core::proto::workspace_selector("default")), + name: "web".to_string(), + target_port: 8080, + ..Default::default() + }), + ) + .await + .unwrap(); + + let mut stored = get_service_endpoint(&state, "default", "my-sandbox", "web") + .await + .unwrap() + .unwrap(); + stored.authorization_mode = ServiceAuthorizationMode::Unspecified as i32; + state.store.put_message(&stored).await.unwrap(); + + let response = handle_get_service( + &state, + authed_request(GetServiceRequest { + sandbox: "my-sandbox".to_string(), + workspace_scope: Some(openshell_core::proto::workspace_selector("default")), + name: "web".to_string(), + }), + ) + .await + .unwrap() + .into_inner(); + + assert_eq!( + response.endpoint.unwrap().authorization_mode(), + ServiceAuthorizationMode::Strip + ); + } + #[tokio::test] async fn endpoint_lifecycle_round_trip() { let state = test_server_state().await; @@ -472,12 +595,17 @@ mod tests { name: "web".to_string(), target_port: 8080, domain: true, + authorization_mode: ServiceAuthorizationMode::Unspecified as i32, }), ) .await .unwrap() .into_inner(); assert_eq!(exposed.endpoint.as_ref().unwrap().target_port, 8080); + assert_eq!( + exposed.endpoint.as_ref().unwrap().authorization_mode(), + ServiceAuthorizationMode::Strip + ); let listed = handle_list_services( &state, @@ -511,6 +639,26 @@ mod tests { .into_inner(); assert_eq!(fetched.endpoint.as_ref().unwrap().target_port, 8080); + let updated = handle_expose_service( + &state, + authed_request(ExposeServiceRequest { + sandbox: "my-sandbox".to_string(), + workspace_scope: Some(openshell_core::proto::workspace_selector("default")), + name: "web".to_string(), + target_port: 9090, + authorization_mode: ServiceAuthorizationMode::BearerPassthrough as i32, + ..Default::default() + }), + ) + .await + .unwrap() + .into_inner(); + assert_eq!(updated.endpoint.as_ref().unwrap().target_port, 9090); + assert_eq!( + updated.endpoint.as_ref().unwrap().authorization_mode(), + ServiceAuthorizationMode::BearerPassthrough + ); + let deleted = handle_delete_service( &state, authed_request(DeleteServiceRequest { @@ -643,6 +791,7 @@ mod tests { name: "web".to_string(), target_port: 8080, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }), ) .await @@ -661,6 +810,7 @@ mod tests { name: "web".to_string(), target_port: 9090, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }), ) .await @@ -713,6 +863,7 @@ mod tests { name: "web".to_string(), target_port: 7070, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }), ) .await @@ -732,6 +883,7 @@ mod tests { name: "web".to_string(), target_port: 8080, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }), ) .await @@ -750,6 +902,7 @@ mod tests { name: "web".to_string(), target_port: 9090, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }), ) .await @@ -840,6 +993,7 @@ mod tests { name: "web".to_string(), target_port: 8080, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }), ) .await @@ -856,6 +1010,7 @@ mod tests { name: "web".to_string(), target_port: 9090, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }), ) .await @@ -999,6 +1154,7 @@ mod tests { name: "api".to_string(), target_port: 3000, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }), ) .await diff --git a/crates/openshell-server/src/service_routing.rs b/crates/openshell-server/src/service_routing.rs index 247363a05f..c139d282ab 100644 --- a/crates/openshell-server/src/service_routing.rs +++ b/crates/openshell-server/src/service_routing.rs @@ -11,7 +11,9 @@ use http::{HeaderMap, HeaderValue, Method, Request, Response, StatusCode, header use hyper_util::rt::TokioIo; use openshell_core::ObjectId; use openshell_core::config::ServiceRoutingConfig; -use openshell_core::proto::{Sandbox, SandboxPhase, ServiceEndpoint, TcpRelayTarget, relay_open}; +use openshell_core::proto::{ + Sandbox, SandboxPhase, ServiceAuthorizationMode, ServiceEndpoint, TcpRelayTarget, relay_open, +}; use openshell_ocsf::{ ActionId, ActivityId, ConfigStateChangeBuilder, DispositionId, Endpoint, EventContext, HttpActivityBuilder, HttpRequest, HttpResponse as OcsfHttpResponse, NetworkActivityBuilder, @@ -428,6 +430,19 @@ async fn proxy_to_endpoint( ); return Err(err); } + let authorization_mode = effective_authorization_mode(endpoint.authorization_mode); + if validate_application_authorization(&req, authorization_mode).is_err() { + let err = ServiceRouteError::invalid_request(); + emit_service_http_failure( + &state, + &req, + &sandbox_name, + &service_name, + Some(&endpoint), + &err, + ); + return Err(err); + } let websocket_upgrade = is_websocket_upgrade(&req); let downstream_upgrade = websocket_upgrade.then(|| hyper::upgrade::on(&mut req)); @@ -446,7 +461,7 @@ async fn proxy_to_endpoint( None => open_upstream(&state, &sandbox, &endpoint, target_port, websocket_upgrade).await?, }; - let upstream = build_upstream_request(req, target_port, websocket_upgrade)?; + let upstream = build_upstream_request(req, target_port, websocket_upgrade, authorization_mode)?; let replay = reused.then(|| replayable_request(&upstream)).flatten(); let first_attempt = if reused { sender.try_send_request(upstream).await.map_err(|mut err| { @@ -626,6 +641,7 @@ fn build_upstream_request( req: Request, target_port: u16, preserve_upgrade_headers: bool, + authorization_mode: ServiceAuthorizationMode, ) -> Result, ServiceRouteError> { let (parts, body) = req.into_parts(); let path = parts.uri.path_and_query().map_or("/", |path| path.as_str()); @@ -644,7 +660,7 @@ fn build_upstream_request( for (name, value) in &parts.headers { if (is_hop_by_hop_header(name) && !(preserve_upgrade_headers && is_websocket_hop_by_hop_header(name))) - || is_gateway_auth_header(name) + || is_gateway_auth_header(name, authorization_mode) { continue; } @@ -724,15 +740,83 @@ fn is_websocket_hop_by_hop_header(name: &header::HeaderName) -> bool { matches!(name.as_str(), "connection" | "upgrade") } -fn is_gateway_auth_header(name: &header::HeaderName) -> bool { - matches!( - name.as_str(), - "authorization" - | "cf-access-jwt-assertion" - | "x-forwarded-client-cert" - | "x-ssl-client-cert" - | "x-client-cert" - ) +pub fn effective_authorization_mode(value: i32) -> ServiceAuthorizationMode { + match ServiceAuthorizationMode::try_from(value) { + Ok(ServiceAuthorizationMode::BearerPassthrough) => { + ServiceAuthorizationMode::BearerPassthrough + } + Ok(ServiceAuthorizationMode::Unspecified | ServiceAuthorizationMode::Strip) | Err(_) => { + ServiceAuthorizationMode::Strip + } + } +} + +fn authorization_mode_label(value: i32) -> &'static str { + match effective_authorization_mode(value) { + ServiceAuthorizationMode::BearerPassthrough => "bearer_passthrough", + ServiceAuthorizationMode::Unspecified | ServiceAuthorizationMode::Strip => "strip", + } +} + +fn validate_application_authorization( + req: &Request, + authorization_mode: ServiceAuthorizationMode, +) -> Result<(), ServiceRouteError> { + if authorization_mode != ServiceAuthorizationMode::BearerPassthrough { + return Ok(()); + } + + let mut values = req.headers().get_all(header::AUTHORIZATION).iter(); + let Some(value) = values.next() else { + return Ok(()); + }; + if values.next().is_some() { + return Err(ServiceRouteError::invalid_request()); + } + + let value = value + .to_str() + .map_err(|_| ServiceRouteError::invalid_request())?; + let Some((scheme, credential)) = value.split_once(' ') else { + return Err(ServiceRouteError::invalid_request()); + }; + let credential = credential.trim_start_matches(' '); + if !scheme.eq_ignore_ascii_case("bearer") || !is_bearer_token68(credential) { + return Err(ServiceRouteError::invalid_request()); + } + Ok(()) +} + +fn is_bearer_token68(value: &str) -> bool { + let mut saw_data = false; + let mut saw_padding = false; + for byte in value.bytes() { + if byte == b'=' { + saw_padding = true; + } else if !saw_padding + && (byte.is_ascii_alphanumeric() + || matches!(byte, b'-' | b'.' | b'_' | b'~' | b'+' | b'/')) + { + saw_data = true; + } else { + return false; + } + } + saw_data +} + +fn is_gateway_auth_header( + name: &header::HeaderName, + authorization_mode: ServiceAuthorizationMode, +) -> bool { + match name.as_str() { + "authorization" => authorization_mode != ServiceAuthorizationMode::BearerPassthrough, + "cf-access-jwt-assertion" + | "x-forwarded-client-cert" + | "x-ssl-client-cert" + | "x-client-cert" => true, + _ => false, + } } fn sanitize_cookie_header(value: &HeaderValue) -> Option { @@ -830,7 +914,11 @@ fn build_service_endpoint_config_event( )) .unmapped("endpoint_name", endpoint_name(endpoint)) .unmapped("service_name", endpoint.name.clone()) - .unmapped("target_port", u64::from(endpoint.target_port)); + .unmapped("target_port", u64::from(endpoint.target_port)) + .unmapped( + "authorization_mode", + authorization_mode_label(endpoint.authorization_mode), + ); if !url.is_empty() { builder = builder.unmapped("url", url.to_string()); @@ -849,6 +937,10 @@ fn build_service_endpoint_delete_event(endpoint: &ServiceEndpoint) -> OcsfEvent .unmapped("endpoint_name", endpoint_name(endpoint)) .unmapped("service_name", endpoint.name.clone()) .unmapped("target_port", u64::from(endpoint.target_port)) + .unmapped( + "authorization_mode", + authorization_mode_label(endpoint.authorization_mode), + ) .build() } @@ -990,6 +1082,7 @@ mod tests { name: "web".to_string(), target_port: 8080, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, } } @@ -1233,6 +1326,7 @@ mod tests { assert_eq!(json["unmapped"]["endpoint_name"], "my-sandbox--web"); assert_eq!(json["unmapped"]["service_name"], "web"); assert_eq!(json["unmapped"]["target_port"], 8080); + assert_eq!(json["unmapped"]["authorization_mode"], "strip"); assert!( event .format_shorthand() @@ -1249,6 +1343,7 @@ mod tests { assert_eq!(json["unmapped"]["endpoint_name"], "my-sandbox--web"); assert_eq!(json["unmapped"]["service_name"], "web"); assert_eq!(json["unmapped"]["target_port"], 8080); + assert_eq!(json["unmapped"]["authorization_mode"], "strip"); assert!( event .format_shorthand() @@ -1309,7 +1404,8 @@ mod tests { .body(Body::empty()) .unwrap(); - let upstream = build_upstream_request(request, 8080, false).unwrap(); + let upstream = + build_upstream_request(request, 8080, false, ServiceAuthorizationMode::Strip).unwrap(); assert_eq!(upstream.uri(), "/path"); assert!(!upstream.headers().contains_key(header::AUTHORIZATION)); @@ -1322,6 +1418,145 @@ mod tests { assert_eq!(upstream.headers()["x-app-header"], "kept"); } + #[test] + fn unspecified_endpoint_authorization_mode_strips_authorization() { + let request = Request::builder() + .uri("/path") + .header(header::AUTHORIZATION, "Bearer application-token") + .body(Body::empty()) + .unwrap(); + + let mode = effective_authorization_mode(ServiceAuthorizationMode::Unspecified as i32); + validate_application_authorization(&request, mode).unwrap(); + let upstream = build_upstream_request(request, 8080, false, mode).unwrap(); + + assert_eq!(mode, ServiceAuthorizationMode::Strip); + assert!(!upstream.headers().contains_key(header::AUTHORIZATION)); + } + + #[test] + fn bearer_passthrough_preserves_valid_authorization_and_strips_gateway_identity() { + let request = Request::builder() + .uri("/path") + .header(header::AUTHORIZATION, "bEaReR application-token") + .header("cf-access-jwt-assertion", "edge-token") + .header("x-forwarded-client-cert", "cert") + .header(header::PROXY_AUTHORIZATION, "Basic proxy-secret") + .header( + header::COOKIE, + "theme=dark; CF_Authorization=edge-cookie; app=session", + ) + .body(Body::empty()) + .unwrap(); + + let mode = ServiceAuthorizationMode::BearerPassthrough; + validate_application_authorization(&request, mode).unwrap(); + let upstream = build_upstream_request(request, 8080, false, mode).unwrap(); + + assert_eq!( + upstream.headers()[header::AUTHORIZATION], + "bEaReR application-token" + ); + assert!(!upstream.headers().contains_key("cf-access-jwt-assertion")); + assert!(!upstream.headers().contains_key("x-forwarded-client-cert")); + assert!(!upstream.headers().contains_key(header::PROXY_AUTHORIZATION)); + assert_eq!( + upstream.headers()[header::COOKIE], + "theme=dark; app=session" + ); + } + + #[test] + fn bearer_passthrough_allows_missing_authorization() { + let request = Request::builder().uri("/path").body(Body::empty()).unwrap(); + + let mode = ServiceAuthorizationMode::BearerPassthrough; + validate_application_authorization(&request, mode).unwrap(); + let upstream = build_upstream_request(request, 8080, false, mode).unwrap(); + + assert!(!upstream.headers().contains_key(header::AUTHORIZATION)); + } + + #[test] + fn bearer_passthrough_rejects_ambiguous_or_malformed_authorization() { + for value in [ + "", + "Bearer", + "Bearer ", + "Basic abc", + "Bearer abc extra", + "Bearer abc,def", + "Bearer abc=def", + "Bearer\tabc", + " Bearer abc", + ] { + let request = Request::builder() + .uri("/path") + .header(header::AUTHORIZATION, value) + .body(Body::empty()) + .unwrap(); + assert!( + validate_application_authorization( + &request, + ServiceAuthorizationMode::BearerPassthrough, + ) + .is_err() + ); + } + + for value in ["Bearer abc", "bearer abc-._~+/==", "Bearer abc"] { + let request = Request::builder() + .uri("/path") + .header(header::AUTHORIZATION, value) + .body(Body::empty()) + .unwrap(); + validate_application_authorization( + &request, + ServiceAuthorizationMode::BearerPassthrough, + ) + .unwrap(); + } + + let mut request = Request::builder().uri("/path").body(Body::empty()).unwrap(); + request.headers_mut().append( + header::AUTHORIZATION, + HeaderValue::from_static("Bearer first"), + ); + request.headers_mut().append( + header::AUTHORIZATION, + HeaderValue::from_static("Bearer second"), + ); + assert!( + validate_application_authorization( + &request, + ServiceAuthorizationMode::BearerPassthrough, + ) + .is_err() + ); + } + + #[test] + fn authorization_value_is_not_in_service_routing_events() { + const SENTINEL: &str = "never-log-this-capability"; + let request = Request::builder() + .uri("/private") + .header(header::AUTHORIZATION, format!("Bearer {SENTINEL}")) + .body(Body::empty()) + .unwrap(); + let err = ServiceRouteError::invalid_request(); + let event = build_service_http_failure_event( + 18080, + &request, + "my-sandbox", + "web", + Some(&endpoint()), + &err, + ); + + assert!(!event.to_json().unwrap().to_string().contains(SENTINEL)); + assert!(!event.format_shorthand().contains(SENTINEL)); + } + #[test] fn detects_websocket_upgrade_request() { let request = Request::builder() @@ -1346,7 +1581,8 @@ mod tests { .body(Body::empty()) .unwrap(); - let upstream = build_upstream_request(request, 8080, true).unwrap(); + let upstream = + build_upstream_request(request, 8080, true, ServiceAuthorizationMode::Strip).unwrap(); assert_eq!(upstream.uri(), "/chat?session=main"); assert_eq!(upstream.headers()[header::CONNECTION], "Upgrade"); @@ -1355,6 +1591,30 @@ mod tests { assert_eq!(upstream.headers()[header::HOST], "127.0.0.1:8080"); } + #[test] + fn bearer_passthrough_preserves_authorization_on_websocket_upgrade() { + let request = Request::builder() + .method(Method::GET) + .uri("/chat") + .header(header::CONNECTION, "Upgrade") + .header(header::UPGRADE, "websocket") + .header("sec-websocket-key", "abc") + .header(header::AUTHORIZATION, "Bearer application-token") + .body(Body::empty()) + .unwrap(); + + let mode = ServiceAuthorizationMode::BearerPassthrough; + validate_application_authorization(&request, mode).unwrap(); + let upstream = build_upstream_request(request, 8080, true, mode).unwrap(); + + assert_eq!( + upstream.headers()[header::AUTHORIZATION], + "Bearer application-token" + ); + assert_eq!(upstream.headers()[header::CONNECTION], "Upgrade"); + assert_eq!(upstream.headers()[header::UPGRADE], "websocket"); + } + #[tokio::test] async fn load_endpoint_uses_workspace_for_lookup() { let store = crate::persistence::test_store().await; @@ -1375,6 +1635,7 @@ mod tests { name: "web".to_string(), target_port: 8080, domain: true, + authorization_mode: ServiceAuthorizationMode::Strip as i32, }; store.put_message(&ep).await.unwrap(); diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index 918ba14d9f..e6d8730aa0 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -126,15 +126,19 @@ mod tests { // inventories; the provider-environment file map is public-only. The // request has no provider-file capability field: older supervisors ignore // the additive file map while retaining the rest of the response. + // Service authorization also extends both schemas additively. Legacy + // payloads retain the safe Strip default. const PUBLIC_RPC_SCHEMA_SHA256: &str = - "2ed66dbc38c60eb96c7461c76d02813c177facfad93753b180534477270ad240"; + "2e156c6ad3c8eb51bcd30dc13b173fe339b38207a1b1f98f7be2e0cad8e3bd45"; const DURABLE_SCHEMA_SHA256: &str = - "399737f2a367d2e3a9d78cf84e2a97eef041835554599790788e4bbf318116c3"; + "38165d9d76f49fcfe98a12f241e032838a2376c1d1a87ea2796fd33b9b1a3541"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = - "d3c444ecdb42306af8a81791481fdfc147ddc54bf344e1c8e69bd06745c6cc3c"; + "761dea31a521b0650840fe2a823ad6e36a265ed323ba4506889781d630df0ee3"; // A persisted Sandbox without endpoint status retains its lifecycle fields; // the absent repeated field decodes empty and needs no database rewrite. const SANDBOX_WITHOUT_ENDPOINT_STATUS: &str = "0a1e0a0a73616e64626f782d6964120773616e64626f783a0764656661756c741a2b0a0773616e64626f782a0d0a05526561647912045472756530023807420d73757065727669736f722d6964"; + // ServiceEndpoint encoded before authorization_mode field 7 existed. + const SERVICE_ENDPOINT_WITHOUT_AUTHORIZATION_MODE: &str = "0a260a0b656e64706f696e742d6964120c73616e64626f782d2d77656228073a0764656661756c74120a73616e64626f782d69641a0773616e64626f78220377656228903f3001"; // Synthetic payloads generated with the public declarations at v0.0.116, // before their relocation into openshell.storage.v1. Values are deliberately // non-secret and the ordinary protobuf bytes contain no package names. @@ -594,9 +598,9 @@ mod tests { overlap_hash.as_str(), ), ( - (306, 26), - (93, 20), - (81, 20), + (306, 27), + (93, 21), + (81, 21), PUBLIC_RPC_SCHEMA_SHA256, DURABLE_SCHEMA_SHA256, PUBLIC_DURABLE_OVERLAP_SHA256 @@ -605,6 +609,30 @@ mod tests { ); } + #[test] + fn service_endpoint_without_authorization_mode_decodes_as_strip() { + use openshell_core::proto::{ServiceAuthorizationMode, ServiceEndpoint}; + + let endpoint = ServiceEndpoint::decode( + legacy_bytes(SERVICE_ENDPOINT_WITHOUT_AUTHORIZATION_MODE).as_slice(), + ) + .expect("stored service endpoint without authorization mode must decode"); + + assert_eq!(endpoint.sandbox_id, "sandbox-id"); + assert_eq!(endpoint.sandbox, "sandbox"); + assert_eq!(endpoint.name, "web"); + assert_eq!(endpoint.target_port, 8080); + assert!(endpoint.domain); + assert_eq!( + endpoint.authorization_mode(), + ServiceAuthorizationMode::Unspecified + ); + assert_eq!( + crate::service_routing::effective_authorization_mode(endpoint.authorization_mode), + ServiceAuthorizationMode::Strip + ); + } + #[test] fn pre_readiness_sandbox_spec_decodes_with_initial_attachment_epoch() { let spec = openshell_core::proto::SandboxSpec::decode( diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index 09f2e65fa8..8194b0df5b 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -478,13 +478,16 @@ name selects the unnamed endpoint. The returned sandbox includes a service URL map keyed by those names; use the empty key for the unnamed endpoint: ```python -from openshell import SandboxClient, ServiceExposure +from openshell import SandboxClient, ServiceAuthorizationMode, ServiceExposure with SandboxClient.from_active_cluster() as client: sandbox = client.create( workspace="default", name="app-server", - service_exposures=[ServiceExposure(target_port=4500)], + service_exposures=[ServiceExposure( + target_port=4500, + authorization_mode=ServiceAuthorizationMode.BEARER_PASSTHROUGH, + )], ) print(sandbox.service_urls[""]) ``` @@ -493,7 +496,10 @@ with SandboxClient.from_active_cluster() as client: const sandbox = await client.sandbox.create({ name: 'app-server', image: 'base', - serviceExposures: [{ targetPort: 4500 }], + serviceExposures: [{ + targetPort: 4500, + authorizationMode: ServiceAuthorizationMode.BearerPassthrough, + }], }) console.log(sandbox.serviceUrls['']) ``` @@ -502,7 +508,10 @@ console.log(sandbox.serviceUrls['']) sandbox, err := client.Sandboxes().Create( ctx, "default", "app-server", spec, nil, v1.CreateOptions{ServiceExposures: []v1.ServiceExposure{ - {TargetPort: 4500}, + { + TargetPort: 4500, + AuthorizationMode: v1.ServiceAuthorizationModeBearerPassthrough, + }, }}, ) fmt.Println(sandbox.ServiceURLs[""]) @@ -514,6 +523,7 @@ let sandbox = client.create_sandbox(openshell_sdk::SandboxSpec { service_exposures: vec![openshell_sdk::ServiceExposure { service: String::new(), target_port: 4500, + authorization_mode: openshell_sdk::ServiceAuthorizationMode::BearerPassthrough, }], ..Default::default() }).await?; @@ -532,6 +542,63 @@ Pass an optional service name to create a named service URL: openshell service expose my-sandbox 8080 web ``` +OpenShell strips the incoming `Authorization` header by default. Opt a service +into forwarding one valid bearer credential unchanged when the application +performs its own authentication: + +```shell +openshell service expose my-sandbox 4500 \ + --authorization-mode bearer-passthrough +``` + +For a create-time exposure, use both flags: + +```shell +openshell sandbox create \ + --expose 4500 \ + --expose-authorization-mode bearer-passthrough \ + --detach \ + -- ./authenticated-server +``` + +In `bearer-passthrough` mode, OpenShell accepts zero or one application +`Authorization` header. When present, it must contain a nonempty Bearer +credential. Missing credentials reach the application so it can return its own +authentication response. Duplicate, Basic, and malformed credentials fail with +`400 Bad Request`. Gateway and edge identity headers, proxy authorization, and +edge authentication cookies remain stripped. + + +Bearer passthrough delivers the caller's credential to the sandbox service. +Enable it only when that service is trusted to receive the credential. Exposed +services still use the gateway listener and its TLS configuration in this +release. + + +For example, Codex App Server can keep the raw capability outside the sandbox +and receive only its SHA-256 verifier: + +```shell +APP_SERVER_TOKEN="$(openssl rand -hex 32)" +APP_SERVER_TOKEN_SHA256="$(printf %s "$APP_SERVER_TOKEN" | openssl dgst -sha256 -hex | awk '{print $2}')" + +openshell sandbox create \ + --name codex-server \ + --env "APP_SERVER_TOKEN_SHA256=$APP_SERVER_TOKEN_SHA256" \ + --expose 4500 \ + --expose-authorization-mode bearer-passthrough \ + --detach \ + -- codex app-server \ + --listen ws://127.0.0.1:4500 \ + --ws-auth capability-token \ + --ws-token-sha256 "$APP_SERVER_TOKEN_SHA256" +``` + +Clients send `Authorization: Bearer $APP_SERVER_TOKEN` in the WebSocket +handshake. Codex's WebSocket transport is experimental and unsupported for +production workloads. It authenticates the handshake before the app-server +`initialize` request. + List exposed endpoints: ```shell @@ -552,7 +619,8 @@ openshell service list my-sandbox --output yaml ``` Structured list output contains `services` and `next_page_token` fields. Each -record contains `workspace`, `sandbox`, `service`, `target_port`, and `url`. +record contains `workspace`, `sandbox`, `service`, `target_port`, +`authorization_mode`, and `url`. The unnamed service uses an empty `service` string. Pass the returned token to `--page-token` to continue. An empty result has an empty `services` collection. @@ -571,7 +639,14 @@ openshell service delete my-sandbox ``` -Loopback gateways return local `openshell.localhost` URLs. Remote gateways return HTTPS URLs that require normal gateway authentication. For gateway service-domain configuration, refer to [Manage Gateways](/how-it-works/gateways/overview#configure-service-forwarding). +Loopback gateways return local `openshell.localhost` URLs. Remote gateways +return HTTPS URLs on the gateway listener. Service routes bypass control-plane +RPC authorization and do not use OIDC or CLI login. Because they share the +listener in this release, its TLS configuration—including any required client +certificate—still applies. The application is responsible for authentication +enabled on its endpoint, and an upstream edge proxy may still apply its own +access policy. For gateway service-domain configuration, refer to +[Manage Gateways](/how-it-works/gateways/overview#configure-service-forwarding). ## Monitor and Debug diff --git a/e2e/rust/Cargo.lock b/e2e/rust/Cargo.lock index c5235dff8b..018ae54912 100644 --- a/e2e/rust/Cargo.lock +++ b/e2e/rust/Cargo.lock @@ -38,7 +38,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e" dependencies = [ "aws-lc-sys", - "untrusted", + "untrusted 0.7.1", "zeroize", ] @@ -278,7 +278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -814,7 +814,7 @@ checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -902,6 +902,8 @@ dependencies = [ "noyalib", "prost", "rand", + "rustls", + "rustls-pemfile", "serde", "serde_json", "serial_test", @@ -909,6 +911,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tokio-rustls", "tokio-stream", "tonic", "tonic-prost", @@ -1111,6 +1114,20 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "rustc-hash" version = "2.1.3" @@ -1127,7 +1144,52 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted 0.9.0", ] [[package]] @@ -1317,7 +1379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1326,6 +1388,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.119" @@ -1375,7 +1443,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1452,7 +1520,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1466,6 +1534,16 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "tokio-rustls" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.19" @@ -1617,6 +1695,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.8" @@ -1738,6 +1822,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -1747,6 +1840,70 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "wit-bindgen" version = "0.57.1" diff --git a/e2e/rust/Cargo.toml b/e2e/rust/Cargo.toml index 4d0522ea86..a2a552400f 100644 --- a/e2e/rust/Cargo.toml +++ b/e2e/rust/Cargo.toml @@ -63,6 +63,11 @@ name = "custom_image" path = "tests/custom_image.rs" required-features = ["e2e-docker"] +[[test]] +name = "service_bearer_passthrough" +path = "tests/service_bearer_passthrough.rs" +required-features = ["e2e-docker"] + [[test]] name = "rootfs_tar" path = "tests/rootfs_tar.rs" @@ -240,11 +245,14 @@ sha1 = "0.10" sha2 = "0.10" hex = "0.4" rand = "0.9" +rustls = { version = "0.23", default-features = false, features = ["std", "logging", "tls12", "aws_lc_rs"] } +rustls-pemfile = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" serde_yml = { package = "noyalib", version = "0.0.28", default-features = false, features = ["std", "compat-serde-yaml"] } tonic = { version = "0.14", features = ["transport"] } tonic-prost = "0.14" +tokio-rustls = { version = "0.26", default-features = false, features = ["logging", "tls12", "aws_lc_rs"] } tower = "0.5" url = "2" nix = { version = "0.29", features = ["process", "signal", "term", "user"] } diff --git a/e2e/rust/tests/provider_readiness.rs b/e2e/rust/tests/provider_readiness.rs index 700c4880da..8ec6398a2b 100644 --- a/e2e/rust/tests/provider_readiness.rs +++ b/e2e/rust/tests/provider_readiness.rs @@ -477,9 +477,12 @@ impl Backend { async fn spawn(&mut self, base: &str, tls_directory: &Path) -> Result { let tls_directory = tls_directory .to_str() - .filter(|path| !path.contains([',', '\n', '\r'])) + .filter(|path| !path.contains([':', '\n', '\r'])) .ok_or("fixture TLS mount path is invalid")?; - let mount = format!("type=bind,src={tls_directory},dst=/fixture-tls,readonly"); + // Docker's structured `--mount` syntax cannot request SELinux + // relabeling. Both fixture backends mount this ephemeral directory, so + // use the shared `z` label rather than the single-container `Z` label. + let mount = format!("{tls_directory}:/fixture-tls:ro,z"); let namespace_label = format!("openshell.ai/sandbox-namespace={}", self.namespace); let mut command = Command::from(self.engine.command()); command @@ -501,7 +504,7 @@ impl Backend { "--read-only", "--cap-drop=ALL", "--security-opt=no-new-privileges:true", - "--mount", + "--volume", &mount, "--entrypoint", "/usr/bin/python3", diff --git a/e2e/rust/tests/service_bearer_passthrough.rs b/e2e/rust/tests/service_bearer_passthrough.rs new file mode 100644 index 0000000000..af2fddb76d --- /dev/null +++ b/e2e/rust/tests/service_bearer_passthrough.rs @@ -0,0 +1,344 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![cfg(feature = "e2e-docker")] + +//! Verifies application bearer authorization behavior through an exposed +//! `OpenShell` service. + +use std::fs::File; +use std::io::BufReader; +use std::net::Ipv4Addr; +use std::path::{Path, PathBuf}; +use std::process::Stdio; +use std::sync::Arc; +use std::time::Duration; + +use bytes::Bytes; +use http_body_util::{BodyExt as _, Empty}; +use hyper::client::conn::http1; +use hyper::{Request, StatusCode, header}; +use hyper_util::rt::TokioIo; +use openshell_e2e::harness::binary::openshell_cmd; +use openshell_e2e::harness::sandbox::{E2E_WORKLOAD_IMAGE, SandboxGuard}; +use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName}; +use rustls::{ClientConfig, RootCertStore}; +use serde_json::Value; +use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::net::TcpStream; +use tokio::time::{sleep, timeout}; +use tokio_rustls::TlsConnector; +use url::Position; + +const SERVICE_PORT: &str = "4500"; +const BEARER_TOKEN: &str = "Bearer openshell-e2e-application-token"; +const READY_TIMEOUT: Duration = Duration::from_secs(60); +const HEADER_ECHO_SERVER: &str = r#" +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer + +class Handler(BaseHTTPRequestHandler): + def do_GET(self): + body = self.headers.get("Authorization", "").encode() + self.send_response(200) + self.send_header("Content-Type", "text/plain") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def log_message(self, _format, *_args): + pass + +ThreadingHTTPServer(("127.0.0.1", 4500), Handler).serve_forever() +"#; + +async fn run_cli(args: &[&str]) -> Result { + let mut command = openshell_cmd(); + command + .args(args) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + command + .output() + .await + .map_err(|error| format!("failed to run openshell: {error}")) +} + +enum ServiceTransport { + Http, + Https { + connector: TlsConnector, + server_name: ServerName<'static>, + }, +} + +struct ServiceTarget { + port: u16, + authority: String, + path: String, + transport: ServiceTransport, +} + +impl ServiceTarget { + fn from_url(url: &str) -> Result { + let url = url::Url::parse(url).map_err(|error| format!("invalid service URL: {error}"))?; + let host = url + .host_str() + .ok_or_else(|| "service URL omitted its host".to_string())?; + let port = url + .port_or_known_default() + .ok_or_else(|| "service URL omitted its port".to_string())?; + let transport = match url.scheme() { + "http" => ServiceTransport::Http, + "https" => ServiceTransport::Https { + connector: e2e_tls_connector()?, + server_name: ServerName::try_from(host.to_string()) + .map_err(|error| format!("invalid service TLS server name: {error}"))?, + }, + scheme => return Err(format!("unsupported service URL scheme {scheme:?}")), + }; + let authority = url[Position::BeforeHost..Position::AfterPort].to_string(); + let path = url.query().map_or_else( + || url.path().to_string(), + |query| format!("{}?{query}", url.path()), + ); + + Ok(Self { + port, + authority, + path, + transport, + }) + } +} + +fn e2e_mtls_dir() -> Result { + let config_home = std::env::var_os("XDG_CONFIG_HOME") + .ok_or_else(|| "XDG_CONFIG_HOME is required for an HTTPS service URL".to_string())?; + let gateway = std::env::var("OPENSHELL_GATEWAY") + .map_err(|_| "OPENSHELL_GATEWAY is required for an HTTPS service URL".to_string())?; + Ok(PathBuf::from(config_home) + .join("openshell/gateways") + .join(gateway) + .join("mtls")) +} + +fn load_certificates( + path: &Path, + description: &str, +) -> Result>, String> { + let file = File::open(path) + .map_err(|error| format!("open {description} '{}': {error}", path.display()))?; + let mut reader = BufReader::new(file); + rustls_pemfile::certs(&mut reader) + .collect::, _>>() + .map_err(|error| format!("parse {description} '{}': {error}", path.display())) +} + +fn load_private_key(path: &Path) -> Result, String> { + let file = File::open(path) + .map_err(|error| format!("open client TLS key '{}': {error}", path.display()))?; + let mut reader = BufReader::new(file); + rustls_pemfile::private_key(&mut reader) + .map_err(|error| format!("parse client TLS key '{}': {error}", path.display()))? + .ok_or_else(|| format!("client TLS key '{}' is empty", path.display())) +} + +fn e2e_tls_connector() -> Result { + let mtls_dir = e2e_mtls_dir()?; + let ca_path = mtls_dir.join("ca.crt"); + let mut roots = RootCertStore::empty(); + for certificate in load_certificates(&ca_path, "gateway CA certificate")? { + roots.add(certificate).map_err(|error| { + format!( + "add gateway CA certificate '{}': {error}", + ca_path.display() + ) + })?; + } + let client_certificates = + load_certificates(&mtls_dir.join("tls.crt"), "client TLS certificate")?; + let client_key = load_private_key(&mtls_dir.join("tls.key"))?; + let config = ClientConfig::builder() + .with_root_certificates(roots) + .with_client_auth_cert(client_certificates, client_key) + .map_err(|error| format!("build e2e mTLS client configuration: {error}"))?; + Ok(TlsConnector::from(Arc::new(config))) +} + +async fn request_over_stream( + stream: S, + target: &ServiceTarget, + authorization: &str, +) -> Result<(StatusCode, String), String> +where + S: AsyncRead + AsyncWrite + Unpin + Send + 'static, +{ + let (mut sender, connection) = http1::handshake(TokioIo::new(stream)) + .await + .map_err(|error| format!("start HTTP connection: {error}"))?; + tokio::spawn(async move { + let _ = connection.await; + }); + + let request = Request::builder() + .uri(&target.path) + .header(header::HOST, &target.authority) + .header(header::AUTHORIZATION, authorization) + .body(Empty::::new()) + .map_err(|error| format!("build service request: {error}"))?; + let response = sender + .send_request(request) + .await + .map_err(|error| format!("send service request: {error}"))?; + let status = response.status(); + let body = response + .into_body() + .collect() + .await + .map_err(|error| format!("read service response: {error}"))? + .to_bytes(); + let body = String::from_utf8(body.to_vec()) + .map_err(|error| format!("service returned non-UTF-8 data: {error}"))?; + Ok((status, body)) +} + +async fn request_service( + target: &ServiceTarget, + authorization: &str, +) -> Result<(StatusCode, String), String> { + // The service hostname is a virtual routing authority. Dial the loopback + // gateway directly so the test does not depend on the host resolver + // recognizing arbitrary subdomains of `.localhost`. + let stream = TcpStream::connect((Ipv4Addr::LOCALHOST, target.port)) + .await + .map_err(|error| format!("connect to loopback service gateway: {error}"))?; + let _ = stream.set_nodelay(true); + match &target.transport { + ServiceTransport::Http => request_over_stream(stream, target, authorization).await, + ServiceTransport::Https { + connector, + server_name, + } => { + let stream = connector + .connect(server_name.clone(), stream) + .await + .map_err(|error| format!("start service TLS connection: {error}"))?; + request_over_stream(stream, target, authorization).await + } + } +} + +async fn wait_for_authorization(url: &str, expected: &str) -> Result<(), String> { + // Parse the URL and load TLS material before the retry loop so permanent + // test-configuration errors fail immediately instead of looking like + // service-readiness timeouts. + let target = ServiceTarget::from_url(url)?; + let mut last_observation = "no request attempted".to_string(); + let result = timeout(READY_TIMEOUT, async { + loop { + match request_service(&target, BEARER_TOKEN).await { + Ok((StatusCode::OK, body)) if body == expected => return Ok(()), + Ok((StatusCode::OK, body)) => { + return Err(format!( + "service received unexpected Authorization value: {body:?}" + )); + } + Ok((status, body)) + if matches!( + status, + StatusCode::BAD_GATEWAY + | StatusCode::PRECONDITION_FAILED + | StatusCode::SERVICE_UNAVAILABLE + ) => + { + last_observation = + format!("service returned retryable status {status} with body {body:?}"); + sleep(Duration::from_millis(250)).await; + } + Err(error) => { + last_observation = error; + sleep(Duration::from_millis(250)).await; + } + Ok((status, body)) => { + return Err(format!( + "service returned unexpected status {status} with body {body:?}" + )); + } + } + } + }) + .await; + + match result { + Ok(result) => result, + Err(_) => Err(format!( + "timed out waiting for the exposed service; last observation: {last_observation}" + )), + } +} + +#[tokio::test] +async fn service_bearer_passthrough_preserves_authorization_header() { + let sandbox_name = format!("service-auth-{}", std::process::id()); + let create = run_cli(&[ + "sandbox", + "create", + "--name", + &sandbox_name, + "--from", + E2E_WORKLOAD_IMAGE, + "--expose", + SERVICE_PORT, + "--output", + "json", + "--detach", + "--no-tty", + "--", + "python3", + "-c", + HEADER_ECHO_SERVER, + ]) + .await + .expect("run sandbox create"); + assert!( + create.status.success(), + "sandbox create failed with exit {:?}: {}", + create.status.code(), + String::from_utf8_lossy(&create.stderr) + ); + let mut sandbox = SandboxGuard::manage_existing(sandbox_name.clone()); + + let created: Value = serde_json::from_slice(&create.stdout).expect("parse sandbox create JSON"); + let service_url = created + .get("service_urls") + .and_then(|urls| urls.get("")) + .and_then(Value::as_str) + .expect("unnamed service URL in create response"); + + wait_for_authorization(service_url, "") + .await + .expect("default mode should strip Authorization"); + + let expose = run_cli(&[ + "service", + "expose", + &sandbox_name, + SERVICE_PORT, + "--authorization-mode", + "bearer-passthrough", + ]) + .await + .expect("run service re-expose"); + assert!( + expose.status.success(), + "service re-expose failed with exit {:?}: {}", + expose.status.code(), + String::from_utf8_lossy(&expose.stderr) + ); + + wait_for_authorization(service_url, BEARER_TOKEN) + .await + .expect("passthrough mode should preserve Authorization"); + + sandbox.cleanup().await; +} diff --git a/proto/openshell.proto b/proto/openshell.proto index 0eaf469f83..83ffbe75ad 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -1774,6 +1774,8 @@ message ExposeServiceRequest { // Optional nonzero UUID for durable at-most-once admission. Successful results // can be replayed for 24 hours; see the API errors and retries reference. string request_id = 6; + // Application authorization behavior. Omission resolves to STRIP. + ServiceAuthorizationMode authorization_mode = 7; } // Request to fetch an exposed sandbox service endpoint. @@ -1840,6 +1842,8 @@ message ServiceEndpoint { uint32 target_port = 5; // Whether browser-facing service routing is enabled for this endpoint. bool domain = 6; + // Effective application authorization behavior for ingress requests. + ServiceAuthorizationMode authorization_mode = 7; } // Response containing a service endpoint and, when available, its local URL. @@ -3785,4 +3789,17 @@ message SandboxServiceExposure { string service = 1; // Loopback TCP port inside the sandbox. uint32 target_port = 2; + // Application authorization behavior. Omission resolves to STRIP. + ServiceAuthorizationMode authorization_mode = 3; +} + +// Controls whether an exposed service receives the request's application +// Authorization header. +enum ServiceAuthorizationMode { + // Omission preserves the secure legacy behavior and resolves to STRIP. + SERVICE_AUTHORIZATION_MODE_UNSPECIFIED = 0; + // Remove Authorization before forwarding to the sandbox service. + SERVICE_AUTHORIZATION_MODE_STRIP = 1; + // Forward one syntactically valid bearer Authorization header unchanged. + SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH = 2; } diff --git a/python/openshell/__init__.py b/python/openshell/__init__.py index 8d0d20f578..109fe09521 100644 --- a/python/openshell/__init__.py +++ b/python/openshell/__init__.py @@ -21,6 +21,7 @@ SandboxStatusRef, SandboxTemplateClient, SandboxWorkloadTemplateProvenanceRef, + ServiceAuthorizationMode, ServiceExposure, TlsConfig, WorkspaceClient, @@ -53,6 +54,7 @@ "SandboxStatusRef", "SandboxTemplateClient", "SandboxWorkloadTemplateProvenanceRef", + "ServiceAuthorizationMode", "ServiceExposure", "TlsConfig", "WorkspaceClient", diff --git a/python/openshell/sandbox.py b/python/openshell/sandbox.py index 20d4734443..485af39d04 100644 --- a/python/openshell/sandbox.py +++ b/python/openshell/sandbox.py @@ -17,6 +17,7 @@ import time from collections import namedtuple from dataclasses import dataclass, field +from enum import IntEnum from typing import TYPE_CHECKING, Any, Generic, Never, SupportsIndex, TypeVar, cast from urllib.parse import urlparse @@ -115,6 +116,12 @@ def _service_exposure_messages( openshell_pb2.SandboxServiceExposure( service=exposure.service, target_port=exposure.target_port, + authorization_mode=( + openshell_pb2.SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH + if exposure.authorization_mode + == ServiceAuthorizationMode.BEARER_PASSTHROUGH + else openshell_pb2.SERVICE_AUTHORIZATION_MODE_STRIP + ), ) for exposure in exposures or () ] @@ -453,12 +460,20 @@ class SandboxStatusRef: main_process_started_at_ms: int | None = None +class ServiceAuthorizationMode(IntEnum): + """Handling for an incoming application Authorization header.""" + + STRIP = 1 + BEARER_PASSTHROUGH = 2 + + @dataclass(frozen=True) class ServiceExposure: """A loopback HTTP service to expose during sandbox creation.""" target_port: int service: str = "" + authorization_mode: ServiceAuthorizationMode = ServiceAuthorizationMode.STRIP class _ImmutableLabels(dict[str, str]): diff --git a/python/openshell/sandbox_test.py b/python/openshell/sandbox_test.py index 7702b9fcd7..3b744451cb 100644 --- a/python/openshell/sandbox_test.py +++ b/python/openshell/sandbox_test.py @@ -32,6 +32,7 @@ SandboxRef, SandboxStatusRef, SandboxTemplateClient, + ServiceAuthorizationMode, ServiceExposure, TlsConfig, _atomic_replace, @@ -2219,15 +2220,26 @@ def test_create_forwards_service_exposures() -> None: name="app-server", service_exposures=[ ServiceExposure(target_port=4500), - ServiceExposure(service="metrics", target_port=9090), + ServiceExposure( + service="metrics", + target_port=9090, + authorization_mode=ServiceAuthorizationMode.BEARER_PASSTHROUGH, + ), ], ) assert stub.create_request is not None assert [ - (exposure.service, exposure.target_port) + (exposure.service, exposure.target_port, exposure.authorization_mode) for exposure in stub.create_request.service_exposures - ] == [("", 4500), ("metrics", 9090)] + ] == [ + ("", 4500, openshell_pb2.SERVICE_AUTHORIZATION_MODE_STRIP), + ( + "metrics", + 9090, + openshell_pb2.SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH, + ), + ] assert dict(ref.service_urls) == { "": "https://.example.test/", "metrics": "https://metrics.example.test/", diff --git a/sdk/go/openshell/v1/fake/service.go b/sdk/go/openshell/v1/fake/service.go index 464d8f7fc9..3d7a1e0331 100644 --- a/sdk/go/openshell/v1/fake/service.go +++ b/sdk/go/openshell/v1/fake/service.go @@ -22,7 +22,7 @@ func newFakeServiceClient(closedFunc func() bool) *fakeServiceClient { } // Expose returns Unimplemented. -func (c *fakeServiceClient) Expose(_ context.Context, _, _, _ string, _ uint32, _ bool) (*types.ServiceEndpoint, error) { +func (c *fakeServiceClient) Expose(_ context.Context, _, _, _ string, _ uint32, _ bool, _ ...v1.ExposeServiceOptions) (*types.ServiceEndpoint, error) { if c.closedFunc() { return nil, &types.StatusError{Code: types.ErrorUnavailable, Message: "client is closed"} } diff --git a/sdk/go/openshell/v1/internal/converter/service.go b/sdk/go/openshell/v1/internal/converter/service.go index be50519613..bb2803c6bb 100644 --- a/sdk/go/openshell/v1/internal/converter/service.go +++ b/sdk/go/openshell/v1/internal/converter/service.go @@ -26,6 +26,7 @@ func ServiceEndpointFromProto(resp *pb.ServiceEndpointResponse) *types.ServiceEn result.Name = ep.GetName() result.TargetPort = ep.GetTargetPort() result.Domain = ep.GetDomain() + result.AuthorizationMode = serviceAuthorizationModeFromProto(ep.GetAuthorizationMode()) if m := ep.GetMetadata(); m != nil { result.ID = m.GetId() @@ -48,12 +49,27 @@ func ServiceEndpointToProto(se *types.ServiceEndpoint) *pb.ServiceEndpointRespon Id: se.ID, Workspace: se.Workspace, }, - SandboxId: se.SandboxID, - Sandbox: se.Sandbox, - Name: se.Name, - TargetPort: se.TargetPort, - Domain: se.Domain, + SandboxId: se.SandboxID, + Sandbox: se.Sandbox, + Name: se.Name, + TargetPort: se.TargetPort, + Domain: se.Domain, + AuthorizationMode: serviceAuthorizationModeToProto(se.AuthorizationMode), }, Url: se.URL, } } + +func serviceAuthorizationModeToProto(mode types.ServiceAuthorizationMode) pb.ServiceAuthorizationMode { + if mode == types.ServiceAuthorizationModeBearerPassthrough { + return pb.ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH + } + return pb.ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_STRIP +} + +func serviceAuthorizationModeFromProto(mode pb.ServiceAuthorizationMode) types.ServiceAuthorizationMode { + if mode == pb.ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH { + return types.ServiceAuthorizationModeBearerPassthrough + } + return types.ServiceAuthorizationModeStrip +} diff --git a/sdk/go/openshell/v1/internal/converter/service_test.go b/sdk/go/openshell/v1/internal/converter/service_test.go index ec5fa540a4..6db09701e3 100644 --- a/sdk/go/openshell/v1/internal/converter/service_test.go +++ b/sdk/go/openshell/v1/internal/converter/service_test.go @@ -19,11 +19,12 @@ func TestServiceEndpointFromProto(t *testing.T) { Metadata: &dm.ObjectMeta{ Id: "svc-1", }, - SandboxId: "sb-1", - Sandbox: "my-sandbox", - Name: "http-server", - TargetPort: 8080, - Domain: true, + SandboxId: "sb-1", + Sandbox: "my-sandbox", + Name: "http-server", + TargetPort: 8080, + Domain: true, + AuthorizationMode: pb.ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH, }, Url: "https://svc-1.example.com", } @@ -37,6 +38,7 @@ func TestServiceEndpointFromProto(t *testing.T) { assert.Equal(t, "http-server", se.Name) assert.Equal(t, uint32(8080), se.TargetPort) assert.True(t, se.Domain) + assert.Equal(t, v1.ServiceAuthorizationModeBearerPassthrough, se.AuthorizationMode) assert.Equal(t, "https://svc-1.example.com", se.URL) } @@ -78,13 +80,14 @@ func TestServiceEndpointFromProto_Nil(t *testing.T) { func TestServiceEndpointToProto(t *testing.T) { se := &v1.ServiceEndpoint{ - ID: "svc-1", - SandboxID: "sb-1", - Sandbox: "my-sandbox", - Name: "http-server", - TargetPort: 8080, - Domain: true, - URL: "https://svc-1.example.com", + ID: "svc-1", + SandboxID: "sb-1", + Sandbox: "my-sandbox", + Name: "http-server", + TargetPort: 8080, + Domain: true, + AuthorizationMode: v1.ServiceAuthorizationModeBearerPassthrough, + URL: "https://svc-1.example.com", } resp := ServiceEndpointToProto(se) @@ -98,6 +101,7 @@ func TestServiceEndpointToProto(t *testing.T) { assert.Equal(t, "http-server", resp.Endpoint.Name) assert.Equal(t, uint32(8080), resp.Endpoint.TargetPort) assert.True(t, resp.Endpoint.Domain) + assert.Equal(t, pb.ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH, resp.Endpoint.AuthorizationMode) assert.Equal(t, "https://svc-1.example.com", resp.Url) } @@ -108,13 +112,14 @@ func TestServiceEndpointToProto_Nil(t *testing.T) { func TestServiceEndpointRoundTrip(t *testing.T) { original := &v1.ServiceEndpoint{ - ID: "svc-rt", - SandboxID: "sb-rt", - Sandbox: "round-trip", - Name: "web", - TargetPort: 9090, - Domain: false, - URL: "http://localhost:9090", + ID: "svc-rt", + SandboxID: "sb-rt", + Sandbox: "round-trip", + Name: "web", + TargetPort: 9090, + Domain: false, + AuthorizationMode: v1.ServiceAuthorizationModeBearerPassthrough, + URL: "http://localhost:9090", } proto := ServiceEndpointToProto(original) @@ -127,5 +132,6 @@ func TestServiceEndpointRoundTrip(t *testing.T) { assert.Equal(t, original.Name, back.Name) assert.Equal(t, original.TargetPort, back.TargetPort) assert.Equal(t, original.Domain, back.Domain) + assert.Equal(t, original.AuthorizationMode, back.AuthorizationMode) assert.Equal(t, original.URL, back.URL) } diff --git a/sdk/go/openshell/v1/sandbox_client.go b/sdk/go/openshell/v1/sandbox_client.go index 9868d11b93..f8b8290ca1 100644 --- a/sdk/go/openshell/v1/sandbox_client.go +++ b/sdk/go/openshell/v1/sandbox_client.go @@ -91,13 +91,21 @@ func serviceExposuresToProto(exposures []types.ServiceExposure) []*pb.SandboxSer result := make([]*pb.SandboxServiceExposure, 0, len(exposures)) for _, exposure := range exposures { result = append(result, &pb.SandboxServiceExposure{ - Service: exposure.Service, - TargetPort: exposure.TargetPort, + Service: exposure.Service, + TargetPort: exposure.TargetPort, + AuthorizationMode: serviceAuthorizationModeToProto(exposure.AuthorizationMode), }) } return result } +func serviceAuthorizationModeToProto(mode types.ServiceAuthorizationMode) pb.ServiceAuthorizationMode { + if mode == 0 { + return pb.ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_STRIP + } + return pb.ServiceAuthorizationMode(mode) +} + func validateTemplateCreateSpec(spec *SandboxSpec) error { if spec == nil { return nil diff --git a/sdk/go/openshell/v1/sandbox_client_test.go b/sdk/go/openshell/v1/sandbox_client_test.go index 8ae398f9e0..70c3b6fab2 100644 --- a/sdk/go/openshell/v1/sandbox_client_test.go +++ b/sdk/go/openshell/v1/sandbox_client_test.go @@ -318,7 +318,11 @@ func TestSandboxCreate(t *testing.T) { labels, CreateOptions{ServiceExposures: []ServiceExposure{ {TargetPort: 4500}, - {Service: "metrics", TargetPort: 9090}, + { + Service: "metrics", + TargetPort: 9090, + AuthorizationMode: ServiceAuthorizationModeBearerPassthrough, + }, }}, ) @@ -334,7 +338,9 @@ func TestSandboxCreate(t *testing.T) { }, result.ServiceURLs) require.Len(t, mock.createRequest.GetServiceExposures(), 2) assert.Equal(t, uint32(4500), mock.createRequest.GetServiceExposures()[0].GetTargetPort()) + assert.Equal(t, pb.ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_STRIP, mock.createRequest.GetServiceExposures()[0].GetAuthorizationMode()) assert.Equal(t, "metrics", mock.createRequest.GetServiceExposures()[1].GetService()) + assert.Equal(t, pb.ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH, mock.createRequest.GetServiceExposures()[1].GetAuthorizationMode()) } func TestSandboxCreate_DefaultGPURequest(t *testing.T) { diff --git a/sdk/go/openshell/v1/service.go b/sdk/go/openshell/v1/service.go index 3ef3bea2fc..ccaf93ee4b 100644 --- a/sdk/go/openshell/v1/service.go +++ b/sdk/go/openshell/v1/service.go @@ -15,9 +15,24 @@ type ServiceEndpoint = types.ServiceEndpoint // ServiceExposure describes a loopback HTTP service to expose during sandbox creation. type ServiceExposure = types.ServiceExposure +// ServiceAuthorizationMode controls handling of an incoming application Authorization header. +type ServiceAuthorizationMode = types.ServiceAuthorizationMode + +const ( + // ServiceAuthorizationModeStrip removes Authorization before proxying to the service. + ServiceAuthorizationModeStrip = types.ServiceAuthorizationModeStrip + // ServiceAuthorizationModeBearerPassthrough forwards one valid bearer credential unchanged. + ServiceAuthorizationModeBearerPassthrough = types.ServiceAuthorizationModeBearerPassthrough +) + +// ExposeServiceOptions configures service exposure behavior. +type ExposeServiceOptions struct { + AuthorizationMode ServiceAuthorizationMode +} + // ServiceInterface defines operations for managing sandbox service endpoints. type ServiceInterface interface { - Expose(ctx context.Context, workspace, sandboxName, serviceName string, targetPort uint32, domain bool) (*ServiceEndpoint, error) + Expose(ctx context.Context, workspace, sandboxName, serviceName string, targetPort uint32, domain bool, opts ...ExposeServiceOptions) (*ServiceEndpoint, error) Get(ctx context.Context, workspace, sandboxName, serviceName string) (*ServiceEndpoint, error) List(workspace, sandboxName string, opts ...ListOptions) (*Pager[*ServiceEndpoint], error) ListAll(ctx context.Context, workspace, sandboxName string, opts ...ListOptions) ([]*ServiceEndpoint, error) diff --git a/sdk/go/openshell/v1/service_client.go b/sdk/go/openshell/v1/service_client.go index 80eb2bbab7..5606ebf2a0 100644 --- a/sdk/go/openshell/v1/service_client.go +++ b/sdk/go/openshell/v1/service_client.go @@ -19,13 +19,18 @@ func newServiceClient(conn grpc.ClientConnInterface) *serviceClient { return &serviceClient{client: pb.NewOpenShellClient(conn)} } -func (s *serviceClient) Expose(ctx context.Context, workspace, sandboxName, serviceName string, targetPort uint32, domain bool) (*ServiceEndpoint, error) { +func (s *serviceClient) Expose(ctx context.Context, workspace, sandboxName, serviceName string, targetPort uint32, domain bool, opts ...ExposeServiceOptions) (*ServiceEndpoint, error) { + authorizationMode := ServiceAuthorizationModeStrip + if len(opts) > 0 && opts[0].AuthorizationMode != 0 { + authorizationMode = opts[0].AuthorizationMode + } resp, err := s.client.ExposeService(ctx, &pb.ExposeServiceRequest{ - Sandbox: sandboxName, - WorkspaceScope: namedWorkspaceScope(workspace), - Name: serviceName, - TargetPort: targetPort, - Domain: domain, + Sandbox: sandboxName, + WorkspaceScope: namedWorkspaceScope(workspace), + Name: serviceName, + TargetPort: targetPort, + Domain: domain, + AuthorizationMode: pb.ServiceAuthorizationMode(authorizationMode), }) if err != nil { return nil, converter.FromGRPCError(err) diff --git a/sdk/go/openshell/v1/service_client_test.go b/sdk/go/openshell/v1/service_client_test.go index 9b702dbde6..3ba2e5e69a 100644 --- a/sdk/go/openshell/v1/service_client_test.go +++ b/sdk/go/openshell/v1/service_client_test.go @@ -55,10 +55,11 @@ func (s *mockServiceServer) ExposeService(_ context.Context, req *pb.ExposeServi Metadata: &dm.ObjectMeta{ Id: "ep-" + req.GetName(), }, - Sandbox: req.GetSandbox(), - Name: req.GetName(), - TargetPort: req.GetTargetPort(), - Domain: req.GetDomain(), + Sandbox: req.GetSandbox(), + Name: req.GetName(), + TargetPort: req.GetTargetPort(), + Domain: req.GetDomain(), + AuthorizationMode: req.GetAuthorizationMode(), }, } if req.GetDomain() { @@ -150,7 +151,15 @@ func TestServiceExpose(t *testing.T) { client, cleanup := setupServiceTest(t, mock) defer cleanup() - ep, err := client.Expose(context.Background(), "default", "web-app", "api", 8080, true) + ep, err := client.Expose( + context.Background(), + "default", + "web-app", + "api", + 8080, + true, + ExposeServiceOptions{AuthorizationMode: ServiceAuthorizationModeBearerPassthrough}, + ) require.NoError(t, err) require.NotNil(t, ep) @@ -159,6 +168,7 @@ func TestServiceExpose(t *testing.T) { assert.Equal(t, "api", ep.Name) assert.Equal(t, uint32(8080), ep.TargetPort) assert.True(t, ep.Domain) + assert.Equal(t, ServiceAuthorizationModeBearerPassthrough, ep.AuthorizationMode) assert.Equal(t, "https://api.example.com", ep.URL) } diff --git a/sdk/go/openshell/v1/types/service.go b/sdk/go/openshell/v1/types/service.go index 9cccff8258..5ae7aa0b9e 100644 --- a/sdk/go/openshell/v1/types/service.go +++ b/sdk/go/openshell/v1/types/service.go @@ -3,20 +3,32 @@ package types +// ServiceAuthorizationMode controls handling of an incoming application Authorization header. +type ServiceAuthorizationMode int32 + +const ( + // ServiceAuthorizationModeStrip removes Authorization before proxying to the sandbox service. + ServiceAuthorizationModeStrip ServiceAuthorizationMode = 1 + // ServiceAuthorizationModeBearerPassthrough forwards one valid bearer credential unchanged. + ServiceAuthorizationModeBearerPassthrough ServiceAuthorizationMode = 2 +) + // ServiceExposure describes a loopback HTTP service to expose during sandbox creation. type ServiceExposure struct { - Service string - TargetPort uint32 + Service string + TargetPort uint32 + AuthorizationMode ServiceAuthorizationMode } // ServiceEndpoint represents an exposed HTTP service on a sandbox. type ServiceEndpoint struct { - ID string - SandboxID string - Sandbox string - Name string - TargetPort uint32 - Domain bool - URL string - Workspace string + ID string + SandboxID string + Sandbox string + Name string + TargetPort uint32 + Domain bool + URL string + Workspace string + AuthorizationMode ServiceAuthorizationMode } diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index f4258a87b6..109d2ef454 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -1197,6 +1197,60 @@ func (EndpointResult) EnumDescriptor() ([]byte, []int) { return file_openshell_proto_rawDescGZIP(), []int{18} } +// Controls whether an exposed service receives the request's application +// Authorization header. +type ServiceAuthorizationMode int32 + +const ( + // Omission preserves the secure legacy behavior and resolves to STRIP. + ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_UNSPECIFIED ServiceAuthorizationMode = 0 + // Remove Authorization before forwarding to the sandbox service. + ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_STRIP ServiceAuthorizationMode = 1 + // Forward one syntactically valid bearer Authorization header unchanged. + ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH ServiceAuthorizationMode = 2 +) + +// Enum value maps for ServiceAuthorizationMode. +var ( + ServiceAuthorizationMode_name = map[int32]string{ + 0: "SERVICE_AUTHORIZATION_MODE_UNSPECIFIED", + 1: "SERVICE_AUTHORIZATION_MODE_STRIP", + 2: "SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH", + } + ServiceAuthorizationMode_value = map[string]int32{ + "SERVICE_AUTHORIZATION_MODE_UNSPECIFIED": 0, + "SERVICE_AUTHORIZATION_MODE_STRIP": 1, + "SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH": 2, + } +) + +func (x ServiceAuthorizationMode) Enum() *ServiceAuthorizationMode { + p := new(ServiceAuthorizationMode) + *p = x + return p +} + +func (x ServiceAuthorizationMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ServiceAuthorizationMode) Descriptor() protoreflect.EnumDescriptor { + return file_openshell_proto_enumTypes[19].Descriptor() +} + +func (ServiceAuthorizationMode) Type() protoreflect.EnumType { + return &file_openshell_proto_enumTypes[19] +} + +func (x ServiceAuthorizationMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ServiceAuthorizationMode.Descriptor instead. +func (ServiceAuthorizationMode) EnumDescriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{19} +} + // IssueSandboxToken request. Empty body; identity is established by the // authentication credentials carried in the request headers (a projected // Kubernetes ServiceAccount JWT in the K8s driver path). @@ -6107,9 +6161,11 @@ type ExposeServiceRequest struct { Sandbox string `protobuf:"bytes,1,opt,name=sandbox,proto3" json:"sandbox,omitempty"` // Optional nonzero UUID for durable at-most-once admission. Successful results // can be replayed for 24 hours; see the API errors and retries reference. - RequestId string `protobuf:"bytes,6,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + RequestId string `protobuf:"bytes,6,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // Application authorization behavior. Omission resolves to STRIP. + AuthorizationMode ServiceAuthorizationMode `protobuf:"varint,7,opt,name=authorization_mode,json=authorizationMode,proto3,enum=openshell.v1.ServiceAuthorizationMode" json:"authorization_mode,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExposeServiceRequest) Reset() { @@ -6184,6 +6240,13 @@ func (x *ExposeServiceRequest) GetRequestId() string { return "" } +func (x *ExposeServiceRequest) GetAuthorizationMode() ServiceAuthorizationMode { + if x != nil { + return x.AuthorizationMode + } + return ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_UNSPECIFIED +} + // Request to fetch an exposed sandbox service endpoint. type GetServiceRequest struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -6516,9 +6579,11 @@ type ServiceEndpoint struct { // Loopback TCP port inside the sandbox. TargetPort uint32 `protobuf:"varint,5,opt,name=target_port,json=targetPort,proto3" json:"target_port,omitempty"` // Whether browser-facing service routing is enabled for this endpoint. - Domain bool `protobuf:"varint,6,opt,name=domain,proto3" json:"domain,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Domain bool `protobuf:"varint,6,opt,name=domain,proto3" json:"domain,omitempty"` + // Effective application authorization behavior for ingress requests. + AuthorizationMode ServiceAuthorizationMode `protobuf:"varint,7,opt,name=authorization_mode,json=authorizationMode,proto3,enum=openshell.v1.ServiceAuthorizationMode" json:"authorization_mode,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ServiceEndpoint) Reset() { @@ -6593,6 +6658,13 @@ func (x *ServiceEndpoint) GetDomain() bool { return false } +func (x *ServiceEndpoint) GetAuthorizationMode() ServiceAuthorizationMode { + if x != nil { + return x.AuthorizationMode + } + return ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_UNSPECIFIED +} + // Response containing a service endpoint and, when available, its local URL. type ServiceEndpointResponse struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -17694,9 +17766,11 @@ type SandboxServiceExposure struct { // Service name within the sandbox. Empty selects the unnamed endpoint. Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` // Loopback TCP port inside the sandbox. - TargetPort uint32 `protobuf:"varint,2,opt,name=target_port,json=targetPort,proto3" json:"target_port,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + TargetPort uint32 `protobuf:"varint,2,opt,name=target_port,json=targetPort,proto3" json:"target_port,omitempty"` + // Application authorization behavior. Omission resolves to STRIP. + AuthorizationMode ServiceAuthorizationMode `protobuf:"varint,3,opt,name=authorization_mode,json=authorizationMode,proto3,enum=openshell.v1.ServiceAuthorizationMode" json:"authorization_mode,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SandboxServiceExposure) Reset() { @@ -17743,6 +17817,13 @@ func (x *SandboxServiceExposure) GetTargetPort() uint32 { return 0 } +func (x *SandboxServiceExposure) GetAuthorizationMode() ServiceAuthorizationMode { + if x != nil { + return x.AuthorizationMode + } + return ServiceAuthorizationMode_SERVICE_AUTHORIZATION_MODE_UNSPECIFIED +} + var File_openshell_proto protoreflect.FileDescriptor const file_openshell_proto_rawDesc = "" + @@ -18146,7 +18227,7 @@ const file_openshell_proto_rawDesc = "" + "\fgateway_port\x18\x04 \x01(\rR\vgatewayPort\x12%\n" + "\x0egateway_scheme\x18\x05 \x01(\tR\rgatewayScheme\x120\n" + "\x14host_key_fingerprint\x18\a \x01(\tR\x12hostKeyFingerprint\x12C\n" + - "\x0fexpiration_time\x18l \x01(\v2\x1a.google.protobuf.TimestampR\x0eexpirationTimeJ\x04\b\b\x10\tR\rexpires_at_ms\"\xf0\x01\n" + + "\x0fexpiration_time\x18l \x01(\v2\x1a.google.protobuf.TimestampR\x0eexpirationTimeJ\x04\b\b\x10\tR\rexpires_at_ms\"\xc7\x02\n" + "\x14ExposeServiceRequest\x12R\n" + "\x0fworkspace_scope\x18\x05 \x01(\v2).openshell.datamodel.v1.WorkspaceSelectorR\x0eworkspaceScope\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1f\n" + @@ -18155,7 +18236,8 @@ const file_openshell_proto_rawDesc = "" + "\x06domain\x18\x04 \x01(\bR\x06domain\x12\x18\n" + "\asandbox\x18\x01 \x01(\tR\asandbox\x12\x1d\n" + "\n" + - "request_id\x18\x06 \x01(\tR\trequestId\"\x95\x01\n" + + "request_id\x18\x06 \x01(\tR\trequestId\x12U\n" + + "\x12authorization_mode\x18\a \x01(\x0e2&.openshell.v1.ServiceAuthorizationModeR\x11authorizationMode\"\x95\x01\n" + "\x11GetServiceRequest\x12R\n" + "\x0fworkspace_scope\x18\x03 \x01(\v2).openshell.datamodel.v1.WorkspaceSelectorR\x0eworkspaceScope\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12\x18\n" + @@ -18177,7 +18259,7 @@ const file_openshell_proto_rawDesc = "" + "\n" + "request_id\x18\x05 \x01(\tR\trequestId\"_\n" + "\x15DeleteServiceResponse\x127\n" + - "\aoutcome\x18\x02 \x01(\x0e2\x1d.openshell.v1.DeletionOutcomeR\aoutcomeJ\x04\b\x01\x10\x02R\adeleted\"\xd7\x01\n" + + "\aoutcome\x18\x02 \x01(\x0e2\x1d.openshell.v1.DeletionOutcomeR\aoutcomeJ\x04\b\x01\x10\x02R\adeleted\"\xae\x02\n" + "\x0fServiceEndpoint\x12>\n" + "\bmetadata\x18\x01 \x01(\v2\".openshell.datamodel.v1.ObjectMetaR\bmetadata\x12\x1d\n" + "\n" + @@ -18186,7 +18268,8 @@ const file_openshell_proto_rawDesc = "" + "\x04name\x18\x04 \x01(\tR\x04name\x12\x1f\n" + "\vtarget_port\x18\x05 \x01(\rR\n" + "targetPort\x12\x16\n" + - "\x06domain\x18\x06 \x01(\bR\x06domain\"f\n" + + "\x06domain\x18\x06 \x01(\bR\x06domain\x12U\n" + + "\x12authorization_mode\x18\a \x01(\x0e2&.openshell.v1.ServiceAuthorizationModeR\x11authorizationMode\"f\n" + "\x17ServiceEndpointResponse\x129\n" + "\bendpoint\x18\x01 \x01(\v2\x1d.openshell.v1.ServiceEndpointR\bendpoint\x12\x10\n" + "\x03url\x18\x02 \x01(\tR\x03url\"Z\n" + @@ -19072,11 +19155,12 @@ const file_openshell_proto_rawDesc = "" + "\x12cleanup_retry_time\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\x10cleanupRetryTime\x120\n" + "\x14attachment_change_id\x18\n" + " \x01(\tR\x12attachmentChangeId\x12P\n" + - "\x16attachment_change_time\x18\v \x01(\v2\x1a.google.protobuf.TimestampR\x14attachmentChangeTime\"S\n" + + "\x16attachment_change_time\x18\v \x01(\v2\x1a.google.protobuf.TimestampR\x14attachmentChangeTime\"\xaa\x01\n" + "\x16SandboxServiceExposure\x12\x18\n" + "\aservice\x18\x01 \x01(\tR\aservice\x12\x1f\n" + "\vtarget_port\x18\x02 \x01(\rR\n" + - "targetPort*\xca\x01\n" + + "targetPort\x12U\n" + + "\x12authorization_mode\x18\x03 \x01(\x0e2&.openshell.v1.ServiceAuthorizationModeR\x11authorizationMode*\xca\x01\n" + "\rExtensionKind\x12\x1e\n" + "\x1aEXTENSION_KIND_UNSPECIFIED\x10\x00\x12!\n" + "\x1dEXTENSION_KIND_COMPUTE_DRIVER\x10\x01\x12$\n" + @@ -19216,7 +19300,11 @@ const file_openshell_proto_rawDesc = "" + "&ENDPOINT_RESULT_CREDENTIAL_UNAVAILABLE\x10\x04\x12\x1e\n" + "\x1aENDPOINT_RESULT_TLS_FAILED\x10\x05\x12$\n" + " ENDPOINT_RESULT_TRANSPORT_FAILED\x10\x06\x12%\n" + - "!ENDPOINT_RESULT_UPSTREAM_REJECTED\x10\a2\xafU\n" + + "!ENDPOINT_RESULT_UPSTREAM_REJECTED\x10\a*\x9f\x01\n" + + "\x18ServiceAuthorizationMode\x12*\n" + + "&SERVICE_AUTHORIZATION_MODE_UNSPECIFIED\x10\x00\x12$\n" + + " SERVICE_AUTHORIZATION_MODE_STRIP\x10\x01\x121\n" + + "-SERVICE_AUTHORIZATION_MODE_BEARER_PASSTHROUGH\x10\x022\xafU\n" + "\tOpenShell\x12Z\n" + "\x06Health\x12\x1b.openshell.v1.HealthRequest\x1a\x1c.openshell.v1.HealthResponse\"\x15\x82\xb5\x18\x11\n" + "\x0funauthenticated\x12i\n" + @@ -19402,7 +19490,7 @@ func file_openshell_proto_rawDescGZIP() []byte { return file_openshell_proto_rawDescData } -var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 19) +var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 20) var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 255) var file_openshell_proto_goTypes = []any{ (ExtensionKind)(0), // 0: openshell.v1.ExtensionKind @@ -19424,772 +19512,776 @@ var file_openshell_proto_goTypes = []any{ (SandboxRestartPolicy)(0), // 16: openshell.v1.SandboxRestartPolicy (DeletionOutcome)(0), // 17: openshell.v1.DeletionOutcome (EndpointResult)(0), // 18: openshell.v1.EndpointResult - (*IssueSandboxTokenRequest)(nil), // 19: openshell.v1.IssueSandboxTokenRequest - (*IssueSandboxTokenResponse)(nil), // 20: openshell.v1.IssueSandboxTokenResponse - (*RefreshSandboxTokenRequest)(nil), // 21: openshell.v1.RefreshSandboxTokenRequest - (*RefreshSandboxTokenResponse)(nil), // 22: openshell.v1.RefreshSandboxTokenResponse - (*HealthRequest)(nil), // 23: openshell.v1.HealthRequest - (*HealthResponse)(nil), // 24: openshell.v1.HealthResponse - (*GetCurrentUserRequest)(nil), // 25: openshell.v1.GetCurrentUserRequest - (*GetCurrentUserResponse)(nil), // 26: openshell.v1.GetCurrentUserResponse - (*GetGatewayInfoRequest)(nil), // 27: openshell.v1.GetGatewayInfoRequest - (*GetGatewayInfoResponse)(nil), // 28: openshell.v1.GetGatewayInfoResponse - (*NegotiatedExtensionInfo)(nil), // 29: openshell.v1.NegotiatedExtensionInfo - (*ComputeDriverInfo)(nil), // 30: openshell.v1.ComputeDriverInfo - (*ComputeDriverCapabilities)(nil), // 31: openshell.v1.ComputeDriverCapabilities - (*ResourceCapabilities)(nil), // 32: openshell.v1.ResourceCapabilities - (*CpuResourceCapabilities)(nil), // 33: openshell.v1.CpuResourceCapabilities - (*MemoryResourceCapabilities)(nil), // 34: openshell.v1.MemoryResourceCapabilities - (*GpuResourceCapabilities)(nil), // 35: openshell.v1.GpuResourceCapabilities - (*Sandbox)(nil), // 36: openshell.v1.Sandbox - (*SandboxSpec)(nil), // 37: openshell.v1.SandboxSpec - (*ResourceRequirements)(nil), // 38: openshell.v1.ResourceRequirements - (*GpuResourceRequirements)(nil), // 39: openshell.v1.GpuResourceRequirements - (*SandboxTemplate)(nil), // 40: openshell.v1.SandboxTemplate - (*SandboxWorkloadTemplate)(nil), // 41: openshell.v1.SandboxWorkloadTemplate - (*SandboxWorkloadTemplateSpec)(nil), // 42: openshell.v1.SandboxWorkloadTemplateSpec - (*SandboxWorkloadConfig)(nil), // 43: openshell.v1.SandboxWorkloadConfig - (*SandboxResources)(nil), // 44: openshell.v1.SandboxResources - (*SandboxServiceLevel)(nil), // 45: openshell.v1.SandboxServiceLevel - (*SandboxStartup)(nil), // 46: openshell.v1.SandboxStartup - (*SandboxWorkloadTemplateProvenance)(nil), // 47: openshell.v1.SandboxWorkloadTemplateProvenance - (*SandboxStatus)(nil), // 48: openshell.v1.SandboxStatus - (*SandboxCondition)(nil), // 49: openshell.v1.SandboxCondition - (*PlatformEvent)(nil), // 50: openshell.v1.PlatformEvent - (*CreateSandboxRequest)(nil), // 51: openshell.v1.CreateSandboxRequest - (*CreateSandboxTemplateRequest)(nil), // 52: openshell.v1.CreateSandboxTemplateRequest - (*GetSandboxTemplateRequest)(nil), // 53: openshell.v1.GetSandboxTemplateRequest - (*ListSandboxTemplatesRequest)(nil), // 54: openshell.v1.ListSandboxTemplatesRequest - (*DeleteSandboxTemplateRequest)(nil), // 55: openshell.v1.DeleteSandboxTemplateRequest - (*SandboxTemplateResponse)(nil), // 56: openshell.v1.SandboxTemplateResponse - (*ListSandboxTemplatesResponse)(nil), // 57: openshell.v1.ListSandboxTemplatesResponse - (*DeleteSandboxTemplateResponse)(nil), // 58: openshell.v1.DeleteSandboxTemplateResponse - (*BeginRootfsTarStagingRequest)(nil), // 59: openshell.v1.BeginRootfsTarStagingRequest - (*BeginRootfsTarStagingResponse)(nil), // 60: openshell.v1.BeginRootfsTarStagingResponse - (*GetSandboxRequest)(nil), // 61: openshell.v1.GetSandboxRequest - (*ListSandboxesRequest)(nil), // 62: openshell.v1.ListSandboxesRequest - (*ListSandboxProvidersRequest)(nil), // 63: openshell.v1.ListSandboxProvidersRequest - (*AttachSandboxProviderRequest)(nil), // 64: openshell.v1.AttachSandboxProviderRequest - (*DetachSandboxProviderRequest)(nil), // 65: openshell.v1.DetachSandboxProviderRequest - (*DeleteSandboxRequest)(nil), // 66: openshell.v1.DeleteSandboxRequest - (*StopSandboxRequest)(nil), // 67: openshell.v1.StopSandboxRequest - (*StartSandboxRequest)(nil), // 68: openshell.v1.StartSandboxRequest - (*SandboxResponse)(nil), // 69: openshell.v1.SandboxResponse - (*ListSandboxesResponse)(nil), // 70: openshell.v1.ListSandboxesResponse - (*ListSandboxProvidersResponse)(nil), // 71: openshell.v1.ListSandboxProvidersResponse - (*AttachSandboxProviderResponse)(nil), // 72: openshell.v1.AttachSandboxProviderResponse - (*DetachSandboxProviderResponse)(nil), // 73: openshell.v1.DetachSandboxProviderResponse - (*ProviderDesiredIdentity)(nil), // 74: openshell.v1.ProviderDesiredIdentity - (*ConfigSnapshotRevision)(nil), // 75: openshell.v1.ConfigSnapshotRevision - (*SandboxConfigRevision)(nil), // 76: openshell.v1.SandboxConfigRevision - (*ConfigUpdateOperation)(nil), // 77: openshell.v1.ConfigUpdateOperation - (*ProviderMutationReceipt)(nil), // 78: openshell.v1.ProviderMutationReceipt - (*ProviderReadinessObservation)(nil), // 79: openshell.v1.ProviderReadinessObservation - (*ProviderReadinessStatus)(nil), // 80: openshell.v1.ProviderReadinessStatus - (*GetSandboxProviderStatusRequest)(nil), // 81: openshell.v1.GetSandboxProviderStatusRequest - (*GetSandboxProviderStatusResponse)(nil), // 82: openshell.v1.GetSandboxProviderStatusResponse - (*ReportProviderReadinessRequest)(nil), // 83: openshell.v1.ReportProviderReadinessRequest - (*ReportProviderReadinessResponse)(nil), // 84: openshell.v1.ReportProviderReadinessResponse - (*DeleteSandboxResponse)(nil), // 85: openshell.v1.DeleteSandboxResponse - (*CreateSshSessionRequest)(nil), // 86: openshell.v1.CreateSshSessionRequest - (*CreateSshSessionResponse)(nil), // 87: openshell.v1.CreateSshSessionResponse - (*ExposeServiceRequest)(nil), // 88: openshell.v1.ExposeServiceRequest - (*GetServiceRequest)(nil), // 89: openshell.v1.GetServiceRequest - (*ListServicesRequest)(nil), // 90: openshell.v1.ListServicesRequest - (*ListServicesResponse)(nil), // 91: openshell.v1.ListServicesResponse - (*DeleteServiceRequest)(nil), // 92: openshell.v1.DeleteServiceRequest - (*DeleteServiceResponse)(nil), // 93: openshell.v1.DeleteServiceResponse - (*ServiceEndpoint)(nil), // 94: openshell.v1.ServiceEndpoint - (*ServiceEndpointResponse)(nil), // 95: openshell.v1.ServiceEndpointResponse - (*RevokeSshSessionRequest)(nil), // 96: openshell.v1.RevokeSshSessionRequest - (*RevokeSshSessionResponse)(nil), // 97: openshell.v1.RevokeSshSessionResponse - (*ExecSandboxRequest)(nil), // 98: openshell.v1.ExecSandboxRequest - (*ExecSandboxStdout)(nil), // 99: openshell.v1.ExecSandboxStdout - (*ExecSandboxStderr)(nil), // 100: openshell.v1.ExecSandboxStderr - (*ExecSandboxExit)(nil), // 101: openshell.v1.ExecSandboxExit - (*ExecSandboxEvent)(nil), // 102: openshell.v1.ExecSandboxEvent - (*TcpForwardInit)(nil), // 103: openshell.v1.TcpForwardInit - (*TcpForwardFrame)(nil), // 104: openshell.v1.TcpForwardFrame - (*ExecSandboxInput)(nil), // 105: openshell.v1.ExecSandboxInput - (*ExecSandboxWindowResize)(nil), // 106: openshell.v1.ExecSandboxWindowResize - (*SshSession)(nil), // 107: openshell.v1.SshSession - (*WatchSandboxRequest)(nil), // 108: openshell.v1.WatchSandboxRequest - (*SandboxStreamEvent)(nil), // 109: openshell.v1.SandboxStreamEvent - (*SandboxLogLine)(nil), // 110: openshell.v1.SandboxLogLine - (*SandboxStreamWarning)(nil), // 111: openshell.v1.SandboxStreamWarning - (*CreateProviderRequest)(nil), // 112: openshell.v1.CreateProviderRequest - (*GetProviderRequest)(nil), // 113: openshell.v1.GetProviderRequest - (*ListProvidersRequest)(nil), // 114: openshell.v1.ListProvidersRequest - (*UpdateProviderRequest)(nil), // 115: openshell.v1.UpdateProviderRequest - (*DeleteProviderRequest)(nil), // 116: openshell.v1.DeleteProviderRequest - (*ProviderResponse)(nil), // 117: openshell.v1.ProviderResponse - (*ListProvidersResponse)(nil), // 118: openshell.v1.ListProvidersResponse - (*ListProviderProfilesRequest)(nil), // 119: openshell.v1.ListProviderProfilesRequest - (*GetProviderProfileRequest)(nil), // 120: openshell.v1.GetProviderProfileRequest - (*ProviderProfileImportItem)(nil), // 121: openshell.v1.ProviderProfileImportItem - (*ProviderProfileDiagnostic)(nil), // 122: openshell.v1.ProviderProfileDiagnostic - (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 123: openshell.v1.ProviderCredentialTokenGrantAudienceOverride - (*ProviderCredentialTokenGrantSubjectToken)(nil), // 124: openshell.v1.ProviderCredentialTokenGrantSubjectToken - (*ProviderCredentialTokenGrant)(nil), // 125: openshell.v1.ProviderCredentialTokenGrant - (*ProviderProfileCredential)(nil), // 126: openshell.v1.ProviderProfileCredential - (*ProviderCredentialRefreshMaterial)(nil), // 127: openshell.v1.ProviderCredentialRefreshMaterial - (*ProviderCredentialRefreshOutput)(nil), // 128: openshell.v1.ProviderCredentialRefreshOutput - (*ProviderCredentialRefresh)(nil), // 129: openshell.v1.ProviderCredentialRefresh - (*ProviderCredentialRefreshStatus)(nil), // 130: openshell.v1.ProviderCredentialRefreshStatus - (*ProviderProfileDiscovery)(nil), // 131: openshell.v1.ProviderProfileDiscovery - (*GetProviderRefreshStatusRequest)(nil), // 132: openshell.v1.GetProviderRefreshStatusRequest - (*GetProviderRefreshStatusResponse)(nil), // 133: openshell.v1.GetProviderRefreshStatusResponse - (*ConfigureProviderRefreshRequest)(nil), // 134: openshell.v1.ConfigureProviderRefreshRequest - (*ConfigureProviderRefreshResponse)(nil), // 135: openshell.v1.ConfigureProviderRefreshResponse - (*RotateProviderCredentialRequest)(nil), // 136: openshell.v1.RotateProviderCredentialRequest - (*RotateProviderCredentialResponse)(nil), // 137: openshell.v1.RotateProviderCredentialResponse - (*DeleteProviderRefreshRequest)(nil), // 138: openshell.v1.DeleteProviderRefreshRequest - (*DeleteProviderRefreshResponse)(nil), // 139: openshell.v1.DeleteProviderRefreshResponse - (*ProviderProfile)(nil), // 140: openshell.v1.ProviderProfile - (*ProviderProfileFile)(nil), // 141: openshell.v1.ProviderProfileFile - (*ProviderProfileResponse)(nil), // 142: openshell.v1.ProviderProfileResponse - (*ListProviderProfilesResponse)(nil), // 143: openshell.v1.ListProviderProfilesResponse - (*ImportProviderProfilesRequest)(nil), // 144: openshell.v1.ImportProviderProfilesRequest - (*ImportProviderProfilesResponse)(nil), // 145: openshell.v1.ImportProviderProfilesResponse - (*UpdateProviderProfilesRequest)(nil), // 146: openshell.v1.UpdateProviderProfilesRequest - (*UpdateProviderProfilesResponse)(nil), // 147: openshell.v1.UpdateProviderProfilesResponse - (*LintProviderProfilesRequest)(nil), // 148: openshell.v1.LintProviderProfilesRequest - (*LintProviderProfilesResponse)(nil), // 149: openshell.v1.LintProviderProfilesResponse - (*DeleteProviderResponse)(nil), // 150: openshell.v1.DeleteProviderResponse - (*DeleteProviderProfileRequest)(nil), // 151: openshell.v1.DeleteProviderProfileRequest - (*DeleteProviderProfileResponse)(nil), // 152: openshell.v1.DeleteProviderProfileResponse - (*GetSandboxProviderEnvironmentRequest)(nil), // 153: openshell.v1.GetSandboxProviderEnvironmentRequest - (*StaticCredentialEndpointBinding)(nil), // 154: openshell.v1.StaticCredentialEndpointBinding - (*StaticCredentialBinding)(nil), // 155: openshell.v1.StaticCredentialBinding - (*GetSandboxProviderEnvironmentResponse)(nil), // 156: openshell.v1.GetSandboxProviderEnvironmentResponse - (*ExchangeProviderSubjectTokenRequest)(nil), // 157: openshell.v1.ExchangeProviderSubjectTokenRequest - (*ExchangeProviderSubjectTokenResponse)(nil), // 158: openshell.v1.ExchangeProviderSubjectTokenResponse - (*UpdateConfigRequest)(nil), // 159: openshell.v1.UpdateConfigRequest - (*PolicyMergeOperation)(nil), // 160: openshell.v1.PolicyMergeOperation - (*AddNetworkRule)(nil), // 161: openshell.v1.AddNetworkRule - (*RemoveNetworkEndpoint)(nil), // 162: openshell.v1.RemoveNetworkEndpoint - (*RemoveNetworkRule)(nil), // 163: openshell.v1.RemoveNetworkRule - (*L7RuleTarget)(nil), // 164: openshell.v1.L7RuleTarget - (*AddDenyRules)(nil), // 165: openshell.v1.AddDenyRules - (*AddAllowRules)(nil), // 166: openshell.v1.AddAllowRules - (*RemoveNetworkBinary)(nil), // 167: openshell.v1.RemoveNetworkBinary - (*UpdateConfigResponse)(nil), // 168: openshell.v1.UpdateConfigResponse - (*GetSandboxPolicyStatusRequest)(nil), // 169: openshell.v1.GetSandboxPolicyStatusRequest - (*GetSandboxPolicyStatusResponse)(nil), // 170: openshell.v1.GetSandboxPolicyStatusResponse - (*ListSandboxPoliciesRequest)(nil), // 171: openshell.v1.ListSandboxPoliciesRequest - (*ListSandboxPoliciesResponse)(nil), // 172: openshell.v1.ListSandboxPoliciesResponse - (*ReportPolicyStatusRequest)(nil), // 173: openshell.v1.ReportPolicyStatusRequest - (*ReportPolicyStatusResponse)(nil), // 174: openshell.v1.ReportPolicyStatusResponse - (*SandboxConfigurationAdmission)(nil), // 175: openshell.v1.SandboxConfigurationAdmission - (*ReportSandboxConfigurationRequest)(nil), // 176: openshell.v1.ReportSandboxConfigurationRequest - (*ReportSandboxConfigurationResponse)(nil), // 177: openshell.v1.ReportSandboxConfigurationResponse - (*SandboxPolicyRevision)(nil), // 178: openshell.v1.SandboxPolicyRevision - (*GetSandboxLogsRequest)(nil), // 179: openshell.v1.GetSandboxLogsRequest - (*PushSandboxLogsRequest)(nil), // 180: openshell.v1.PushSandboxLogsRequest - (*PushSandboxLogsResponse)(nil), // 181: openshell.v1.PushSandboxLogsResponse - (*GetSandboxLogsResponse)(nil), // 182: openshell.v1.GetSandboxLogsResponse - (*SupervisorMessage)(nil), // 183: openshell.v1.SupervisorMessage - (*GatewayMessage)(nil), // 184: openshell.v1.GatewayMessage - (*SupervisorHello)(nil), // 185: openshell.v1.SupervisorHello - (*SessionAccepted)(nil), // 186: openshell.v1.SessionAccepted - (*SessionRejected)(nil), // 187: openshell.v1.SessionRejected - (*SupervisorHeartbeat)(nil), // 188: openshell.v1.SupervisorHeartbeat - (*GatewayHeartbeat)(nil), // 189: openshell.v1.GatewayHeartbeat - (*ReportMainProcessExitRequest)(nil), // 190: openshell.v1.ReportMainProcessExitRequest - (*ReportMainProcessExitResponse)(nil), // 191: openshell.v1.ReportMainProcessExitResponse - (*FinalizeMainProcessExitRequest)(nil), // 192: openshell.v1.FinalizeMainProcessExitRequest - (*FinalizeMainProcessExitResponse)(nil), // 193: openshell.v1.FinalizeMainProcessExitResponse - (*RelayOpen)(nil), // 194: openshell.v1.RelayOpen - (*SshRelayTarget)(nil), // 195: openshell.v1.SshRelayTarget - (*TcpRelayTarget)(nil), // 196: openshell.v1.TcpRelayTarget - (*RelayInit)(nil), // 197: openshell.v1.RelayInit - (*RelayFrame)(nil), // 198: openshell.v1.RelayFrame - (*PeerRelayInit)(nil), // 199: openshell.v1.PeerRelayInit - (*PeerRelayFrame)(nil), // 200: openshell.v1.PeerRelayFrame - (*RelayOpenResult)(nil), // 201: openshell.v1.RelayOpenResult - (*RelayClose)(nil), // 202: openshell.v1.RelayClose - (*L7RequestSample)(nil), // 203: openshell.v1.L7RequestSample - (*DenialSummary)(nil), // 204: openshell.v1.DenialSummary - (*DenialGroupCount)(nil), // 205: openshell.v1.DenialGroupCount - (*NetworkActivitySummary)(nil), // 206: openshell.v1.NetworkActivitySummary - (*PolicyChunk)(nil), // 207: openshell.v1.PolicyChunk - (*DraftPolicyUpdate)(nil), // 208: openshell.v1.DraftPolicyUpdate - (*SubmitPolicyAnalysisRequest)(nil), // 209: openshell.v1.SubmitPolicyAnalysisRequest - (*SubmitPolicyAnalysisResponse)(nil), // 210: openshell.v1.SubmitPolicyAnalysisResponse - (*GetDraftPolicyRequest)(nil), // 211: openshell.v1.GetDraftPolicyRequest - (*GetDraftPolicyResponse)(nil), // 212: openshell.v1.GetDraftPolicyResponse - (*ApproveDraftChunkRequest)(nil), // 213: openshell.v1.ApproveDraftChunkRequest - (*ApproveDraftChunkResponse)(nil), // 214: openshell.v1.ApproveDraftChunkResponse - (*RejectDraftChunkRequest)(nil), // 215: openshell.v1.RejectDraftChunkRequest - (*RejectDraftChunkResponse)(nil), // 216: openshell.v1.RejectDraftChunkResponse - (*DraftChunkApproval)(nil), // 217: openshell.v1.DraftChunkApproval - (*ApproveAllDraftChunksRequest)(nil), // 218: openshell.v1.ApproveAllDraftChunksRequest - (*ApproveAllDraftChunksResponse)(nil), // 219: openshell.v1.ApproveAllDraftChunksResponse - (*EditDraftChunkRequest)(nil), // 220: openshell.v1.EditDraftChunkRequest - (*EditDraftChunkResponse)(nil), // 221: openshell.v1.EditDraftChunkResponse - (*UndoDraftChunkRequest)(nil), // 222: openshell.v1.UndoDraftChunkRequest - (*UndoDraftChunkResponse)(nil), // 223: openshell.v1.UndoDraftChunkResponse - (*ClearDraftChunksRequest)(nil), // 224: openshell.v1.ClearDraftChunksRequest - (*ClearDraftChunksResponse)(nil), // 225: openshell.v1.ClearDraftChunksResponse - (*GetDraftHistoryRequest)(nil), // 226: openshell.v1.GetDraftHistoryRequest - (*DraftHistoryEntry)(nil), // 227: openshell.v1.DraftHistoryEntry - (*GetDraftHistoryResponse)(nil), // 228: openshell.v1.GetDraftHistoryResponse - (*CreateWorkspaceRequest)(nil), // 229: openshell.v1.CreateWorkspaceRequest - (*CreateWorkspaceResponse)(nil), // 230: openshell.v1.CreateWorkspaceResponse - (*GetWorkspaceRequest)(nil), // 231: openshell.v1.GetWorkspaceRequest - (*GetWorkspaceResponse)(nil), // 232: openshell.v1.GetWorkspaceResponse - (*ListWorkspacesRequest)(nil), // 233: openshell.v1.ListWorkspacesRequest - (*ListWorkspacesResponse)(nil), // 234: openshell.v1.ListWorkspacesResponse - (*DeleteWorkspaceRequest)(nil), // 235: openshell.v1.DeleteWorkspaceRequest - (*DeleteWorkspaceResponse)(nil), // 236: openshell.v1.DeleteWorkspaceResponse - (*WorkspaceMember)(nil), // 237: openshell.v1.WorkspaceMember - (*AddWorkspaceMemberRequest)(nil), // 238: openshell.v1.AddWorkspaceMemberRequest - (*AddWorkspaceMemberResponse)(nil), // 239: openshell.v1.AddWorkspaceMemberResponse - (*RemoveWorkspaceMemberRequest)(nil), // 240: openshell.v1.RemoveWorkspaceMemberRequest - (*RemoveWorkspaceMemberResponse)(nil), // 241: openshell.v1.RemoveWorkspaceMemberResponse - (*ListWorkspaceMembersRequest)(nil), // 242: openshell.v1.ListWorkspaceMembersRequest - (*ListWorkspaceMembersResponse)(nil), // 243: openshell.v1.ListWorkspaceMembersResponse - (*ExtensionServiceCredential)(nil), // 244: openshell.v1.ExtensionServiceCredential - (*EndpointObservation)(nil), // 245: openshell.v1.EndpointObservation - (*ReportEndpointStatusRequest)(nil), // 246: openshell.v1.ReportEndpointStatusRequest - (*ReportEndpointStatusResponse)(nil), // 247: openshell.v1.ReportEndpointStatusResponse - (*EndpointStatus)(nil), // 248: openshell.v1.EndpointStatus - (*SandboxProvisioning)(nil), // 249: openshell.v1.SandboxProvisioning - (*SandboxServiceExposure)(nil), // 250: openshell.v1.SandboxServiceExposure - nil, // 251: openshell.v1.SandboxSpec.EnvironmentEntry - nil, // 252: openshell.v1.SandboxTemplate.LabelsEntry - nil, // 253: openshell.v1.SandboxTemplate.AnnotationsEntry - nil, // 254: openshell.v1.SandboxTemplate.EnvironmentEntry - nil, // 255: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - nil, // 256: openshell.v1.PlatformEvent.MetadataEntry - nil, // 257: openshell.v1.CreateSandboxRequest.LabelsEntry - nil, // 258: openshell.v1.CreateSandboxRequest.AnnotationsEntry - nil, // 259: openshell.v1.SandboxResponse.ServiceUrlsEntry - nil, // 260: openshell.v1.ExecSandboxRequest.EnvironmentEntry - nil, // 261: openshell.v1.SandboxLogLine.FieldsEntry - nil, // 262: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - nil, // 263: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - nil, // 264: openshell.v1.ProviderProfile.AnnotationsEntry - nil, // 265: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - nil, // 266: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - nil, // 267: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - nil, // 268: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - nil, // 269: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - nil, // 270: openshell.v1.UpdateConfigRequest.AnnotationsEntry - nil, // 271: openshell.v1.UpdateConfigResponse.AnnotationsEntry - nil, // 272: openshell.v1.SandboxPolicyRevision.ProvenanceEntry - nil, // 273: openshell.v1.CreateWorkspaceRequest.LabelsEntry - (*timestamppb.Timestamp)(nil), // 274: google.protobuf.Timestamp - (*datamodelv1.ObjectMeta)(nil), // 275: openshell.datamodel.v1.ObjectMeta - (*sandboxv1.SandboxPolicy)(nil), // 276: openshell.sandbox.v1.SandboxPolicy - (*structpb.Struct)(nil), // 277: google.protobuf.Struct - (*durationpb.Duration)(nil), // 278: google.protobuf.Duration - (*datamodelv1.WorkspaceSelector)(nil), // 279: openshell.datamodel.v1.WorkspaceSelector - (*datamodelv1.Provider)(nil), // 280: openshell.datamodel.v1.Provider - (sandboxv1.PolicySource)(0), // 281: openshell.sandbox.v1.PolicySource - (*sandboxv1.NetworkEndpoint)(nil), // 282: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 283: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 284: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 285: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 286: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 287: openshell.sandbox.v1.L7Rule - (*datamodelv1.Workspace)(nil), // 288: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 289: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 290: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 291: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 292: openshell.sandbox.v1.GetGatewayConfigResponse + (ServiceAuthorizationMode)(0), // 19: openshell.v1.ServiceAuthorizationMode + (*IssueSandboxTokenRequest)(nil), // 20: openshell.v1.IssueSandboxTokenRequest + (*IssueSandboxTokenResponse)(nil), // 21: openshell.v1.IssueSandboxTokenResponse + (*RefreshSandboxTokenRequest)(nil), // 22: openshell.v1.RefreshSandboxTokenRequest + (*RefreshSandboxTokenResponse)(nil), // 23: openshell.v1.RefreshSandboxTokenResponse + (*HealthRequest)(nil), // 24: openshell.v1.HealthRequest + (*HealthResponse)(nil), // 25: openshell.v1.HealthResponse + (*GetCurrentUserRequest)(nil), // 26: openshell.v1.GetCurrentUserRequest + (*GetCurrentUserResponse)(nil), // 27: openshell.v1.GetCurrentUserResponse + (*GetGatewayInfoRequest)(nil), // 28: openshell.v1.GetGatewayInfoRequest + (*GetGatewayInfoResponse)(nil), // 29: openshell.v1.GetGatewayInfoResponse + (*NegotiatedExtensionInfo)(nil), // 30: openshell.v1.NegotiatedExtensionInfo + (*ComputeDriverInfo)(nil), // 31: openshell.v1.ComputeDriverInfo + (*ComputeDriverCapabilities)(nil), // 32: openshell.v1.ComputeDriverCapabilities + (*ResourceCapabilities)(nil), // 33: openshell.v1.ResourceCapabilities + (*CpuResourceCapabilities)(nil), // 34: openshell.v1.CpuResourceCapabilities + (*MemoryResourceCapabilities)(nil), // 35: openshell.v1.MemoryResourceCapabilities + (*GpuResourceCapabilities)(nil), // 36: openshell.v1.GpuResourceCapabilities + (*Sandbox)(nil), // 37: openshell.v1.Sandbox + (*SandboxSpec)(nil), // 38: openshell.v1.SandboxSpec + (*ResourceRequirements)(nil), // 39: openshell.v1.ResourceRequirements + (*GpuResourceRequirements)(nil), // 40: openshell.v1.GpuResourceRequirements + (*SandboxTemplate)(nil), // 41: openshell.v1.SandboxTemplate + (*SandboxWorkloadTemplate)(nil), // 42: openshell.v1.SandboxWorkloadTemplate + (*SandboxWorkloadTemplateSpec)(nil), // 43: openshell.v1.SandboxWorkloadTemplateSpec + (*SandboxWorkloadConfig)(nil), // 44: openshell.v1.SandboxWorkloadConfig + (*SandboxResources)(nil), // 45: openshell.v1.SandboxResources + (*SandboxServiceLevel)(nil), // 46: openshell.v1.SandboxServiceLevel + (*SandboxStartup)(nil), // 47: openshell.v1.SandboxStartup + (*SandboxWorkloadTemplateProvenance)(nil), // 48: openshell.v1.SandboxWorkloadTemplateProvenance + (*SandboxStatus)(nil), // 49: openshell.v1.SandboxStatus + (*SandboxCondition)(nil), // 50: openshell.v1.SandboxCondition + (*PlatformEvent)(nil), // 51: openshell.v1.PlatformEvent + (*CreateSandboxRequest)(nil), // 52: openshell.v1.CreateSandboxRequest + (*CreateSandboxTemplateRequest)(nil), // 53: openshell.v1.CreateSandboxTemplateRequest + (*GetSandboxTemplateRequest)(nil), // 54: openshell.v1.GetSandboxTemplateRequest + (*ListSandboxTemplatesRequest)(nil), // 55: openshell.v1.ListSandboxTemplatesRequest + (*DeleteSandboxTemplateRequest)(nil), // 56: openshell.v1.DeleteSandboxTemplateRequest + (*SandboxTemplateResponse)(nil), // 57: openshell.v1.SandboxTemplateResponse + (*ListSandboxTemplatesResponse)(nil), // 58: openshell.v1.ListSandboxTemplatesResponse + (*DeleteSandboxTemplateResponse)(nil), // 59: openshell.v1.DeleteSandboxTemplateResponse + (*BeginRootfsTarStagingRequest)(nil), // 60: openshell.v1.BeginRootfsTarStagingRequest + (*BeginRootfsTarStagingResponse)(nil), // 61: openshell.v1.BeginRootfsTarStagingResponse + (*GetSandboxRequest)(nil), // 62: openshell.v1.GetSandboxRequest + (*ListSandboxesRequest)(nil), // 63: openshell.v1.ListSandboxesRequest + (*ListSandboxProvidersRequest)(nil), // 64: openshell.v1.ListSandboxProvidersRequest + (*AttachSandboxProviderRequest)(nil), // 65: openshell.v1.AttachSandboxProviderRequest + (*DetachSandboxProviderRequest)(nil), // 66: openshell.v1.DetachSandboxProviderRequest + (*DeleteSandboxRequest)(nil), // 67: openshell.v1.DeleteSandboxRequest + (*StopSandboxRequest)(nil), // 68: openshell.v1.StopSandboxRequest + (*StartSandboxRequest)(nil), // 69: openshell.v1.StartSandboxRequest + (*SandboxResponse)(nil), // 70: openshell.v1.SandboxResponse + (*ListSandboxesResponse)(nil), // 71: openshell.v1.ListSandboxesResponse + (*ListSandboxProvidersResponse)(nil), // 72: openshell.v1.ListSandboxProvidersResponse + (*AttachSandboxProviderResponse)(nil), // 73: openshell.v1.AttachSandboxProviderResponse + (*DetachSandboxProviderResponse)(nil), // 74: openshell.v1.DetachSandboxProviderResponse + (*ProviderDesiredIdentity)(nil), // 75: openshell.v1.ProviderDesiredIdentity + (*ConfigSnapshotRevision)(nil), // 76: openshell.v1.ConfigSnapshotRevision + (*SandboxConfigRevision)(nil), // 77: openshell.v1.SandboxConfigRevision + (*ConfigUpdateOperation)(nil), // 78: openshell.v1.ConfigUpdateOperation + (*ProviderMutationReceipt)(nil), // 79: openshell.v1.ProviderMutationReceipt + (*ProviderReadinessObservation)(nil), // 80: openshell.v1.ProviderReadinessObservation + (*ProviderReadinessStatus)(nil), // 81: openshell.v1.ProviderReadinessStatus + (*GetSandboxProviderStatusRequest)(nil), // 82: openshell.v1.GetSandboxProviderStatusRequest + (*GetSandboxProviderStatusResponse)(nil), // 83: openshell.v1.GetSandboxProviderStatusResponse + (*ReportProviderReadinessRequest)(nil), // 84: openshell.v1.ReportProviderReadinessRequest + (*ReportProviderReadinessResponse)(nil), // 85: openshell.v1.ReportProviderReadinessResponse + (*DeleteSandboxResponse)(nil), // 86: openshell.v1.DeleteSandboxResponse + (*CreateSshSessionRequest)(nil), // 87: openshell.v1.CreateSshSessionRequest + (*CreateSshSessionResponse)(nil), // 88: openshell.v1.CreateSshSessionResponse + (*ExposeServiceRequest)(nil), // 89: openshell.v1.ExposeServiceRequest + (*GetServiceRequest)(nil), // 90: openshell.v1.GetServiceRequest + (*ListServicesRequest)(nil), // 91: openshell.v1.ListServicesRequest + (*ListServicesResponse)(nil), // 92: openshell.v1.ListServicesResponse + (*DeleteServiceRequest)(nil), // 93: openshell.v1.DeleteServiceRequest + (*DeleteServiceResponse)(nil), // 94: openshell.v1.DeleteServiceResponse + (*ServiceEndpoint)(nil), // 95: openshell.v1.ServiceEndpoint + (*ServiceEndpointResponse)(nil), // 96: openshell.v1.ServiceEndpointResponse + (*RevokeSshSessionRequest)(nil), // 97: openshell.v1.RevokeSshSessionRequest + (*RevokeSshSessionResponse)(nil), // 98: openshell.v1.RevokeSshSessionResponse + (*ExecSandboxRequest)(nil), // 99: openshell.v1.ExecSandboxRequest + (*ExecSandboxStdout)(nil), // 100: openshell.v1.ExecSandboxStdout + (*ExecSandboxStderr)(nil), // 101: openshell.v1.ExecSandboxStderr + (*ExecSandboxExit)(nil), // 102: openshell.v1.ExecSandboxExit + (*ExecSandboxEvent)(nil), // 103: openshell.v1.ExecSandboxEvent + (*TcpForwardInit)(nil), // 104: openshell.v1.TcpForwardInit + (*TcpForwardFrame)(nil), // 105: openshell.v1.TcpForwardFrame + (*ExecSandboxInput)(nil), // 106: openshell.v1.ExecSandboxInput + (*ExecSandboxWindowResize)(nil), // 107: openshell.v1.ExecSandboxWindowResize + (*SshSession)(nil), // 108: openshell.v1.SshSession + (*WatchSandboxRequest)(nil), // 109: openshell.v1.WatchSandboxRequest + (*SandboxStreamEvent)(nil), // 110: openshell.v1.SandboxStreamEvent + (*SandboxLogLine)(nil), // 111: openshell.v1.SandboxLogLine + (*SandboxStreamWarning)(nil), // 112: openshell.v1.SandboxStreamWarning + (*CreateProviderRequest)(nil), // 113: openshell.v1.CreateProviderRequest + (*GetProviderRequest)(nil), // 114: openshell.v1.GetProviderRequest + (*ListProvidersRequest)(nil), // 115: openshell.v1.ListProvidersRequest + (*UpdateProviderRequest)(nil), // 116: openshell.v1.UpdateProviderRequest + (*DeleteProviderRequest)(nil), // 117: openshell.v1.DeleteProviderRequest + (*ProviderResponse)(nil), // 118: openshell.v1.ProviderResponse + (*ListProvidersResponse)(nil), // 119: openshell.v1.ListProvidersResponse + (*ListProviderProfilesRequest)(nil), // 120: openshell.v1.ListProviderProfilesRequest + (*GetProviderProfileRequest)(nil), // 121: openshell.v1.GetProviderProfileRequest + (*ProviderProfileImportItem)(nil), // 122: openshell.v1.ProviderProfileImportItem + (*ProviderProfileDiagnostic)(nil), // 123: openshell.v1.ProviderProfileDiagnostic + (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 124: openshell.v1.ProviderCredentialTokenGrantAudienceOverride + (*ProviderCredentialTokenGrantSubjectToken)(nil), // 125: openshell.v1.ProviderCredentialTokenGrantSubjectToken + (*ProviderCredentialTokenGrant)(nil), // 126: openshell.v1.ProviderCredentialTokenGrant + (*ProviderProfileCredential)(nil), // 127: openshell.v1.ProviderProfileCredential + (*ProviderCredentialRefreshMaterial)(nil), // 128: openshell.v1.ProviderCredentialRefreshMaterial + (*ProviderCredentialRefreshOutput)(nil), // 129: openshell.v1.ProviderCredentialRefreshOutput + (*ProviderCredentialRefresh)(nil), // 130: openshell.v1.ProviderCredentialRefresh + (*ProviderCredentialRefreshStatus)(nil), // 131: openshell.v1.ProviderCredentialRefreshStatus + (*ProviderProfileDiscovery)(nil), // 132: openshell.v1.ProviderProfileDiscovery + (*GetProviderRefreshStatusRequest)(nil), // 133: openshell.v1.GetProviderRefreshStatusRequest + (*GetProviderRefreshStatusResponse)(nil), // 134: openshell.v1.GetProviderRefreshStatusResponse + (*ConfigureProviderRefreshRequest)(nil), // 135: openshell.v1.ConfigureProviderRefreshRequest + (*ConfigureProviderRefreshResponse)(nil), // 136: openshell.v1.ConfigureProviderRefreshResponse + (*RotateProviderCredentialRequest)(nil), // 137: openshell.v1.RotateProviderCredentialRequest + (*RotateProviderCredentialResponse)(nil), // 138: openshell.v1.RotateProviderCredentialResponse + (*DeleteProviderRefreshRequest)(nil), // 139: openshell.v1.DeleteProviderRefreshRequest + (*DeleteProviderRefreshResponse)(nil), // 140: openshell.v1.DeleteProviderRefreshResponse + (*ProviderProfile)(nil), // 141: openshell.v1.ProviderProfile + (*ProviderProfileFile)(nil), // 142: openshell.v1.ProviderProfileFile + (*ProviderProfileResponse)(nil), // 143: openshell.v1.ProviderProfileResponse + (*ListProviderProfilesResponse)(nil), // 144: openshell.v1.ListProviderProfilesResponse + (*ImportProviderProfilesRequest)(nil), // 145: openshell.v1.ImportProviderProfilesRequest + (*ImportProviderProfilesResponse)(nil), // 146: openshell.v1.ImportProviderProfilesResponse + (*UpdateProviderProfilesRequest)(nil), // 147: openshell.v1.UpdateProviderProfilesRequest + (*UpdateProviderProfilesResponse)(nil), // 148: openshell.v1.UpdateProviderProfilesResponse + (*LintProviderProfilesRequest)(nil), // 149: openshell.v1.LintProviderProfilesRequest + (*LintProviderProfilesResponse)(nil), // 150: openshell.v1.LintProviderProfilesResponse + (*DeleteProviderResponse)(nil), // 151: openshell.v1.DeleteProviderResponse + (*DeleteProviderProfileRequest)(nil), // 152: openshell.v1.DeleteProviderProfileRequest + (*DeleteProviderProfileResponse)(nil), // 153: openshell.v1.DeleteProviderProfileResponse + (*GetSandboxProviderEnvironmentRequest)(nil), // 154: openshell.v1.GetSandboxProviderEnvironmentRequest + (*StaticCredentialEndpointBinding)(nil), // 155: openshell.v1.StaticCredentialEndpointBinding + (*StaticCredentialBinding)(nil), // 156: openshell.v1.StaticCredentialBinding + (*GetSandboxProviderEnvironmentResponse)(nil), // 157: openshell.v1.GetSandboxProviderEnvironmentResponse + (*ExchangeProviderSubjectTokenRequest)(nil), // 158: openshell.v1.ExchangeProviderSubjectTokenRequest + (*ExchangeProviderSubjectTokenResponse)(nil), // 159: openshell.v1.ExchangeProviderSubjectTokenResponse + (*UpdateConfigRequest)(nil), // 160: openshell.v1.UpdateConfigRequest + (*PolicyMergeOperation)(nil), // 161: openshell.v1.PolicyMergeOperation + (*AddNetworkRule)(nil), // 162: openshell.v1.AddNetworkRule + (*RemoveNetworkEndpoint)(nil), // 163: openshell.v1.RemoveNetworkEndpoint + (*RemoveNetworkRule)(nil), // 164: openshell.v1.RemoveNetworkRule + (*L7RuleTarget)(nil), // 165: openshell.v1.L7RuleTarget + (*AddDenyRules)(nil), // 166: openshell.v1.AddDenyRules + (*AddAllowRules)(nil), // 167: openshell.v1.AddAllowRules + (*RemoveNetworkBinary)(nil), // 168: openshell.v1.RemoveNetworkBinary + (*UpdateConfigResponse)(nil), // 169: openshell.v1.UpdateConfigResponse + (*GetSandboxPolicyStatusRequest)(nil), // 170: openshell.v1.GetSandboxPolicyStatusRequest + (*GetSandboxPolicyStatusResponse)(nil), // 171: openshell.v1.GetSandboxPolicyStatusResponse + (*ListSandboxPoliciesRequest)(nil), // 172: openshell.v1.ListSandboxPoliciesRequest + (*ListSandboxPoliciesResponse)(nil), // 173: openshell.v1.ListSandboxPoliciesResponse + (*ReportPolicyStatusRequest)(nil), // 174: openshell.v1.ReportPolicyStatusRequest + (*ReportPolicyStatusResponse)(nil), // 175: openshell.v1.ReportPolicyStatusResponse + (*SandboxConfigurationAdmission)(nil), // 176: openshell.v1.SandboxConfigurationAdmission + (*ReportSandboxConfigurationRequest)(nil), // 177: openshell.v1.ReportSandboxConfigurationRequest + (*ReportSandboxConfigurationResponse)(nil), // 178: openshell.v1.ReportSandboxConfigurationResponse + (*SandboxPolicyRevision)(nil), // 179: openshell.v1.SandboxPolicyRevision + (*GetSandboxLogsRequest)(nil), // 180: openshell.v1.GetSandboxLogsRequest + (*PushSandboxLogsRequest)(nil), // 181: openshell.v1.PushSandboxLogsRequest + (*PushSandboxLogsResponse)(nil), // 182: openshell.v1.PushSandboxLogsResponse + (*GetSandboxLogsResponse)(nil), // 183: openshell.v1.GetSandboxLogsResponse + (*SupervisorMessage)(nil), // 184: openshell.v1.SupervisorMessage + (*GatewayMessage)(nil), // 185: openshell.v1.GatewayMessage + (*SupervisorHello)(nil), // 186: openshell.v1.SupervisorHello + (*SessionAccepted)(nil), // 187: openshell.v1.SessionAccepted + (*SessionRejected)(nil), // 188: openshell.v1.SessionRejected + (*SupervisorHeartbeat)(nil), // 189: openshell.v1.SupervisorHeartbeat + (*GatewayHeartbeat)(nil), // 190: openshell.v1.GatewayHeartbeat + (*ReportMainProcessExitRequest)(nil), // 191: openshell.v1.ReportMainProcessExitRequest + (*ReportMainProcessExitResponse)(nil), // 192: openshell.v1.ReportMainProcessExitResponse + (*FinalizeMainProcessExitRequest)(nil), // 193: openshell.v1.FinalizeMainProcessExitRequest + (*FinalizeMainProcessExitResponse)(nil), // 194: openshell.v1.FinalizeMainProcessExitResponse + (*RelayOpen)(nil), // 195: openshell.v1.RelayOpen + (*SshRelayTarget)(nil), // 196: openshell.v1.SshRelayTarget + (*TcpRelayTarget)(nil), // 197: openshell.v1.TcpRelayTarget + (*RelayInit)(nil), // 198: openshell.v1.RelayInit + (*RelayFrame)(nil), // 199: openshell.v1.RelayFrame + (*PeerRelayInit)(nil), // 200: openshell.v1.PeerRelayInit + (*PeerRelayFrame)(nil), // 201: openshell.v1.PeerRelayFrame + (*RelayOpenResult)(nil), // 202: openshell.v1.RelayOpenResult + (*RelayClose)(nil), // 203: openshell.v1.RelayClose + (*L7RequestSample)(nil), // 204: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 205: openshell.v1.DenialSummary + (*DenialGroupCount)(nil), // 206: openshell.v1.DenialGroupCount + (*NetworkActivitySummary)(nil), // 207: openshell.v1.NetworkActivitySummary + (*PolicyChunk)(nil), // 208: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 209: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 210: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 211: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 212: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 213: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 214: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 215: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 216: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 217: openshell.v1.RejectDraftChunkResponse + (*DraftChunkApproval)(nil), // 218: openshell.v1.DraftChunkApproval + (*ApproveAllDraftChunksRequest)(nil), // 219: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 220: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 221: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 222: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 223: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 224: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 225: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 226: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 227: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 228: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 229: openshell.v1.GetDraftHistoryResponse + (*CreateWorkspaceRequest)(nil), // 230: openshell.v1.CreateWorkspaceRequest + (*CreateWorkspaceResponse)(nil), // 231: openshell.v1.CreateWorkspaceResponse + (*GetWorkspaceRequest)(nil), // 232: openshell.v1.GetWorkspaceRequest + (*GetWorkspaceResponse)(nil), // 233: openshell.v1.GetWorkspaceResponse + (*ListWorkspacesRequest)(nil), // 234: openshell.v1.ListWorkspacesRequest + (*ListWorkspacesResponse)(nil), // 235: openshell.v1.ListWorkspacesResponse + (*DeleteWorkspaceRequest)(nil), // 236: openshell.v1.DeleteWorkspaceRequest + (*DeleteWorkspaceResponse)(nil), // 237: openshell.v1.DeleteWorkspaceResponse + (*WorkspaceMember)(nil), // 238: openshell.v1.WorkspaceMember + (*AddWorkspaceMemberRequest)(nil), // 239: openshell.v1.AddWorkspaceMemberRequest + (*AddWorkspaceMemberResponse)(nil), // 240: openshell.v1.AddWorkspaceMemberResponse + (*RemoveWorkspaceMemberRequest)(nil), // 241: openshell.v1.RemoveWorkspaceMemberRequest + (*RemoveWorkspaceMemberResponse)(nil), // 242: openshell.v1.RemoveWorkspaceMemberResponse + (*ListWorkspaceMembersRequest)(nil), // 243: openshell.v1.ListWorkspaceMembersRequest + (*ListWorkspaceMembersResponse)(nil), // 244: openshell.v1.ListWorkspaceMembersResponse + (*ExtensionServiceCredential)(nil), // 245: openshell.v1.ExtensionServiceCredential + (*EndpointObservation)(nil), // 246: openshell.v1.EndpointObservation + (*ReportEndpointStatusRequest)(nil), // 247: openshell.v1.ReportEndpointStatusRequest + (*ReportEndpointStatusResponse)(nil), // 248: openshell.v1.ReportEndpointStatusResponse + (*EndpointStatus)(nil), // 249: openshell.v1.EndpointStatus + (*SandboxProvisioning)(nil), // 250: openshell.v1.SandboxProvisioning + (*SandboxServiceExposure)(nil), // 251: openshell.v1.SandboxServiceExposure + nil, // 252: openshell.v1.SandboxSpec.EnvironmentEntry + nil, // 253: openshell.v1.SandboxTemplate.LabelsEntry + nil, // 254: openshell.v1.SandboxTemplate.AnnotationsEntry + nil, // 255: openshell.v1.SandboxTemplate.EnvironmentEntry + nil, // 256: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + nil, // 257: openshell.v1.PlatformEvent.MetadataEntry + nil, // 258: openshell.v1.CreateSandboxRequest.LabelsEntry + nil, // 259: openshell.v1.CreateSandboxRequest.AnnotationsEntry + nil, // 260: openshell.v1.SandboxResponse.ServiceUrlsEntry + nil, // 261: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 262: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 263: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + nil, // 264: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + nil, // 265: openshell.v1.ProviderProfile.AnnotationsEntry + nil, // 266: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + nil, // 267: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + nil, // 268: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + nil, // 269: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + nil, // 270: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + nil, // 271: openshell.v1.UpdateConfigRequest.AnnotationsEntry + nil, // 272: openshell.v1.UpdateConfigResponse.AnnotationsEntry + nil, // 273: openshell.v1.SandboxPolicyRevision.ProvenanceEntry + nil, // 274: openshell.v1.CreateWorkspaceRequest.LabelsEntry + (*timestamppb.Timestamp)(nil), // 275: google.protobuf.Timestamp + (*datamodelv1.ObjectMeta)(nil), // 276: openshell.datamodel.v1.ObjectMeta + (*sandboxv1.SandboxPolicy)(nil), // 277: openshell.sandbox.v1.SandboxPolicy + (*structpb.Struct)(nil), // 278: google.protobuf.Struct + (*durationpb.Duration)(nil), // 279: google.protobuf.Duration + (*datamodelv1.WorkspaceSelector)(nil), // 280: openshell.datamodel.v1.WorkspaceSelector + (*datamodelv1.Provider)(nil), // 281: openshell.datamodel.v1.Provider + (sandboxv1.PolicySource)(0), // 282: openshell.sandbox.v1.PolicySource + (*sandboxv1.NetworkEndpoint)(nil), // 283: openshell.sandbox.v1.NetworkEndpoint + (*sandboxv1.NetworkBinary)(nil), // 284: openshell.sandbox.v1.NetworkBinary + (*sandboxv1.SettingValue)(nil), // 285: openshell.sandbox.v1.SettingValue + (*sandboxv1.NetworkPolicyRule)(nil), // 286: openshell.sandbox.v1.NetworkPolicyRule + (*sandboxv1.L7DenyRule)(nil), // 287: openshell.sandbox.v1.L7DenyRule + (*sandboxv1.L7Rule)(nil), // 288: openshell.sandbox.v1.L7Rule + (*datamodelv1.Workspace)(nil), // 289: openshell.datamodel.v1.Workspace + (*sandboxv1.GetSandboxConfigRequest)(nil), // 290: openshell.sandbox.v1.GetSandboxConfigRequest + (*sandboxv1.GetGatewayConfigRequest)(nil), // 291: openshell.sandbox.v1.GetGatewayConfigRequest + (*sandboxv1.GetSandboxConfigResponse)(nil), // 292: openshell.sandbox.v1.GetSandboxConfigResponse + (*sandboxv1.GetGatewayConfigResponse)(nil), // 293: openshell.sandbox.v1.GetGatewayConfigResponse } var file_openshell_proto_depIdxs = []int32{ - 274, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 274, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 244, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential - 274, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp + 275, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 275, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 245, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential + 275, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp 13, // 4: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus 13, // 5: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus - 30, // 6: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo - 29, // 7: openshell.v1.GetGatewayInfoResponse.extensions:type_name -> openshell.v1.NegotiatedExtensionInfo + 31, // 6: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo + 30, // 7: openshell.v1.GetGatewayInfoResponse.extensions:type_name -> openshell.v1.NegotiatedExtensionInfo 0, // 8: openshell.v1.NegotiatedExtensionInfo.kind:type_name -> openshell.v1.ExtensionKind - 31, // 9: openshell.v1.ComputeDriverInfo.capabilities:type_name -> openshell.v1.ComputeDriverCapabilities - 32, // 10: openshell.v1.ComputeDriverCapabilities.resource_capabilities:type_name -> openshell.v1.ResourceCapabilities - 33, // 11: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities - 34, // 12: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities - 35, // 13: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities - 275, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 37, // 15: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec - 48, // 16: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus - 47, // 17: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance - 251, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry - 40, // 19: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate - 276, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 38, // 21: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements + 32, // 9: openshell.v1.ComputeDriverInfo.capabilities:type_name -> openshell.v1.ComputeDriverCapabilities + 33, // 10: openshell.v1.ComputeDriverCapabilities.resource_capabilities:type_name -> openshell.v1.ResourceCapabilities + 34, // 11: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities + 35, // 12: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities + 36, // 13: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities + 276, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 38, // 15: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec + 49, // 16: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus + 48, // 17: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance + 252, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry + 41, // 19: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate + 277, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 39, // 21: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements 16, // 22: openshell.v1.SandboxSpec.restart_policy:type_name -> openshell.v1.SandboxRestartPolicy - 39, // 23: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements - 252, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry - 253, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry - 254, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry - 277, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct - 277, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct - 275, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 42, // 30: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec - 43, // 31: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig - 277, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct - 45, // 33: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel - 255, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - 44, // 35: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources - 39, // 36: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements - 46, // 37: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup - 278, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration - 49, // 39: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition + 40, // 23: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements + 253, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry + 254, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry + 255, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry + 278, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 278, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct + 276, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 43, // 30: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec + 44, // 31: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig + 278, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct + 46, // 33: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel + 256, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + 45, // 35: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources + 40, // 36: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements + 47, // 37: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup + 279, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 50, // 39: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition 1, // 40: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 248, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus - 175, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 249, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning - 274, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp - 274, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp - 274, // 46: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp - 274, // 47: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp - 256, // 48: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 279, // 49: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 37, // 50: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 257, // 51: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 258, // 52: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 250, // 53: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure - 279, // 54: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 41, // 55: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 279, // 56: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 57: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 58: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 41, // 59: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 41, // 60: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate + 249, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus + 176, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 250, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning + 275, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp + 275, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp + 275, // 46: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp + 275, // 47: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp + 257, // 48: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 280, // 49: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 38, // 50: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec + 258, // 51: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 259, // 52: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 251, // 53: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure + 280, // 54: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 42, // 55: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 280, // 56: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 57: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 58: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 42, // 59: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 42, // 60: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate 17, // 61: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 279, // 62: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 274, // 63: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp - 279, // 64: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 65: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 66: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 67: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 68: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 69: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 70: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 71: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 36, // 72: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 259, // 73: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry - 36, // 74: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 280, // 75: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 36, // 76: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 78, // 77: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 36, // 78: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 78, // 79: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt - 76, // 80: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision - 74, // 81: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity - 281, // 82: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 280, // 62: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 275, // 63: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp + 280, // 64: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 65: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 66: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 67: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 68: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 69: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 70: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 71: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 37, // 72: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox + 260, // 73: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry + 37, // 74: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox + 281, // 75: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 37, // 76: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 79, // 77: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 37, // 78: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 79, // 79: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 77, // 80: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision + 75, // 81: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity + 282, // 82: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource 5, // 83: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent - 75, // 84: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision + 76, // 84: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision 7, // 85: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState 6, // 86: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 274, // 87: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp - 274, // 88: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp - 274, // 89: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp + 275, // 87: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp + 275, // 88: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp + 275, // 89: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp 2, // 90: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind - 74, // 91: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity - 274, // 92: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp + 75, // 91: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity + 275, // 92: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp 4, // 93: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason - 78, // 94: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt + 79, // 94: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt 3, // 95: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState 4, // 96: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason - 79, // 97: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation - 274, // 98: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp - 274, // 99: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp - 77, // 100: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation - 279, // 101: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 80, // 102: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus - 79, // 103: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation - 278, // 104: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration - 278, // 105: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration + 80, // 97: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation + 275, // 98: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp + 275, // 99: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp + 78, // 100: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation + 280, // 101: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 81, // 102: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus + 80, // 103: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation + 279, // 104: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration + 279, // 105: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration 17, // 106: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 279, // 107: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 274, // 108: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp - 279, // 109: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 110: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 111: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 95, // 112: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 279, // 113: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 17, // 114: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 275, // 115: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 94, // 116: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint - 17, // 117: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 279, // 118: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 260, // 119: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 278, // 120: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration - 99, // 121: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout - 100, // 122: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr - 101, // 123: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 195, // 124: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 196, // 125: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget - 103, // 126: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit - 98, // 127: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest - 106, // 128: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 275, // 129: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 274, // 130: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp - 279, // 131: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 274, // 132: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp - 36, // 133: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox - 110, // 134: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine - 50, // 135: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent - 111, // 136: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 208, // 137: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 274, // 138: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp - 261, // 139: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 279, // 140: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 280, // 141: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 279, // 142: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 143: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 144: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 280, // 145: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 262, // 146: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - 279, // 147: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 280, // 148: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider - 78, // 149: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt - 280, // 150: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 279, // 151: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 152: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 140, // 153: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 278, // 154: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration - 123, // 155: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride - 8, // 156: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType - 124, // 157: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken - 129, // 158: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh - 125, // 159: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant - 9, // 160: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 278, // 161: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration - 278, // 162: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration - 127, // 163: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial - 128, // 164: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput - 9, // 165: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 274, // 166: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp - 274, // 167: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp - 274, // 168: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp - 15, // 169: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 274, // 170: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp - 279, // 171: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 130, // 172: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 279, // 173: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 9, // 174: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 263, // 175: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 274, // 176: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp - 130, // 177: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 279, // 178: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 130, // 179: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 279, // 180: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 17, // 181: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 10, // 182: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory - 126, // 183: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 282, // 184: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 283, // 185: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 131, // 186: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 264, // 187: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 141, // 188: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile - 140, // 189: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 140, // 190: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 279, // 191: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 121, // 192: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 122, // 193: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 140, // 194: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 279, // 195: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 121, // 196: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 122, // 197: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 140, // 198: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 279, // 199: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 121, // 200: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 122, // 201: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 17, // 202: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 279, // 203: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 17, // 204: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 154, // 205: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 265, // 206: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 266, // 207: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - 267, // 208: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 268, // 209: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 4, // 210: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 269, // 211: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry - 278, // 212: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration - 279, // 213: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 276, // 214: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 284, // 215: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 160, // 216: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 270, // 217: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 161, // 218: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 162, // 219: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 163, // 220: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 165, // 221: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 166, // 222: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 167, // 223: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 285, // 224: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 283, // 225: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 286, // 226: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 164, // 227: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget - 287, // 228: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 164, // 229: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget - 271, // 230: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 279, // 231: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 178, // 232: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 279, // 233: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 178, // 234: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 12, // 235: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 11, // 236: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState - 175, // 237: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 12, // 238: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 274, // 239: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp - 274, // 240: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp - 276, // 241: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 272, // 242: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 279, // 243: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 274, // 244: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp - 110, // 245: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 110, // 246: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 185, // 247: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 188, // 248: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 201, // 249: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 202, // 250: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 186, // 251: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 187, // 252: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 189, // 253: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 194, // 254: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 202, // 255: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 278, // 256: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration - 195, // 257: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 196, // 258: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 197, // 259: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 194, // 260: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen - 199, // 261: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit - 274, // 262: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp - 274, // 263: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp - 203, // 264: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 205, // 265: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 285, // 266: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 274, // 267: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp - 274, // 268: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp - 274, // 269: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp - 274, // 270: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp - 276, // 271: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 276, // 272: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 279, // 273: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 204, // 274: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 207, // 275: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 206, // 276: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 279, // 277: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 207, // 278: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 274, // 279: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp - 279, // 280: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 281: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 282: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 217, // 283: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval - 279, // 284: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 285, // 285: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 279, // 286: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 287: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 279, // 288: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 274, // 289: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp - 227, // 290: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 273, // 291: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 288, // 292: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 288, // 293: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 288, // 294: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 17, // 295: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 275, // 296: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 14, // 297: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 279, // 298: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 14, // 299: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 237, // 300: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 279, // 301: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 17, // 302: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 279, // 303: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 237, // 304: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 274, // 305: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp - 18, // 306: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult - 245, // 307: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation - 18, // 308: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult - 274, // 309: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp - 274, // 310: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp - 274, // 311: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp - 274, // 312: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp - 274, // 313: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp - 274, // 314: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp - 274, // 315: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp - 274, // 316: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp - 274, // 317: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 274, // 318: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 126, // 319: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 155, // 320: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 23, // 321: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 25, // 322: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 27, // 323: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 51, // 324: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 59, // 325: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest - 61, // 326: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 62, // 327: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 52, // 328: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 53, // 329: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 54, // 330: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 55, // 331: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 63, // 332: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 64, // 333: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 65, // 334: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 81, // 335: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 66, // 336: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 67, // 337: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 68, // 338: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 86, // 339: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 88, // 340: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 89, // 341: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 90, // 342: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 92, // 343: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 96, // 344: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 98, // 345: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 104, // 346: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 105, // 347: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 112, // 348: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 113, // 349: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 114, // 350: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 119, // 351: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 120, // 352: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 144, // 353: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 146, // 354: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 148, // 355: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 115, // 356: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 132, // 357: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 134, // 358: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 136, // 359: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 138, // 360: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 116, // 361: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 151, // 362: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 289, // 363: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 290, // 364: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 159, // 365: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 169, // 366: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 171, // 367: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 173, // 368: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 246, // 369: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 83, // 370: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 176, // 371: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest - 153, // 372: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 157, // 373: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest - 179, // 374: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 180, // 375: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 183, // 376: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 190, // 377: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest - 192, // 378: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest - 198, // 379: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 200, // 380: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame - 83, // 381: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 246, // 382: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 81, // 383: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 108, // 384: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 209, // 385: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 211, // 386: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 213, // 387: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 215, // 388: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 218, // 389: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 220, // 390: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 222, // 391: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 224, // 392: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 226, // 393: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 19, // 394: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 21, // 395: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 229, // 396: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 231, // 397: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 233, // 398: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 235, // 399: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 238, // 400: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 240, // 401: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 242, // 402: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 24, // 403: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 26, // 404: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 28, // 405: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 69, // 406: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 60, // 407: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse - 69, // 408: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 70, // 409: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 56, // 410: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 56, // 411: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 57, // 412: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 58, // 413: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 71, // 414: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 72, // 415: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 73, // 416: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 82, // 417: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 85, // 418: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 69, // 419: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 69, // 420: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 87, // 421: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 95, // 422: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 95, // 423: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 91, // 424: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 93, // 425: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 97, // 426: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 102, // 427: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 104, // 428: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 102, // 429: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 117, // 430: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 117, // 431: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 118, // 432: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 143, // 433: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 142, // 434: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 145, // 435: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 147, // 436: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 149, // 437: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 117, // 438: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 133, // 439: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 135, // 440: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 137, // 441: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 139, // 442: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 150, // 443: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 152, // 444: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 291, // 445: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 292, // 446: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 168, // 447: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 170, // 448: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 172, // 449: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 174, // 450: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 247, // 451: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 84, // 452: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 177, // 453: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse - 156, // 454: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 158, // 455: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse - 182, // 456: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 181, // 457: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 184, // 458: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 191, // 459: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse - 193, // 460: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse - 198, // 461: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 200, // 462: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame - 84, // 463: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 247, // 464: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 82, // 465: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 109, // 466: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 210, // 467: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 212, // 468: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 214, // 469: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 216, // 470: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 219, // 471: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 221, // 472: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 223, // 473: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 225, // 474: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 228, // 475: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 20, // 476: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 22, // 477: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 230, // 478: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 232, // 479: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 234, // 480: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 236, // 481: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 239, // 482: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 241, // 483: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 243, // 484: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 403, // [403:485] is the sub-list for method output_type - 321, // [321:403] is the sub-list for method input_type - 321, // [321:321] is the sub-list for extension type_name - 321, // [321:321] is the sub-list for extension extendee - 0, // [0:321] is the sub-list for field type_name + 280, // 107: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 275, // 108: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp + 280, // 109: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 19, // 110: openshell.v1.ExposeServiceRequest.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 280, // 111: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 112: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 96, // 113: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse + 280, // 114: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 17, // 115: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 276, // 116: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 19, // 117: openshell.v1.ServiceEndpoint.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 95, // 118: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint + 17, // 119: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 280, // 120: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 261, // 121: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 279, // 122: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration + 100, // 123: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout + 101, // 124: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr + 102, // 125: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit + 196, // 126: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget + 197, // 127: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget + 104, // 128: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit + 99, // 129: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest + 107, // 130: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize + 276, // 131: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 275, // 132: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp + 280, // 133: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 275, // 134: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp + 37, // 135: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox + 111, // 136: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine + 51, // 137: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent + 112, // 138: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning + 209, // 139: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 275, // 140: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp + 262, // 141: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 280, // 142: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 281, // 143: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 280, // 144: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 145: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 146: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 281, // 147: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 263, // 148: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + 280, // 149: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 281, // 150: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 79, // 151: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt + 281, // 152: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 280, // 153: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 154: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 141, // 155: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile + 279, // 156: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration + 124, // 157: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride + 8, // 158: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType + 125, // 159: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken + 130, // 160: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh + 126, // 161: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant + 9, // 162: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 279, // 163: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration + 279, // 164: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration + 128, // 165: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial + 129, // 166: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput + 9, // 167: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 275, // 168: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp + 275, // 169: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp + 275, // 170: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp + 15, // 171: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 275, // 172: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp + 280, // 173: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 131, // 174: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 280, // 175: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 9, // 176: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 264, // 177: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 275, // 178: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp + 131, // 179: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 280, // 180: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 131, // 181: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 280, // 182: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 17, // 183: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 10, // 184: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory + 127, // 185: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential + 283, // 186: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 284, // 187: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 132, // 188: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery + 265, // 189: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 142, // 190: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile + 141, // 191: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile + 141, // 192: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 280, // 193: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 122, // 194: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 123, // 195: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 141, // 196: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 280, // 197: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 122, // 198: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem + 123, // 199: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 141, // 200: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile + 280, // 201: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 122, // 202: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 123, // 203: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 17, // 204: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 280, // 205: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 17, // 206: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 155, // 207: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding + 266, // 208: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 267, // 209: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + 268, // 210: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 269, // 211: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 4, // 212: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason + 270, // 213: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + 279, // 214: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration + 280, // 215: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 277, // 216: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 285, // 217: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 161, // 218: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation + 271, // 219: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 162, // 220: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule + 163, // 221: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint + 164, // 222: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule + 166, // 223: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules + 167, // 224: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules + 168, // 225: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary + 286, // 226: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 284, // 227: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 287, // 228: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 165, // 229: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget + 288, // 230: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 165, // 231: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget + 272, // 232: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 280, // 233: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 179, // 234: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 280, // 235: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 179, // 236: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 12, // 237: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 11, // 238: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState + 176, // 239: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 12, // 240: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 275, // 241: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp + 275, // 242: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp + 277, // 243: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 273, // 244: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 280, // 245: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 275, // 246: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp + 111, // 247: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 111, // 248: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 186, // 249: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello + 189, // 250: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat + 202, // 251: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 203, // 252: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 187, // 253: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted + 188, // 254: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected + 190, // 255: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat + 195, // 256: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen + 203, // 257: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 279, // 258: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration + 196, // 259: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget + 197, // 260: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget + 198, // 261: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit + 195, // 262: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen + 200, // 263: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit + 275, // 264: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp + 275, // 265: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp + 204, // 266: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 206, // 267: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 286, // 268: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 275, // 269: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp + 275, // 270: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp + 275, // 271: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp + 275, // 272: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp + 277, // 273: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 277, // 274: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 280, // 275: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 205, // 276: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 208, // 277: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 207, // 278: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 280, // 279: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 208, // 280: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 275, // 281: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp + 280, // 282: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 283: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 284: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 218, // 285: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval + 280, // 286: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 286, // 287: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 280, // 288: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 289: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 290: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 275, // 291: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp + 228, // 292: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 274, // 293: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 289, // 294: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 289, // 295: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 289, // 296: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 17, // 297: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 276, // 298: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 14, // 299: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 280, // 300: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 14, // 301: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 238, // 302: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 280, // 303: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 17, // 304: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 280, // 305: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 238, // 306: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 275, // 307: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp + 18, // 308: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult + 246, // 309: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation + 18, // 310: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult + 275, // 311: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp + 275, // 312: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp + 275, // 313: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp + 275, // 314: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp + 275, // 315: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp + 275, // 316: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp + 275, // 317: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp + 275, // 318: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp + 19, // 319: openshell.v1.SandboxServiceExposure.authorization_mode:type_name -> openshell.v1.ServiceAuthorizationMode + 275, // 320: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 275, // 321: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 127, // 322: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 156, // 323: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 24, // 324: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 26, // 325: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 28, // 326: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 52, // 327: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 60, // 328: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest + 62, // 329: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 63, // 330: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 53, // 331: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 54, // 332: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 55, // 333: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 56, // 334: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 64, // 335: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 65, // 336: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 66, // 337: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 82, // 338: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 67, // 339: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 68, // 340: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 69, // 341: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 87, // 342: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 89, // 343: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 90, // 344: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 91, // 345: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 93, // 346: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 97, // 347: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 99, // 348: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 105, // 349: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 106, // 350: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 113, // 351: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 114, // 352: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 115, // 353: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 120, // 354: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 121, // 355: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 145, // 356: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 147, // 357: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 149, // 358: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 116, // 359: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 133, // 360: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 135, // 361: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 137, // 362: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 139, // 363: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 117, // 364: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 152, // 365: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 290, // 366: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 291, // 367: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 160, // 368: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 170, // 369: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 172, // 370: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 174, // 371: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 247, // 372: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 84, // 373: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 177, // 374: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest + 154, // 375: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 158, // 376: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest + 180, // 377: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 181, // 378: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 184, // 379: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 191, // 380: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest + 193, // 381: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest + 199, // 382: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 201, // 383: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame + 84, // 384: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 247, // 385: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 82, // 386: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 109, // 387: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 210, // 388: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 212, // 389: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 214, // 390: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 216, // 391: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 219, // 392: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 221, // 393: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 223, // 394: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 225, // 395: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 227, // 396: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 20, // 397: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 22, // 398: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 230, // 399: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 232, // 400: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 234, // 401: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 236, // 402: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 239, // 403: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 241, // 404: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 243, // 405: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 25, // 406: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 27, // 407: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 29, // 408: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 70, // 409: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 61, // 410: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse + 70, // 411: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 71, // 412: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 57, // 413: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 57, // 414: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 58, // 415: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 59, // 416: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 72, // 417: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 73, // 418: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 74, // 419: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 83, // 420: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 86, // 421: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 70, // 422: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 70, // 423: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 88, // 424: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 96, // 425: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 96, // 426: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 92, // 427: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 94, // 428: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 98, // 429: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 103, // 430: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 105, // 431: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 103, // 432: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 118, // 433: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 118, // 434: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 119, // 435: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 144, // 436: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 143, // 437: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 146, // 438: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 148, // 439: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 150, // 440: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 118, // 441: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 134, // 442: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 136, // 443: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 138, // 444: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 140, // 445: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 151, // 446: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 153, // 447: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 292, // 448: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 293, // 449: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 169, // 450: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 171, // 451: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 173, // 452: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 175, // 453: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 248, // 454: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 85, // 455: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 178, // 456: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse + 157, // 457: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 159, // 458: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse + 183, // 459: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 182, // 460: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 185, // 461: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 192, // 462: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse + 194, // 463: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse + 199, // 464: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 201, // 465: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame + 85, // 466: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 248, // 467: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 83, // 468: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 110, // 469: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 211, // 470: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 213, // 471: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 215, // 472: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 217, // 473: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 220, // 474: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 222, // 475: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 224, // 476: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 226, // 477: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 229, // 478: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 21, // 479: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 23, // 480: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 231, // 481: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 233, // 482: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 235, // 483: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 237, // 484: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 240, // 485: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 242, // 486: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 244, // 487: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 406, // [406:488] is the sub-list for method output_type + 324, // [324:406] is the sub-list for method input_type + 324, // [324:324] is the sub-list for extension type_name + 324, // [324:324] is the sub-list for extension extendee + 0, // [0:324] is the sub-list for field type_name } func init() { file_openshell_proto_init() } @@ -20269,7 +20361,7 @@ func file_openshell_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_openshell_proto_rawDesc), len(file_openshell_proto_rawDesc)), - NumEnums: 19, + NumEnums: 20, NumMessages: 255, NumExtensions: 0, NumServices: 1, diff --git a/sdk/typescript/src/client.test.ts b/sdk/typescript/src/client.test.ts index 56dcdf3f2b..178a73cc6e 100644 --- a/sdk/typescript/src/client.test.ts +++ b/sdk/typescript/src/client.test.ts @@ -20,9 +20,16 @@ import { SandboxClient, SandboxTemplateClient, SCOPE_NAMES, + ServiceAuthorizationMode, STATUS_NAMES, } from './client.js'; -import { OpenShell, SandboxPhase, SandboxRestartPolicy, ServiceStatus } from './gen/openshell_pb.js'; +import { + OpenShell, + ServiceAuthorizationMode as ProtoServiceAuthorizationMode, + SandboxPhase, + SandboxRestartPolicy, + ServiceStatus, +} from './gen/openshell_pb.js'; import { PolicySource, SettingScope } from './gen/sandbox_pb.js'; import type { ExecInteractiveSession, ExecInteractiveSessionControl } from './index.js'; @@ -276,7 +283,9 @@ describe('exec / execStream', () => { describe('create', () => { it('sends create-time service exposures', async () => { - let created: { serviceExposures?: Array<{ service?: string; targetPort?: number }> } = {}; + let created: { + serviceExposures?: Array<{ service?: string; targetPort?: number; authorizationMode?: number }>; + } = {}; const sandbox = client({ createSandbox: (req) => { created = req; @@ -292,12 +301,29 @@ describe('create', () => { const result = await sandbox.create({ image: 'img', - serviceExposures: [{ targetPort: 4500 }, { service: 'metrics', targetPort: 9090 }], + serviceExposures: [ + { targetPort: 4500 }, + { + service: 'metrics', + targetPort: 9090, + authorizationMode: ServiceAuthorizationMode.BearerPassthrough, + }, + ], }); - expect(created.serviceExposures?.map(({ service, targetPort }) => ({ service, targetPort }))).toEqual([ - { service: '', targetPort: 4500 }, - { service: 'metrics', targetPort: 9090 }, + expect( + created.serviceExposures?.map(({ service, targetPort, authorizationMode }) => ({ + service, + targetPort, + authorizationMode, + })), + ).toEqual([ + { service: '', targetPort: 4500, authorizationMode: ProtoServiceAuthorizationMode.STRIP }, + { + service: 'metrics', + targetPort: 9090, + authorizationMode: ProtoServiceAuthorizationMode.BEARER_PASSTHROUGH, + }, ]); expect(result.serviceUrls).toEqual({ '': 'https://sb.example.test/', diff --git a/sdk/typescript/src/client.ts b/sdk/typescript/src/client.ts index 2f26a71f91..e73bccd314 100644 --- a/sdk/typescript/src/client.ts +++ b/sdk/typescript/src/client.ts @@ -22,6 +22,7 @@ import type { Sandbox, SandboxWorkloadTemplate, UpdateConfigResponse } from './g import { type ExecSandboxInputSchema, OpenShell, + ServiceAuthorizationMode as ProtoServiceAuthorizationMode, SandboxPhase, SandboxRestartPolicy, type SandboxSpecSchema, @@ -168,6 +169,23 @@ export interface ServiceExposure { service?: string; /** Loopback TCP port inside the sandbox. */ targetPort: number; + /** Handling for an incoming application Authorization header. */ + authorizationMode?: ServiceAuthorizationMode; +} + +export enum ServiceAuthorizationMode { + Strip = 'strip', + BearerPassthrough = 'bearer_passthrough', +} + +function serviceAuthorizationModeToProto(mode: ServiceAuthorizationMode | undefined): ProtoServiceAuthorizationMode { + switch (mode) { + case ServiceAuthorizationMode.BearerPassthrough: + return ProtoServiceAuthorizationMode.BEARER_PASSTHROUGH; + case ServiceAuthorizationMode.Strip: + case undefined: + return ProtoServiceAuthorizationMode.STRIP; + } } export interface SandboxFromTemplateSpec { @@ -1023,6 +1041,7 @@ export class SandboxClient { spec.serviceExposures?.map((exposure) => ({ service: exposure.service ?? '', targetPort: exposure.targetPort, + authorizationMode: serviceAuthorizationModeToProto(exposure.authorizationMode), })) ?? [], }); return sandboxRef(resp.sandbox, resp.serviceUrls); @@ -1049,6 +1068,7 @@ export class SandboxClient { spec.serviceExposures?.map((exposure) => ({ service: exposure.service ?? '', targetPort: exposure.targetPort, + authorizationMode: serviceAuthorizationModeToProto(exposure.authorizationMode), })) ?? [], }); return sandboxRef(resp.sandbox, resp.serviceUrls); diff --git a/sdk/typescript/src/index.ts b/sdk/typescript/src/index.ts index 974136fc37..9229f8bcbe 100644 --- a/sdk/typescript/src/index.ts +++ b/sdk/typescript/src/index.ts @@ -53,7 +53,14 @@ export type { WaitOptions, WorkspaceListScope, } from './client.js'; -export { errorCode, OpenShellClient, Pager, SandboxClient, SandboxTemplateClient } from './client.js'; +export { + errorCode, + OpenShellClient, + Pager, + SandboxClient, + SandboxTemplateClient, + ServiceAuthorizationMode, +} from './client.js'; export type { ErrorInfo, FieldViolation, SdkErrorCode } from './errors.js'; export { fromConnect, SdkError } from './errors.js'; export type { ClientCredentialsOptions, OidcTokenProvider } from './oidc.js'; diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index c9440dfaad..060555264d 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -882,11 +882,13 @@ openshell sandbox create \ --name my-app \ --from my-app:latest \ --expose 8080 \ + --expose-authorization-mode bearer-passthrough \ --detach \ -- ./start-server.sh # Expose and manage an HTTP service through the gateway. -openshell service expose my-app 8080 web +openshell service expose my-app 8080 web \ + --authorization-mode bearer-passthrough openshell service list my-app openshell service list my-app --output json openshell service get my-app web @@ -901,6 +903,19 @@ request and keeps the sandbox running. Add `--output json` for automation; the result contains a `service_urls` map whose empty key is the unnamed endpoint. Use `openshell service expose` after creation to add or update named endpoints. +Exposed services strip `Authorization` by default. Select +`bearer-passthrough` only when the application inside the sandbox authenticates +its own clients. This mode accepts either no `Authorization` header or exactly +one non-empty Bearer credential and forwards that value unchanged. It rejects +duplicate, malformed, or non-Bearer authorization before contacting the +application. The application remains responsible for validating the token, and +the raw token reaches the sandbox process, so never log it. Service routes +bypass control-plane RPC authorization, but they still use the gateway's +existing listener, domain routing, and TLS configuration, including any client +certificate requirement. See the published +[sandbox service documentation](https://docs.nvidia.com/openshell/latest/how-it-works/sandboxes/overview.md) +for the complete security contract. + Prefer loopback binds unless the user explicitly needs LAN-visible local access. --- diff --git a/tests/suites/features/Cargo.lock b/tests/suites/features/Cargo.lock index 268f8bac92..8561dc97df 100644 --- a/tests/suites/features/Cargo.lock +++ b/tests/suites/features/Cargo.lock @@ -38,7 +38,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e" dependencies = [ "aws-lc-sys", - "untrusted", + "untrusted 0.7.1", "zeroize", ] @@ -278,7 +278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -804,7 +804,7 @@ checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -903,12 +903,15 @@ dependencies = [ "noyalib", "prost", "rand", + "rustls", + "rustls-pemfile", "serde", "serde_json", "sha1", "sha2", "tempfile", "tokio", + "tokio-rustls", "tokio-stream", "tonic", "tonic-prost", @@ -1122,6 +1125,20 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "rustc-hash" version = "2.1.3" @@ -1138,7 +1155,52 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted 0.9.0", ] [[package]] @@ -1303,7 +1365,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1312,6 +1374,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.119" @@ -1361,7 +1429,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1438,7 +1506,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1452,6 +1520,16 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "tokio-rustls" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.19" @@ -1603,6 +1681,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.8" @@ -1724,6 +1808,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -1733,6 +1826,70 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "wit-bindgen" version = "0.57.1"