diff --git a/architecture/gateway.md b/architecture/gateway.md index 2fbd46533e..bf0f989d25 100644 --- a/architecture/gateway.md +++ b/architecture/gateway.md @@ -311,15 +311,15 @@ The storage schema is intentionally narrow: ### Protobuf API and storage boundaries Public RPC contracts and durable protobuf formats have separate ownership. The -`openshell.v1.OpenShell` service currently has 74 RPCs. Their request and +`openshell.v1.OpenShell` service currently has 75 RPCs. Their request and response roots, streaming flags, and transitive message closure come from the public descriptor set generated by `openshell-core`; a fingerprint test in `openshell-server` requires this inventory to be reviewed whenever it changes. Compute-driver, credential-driver, gateway-interceptor, and supervisor-middleware services are compiled contracts for internal extension -boundaries, not public gateway RPCs. The current public inventory has 74 -methods, 276 messages, and 12 enums -(`042034fe4d0000279ee4ed27e587ab8e530934b8d5c3aa36dc9769f81dfa6e51`). +boundaries, not public gateway RPCs. The current public inventory has 75 +methods, 279 messages, and 13 enums +(`25b9b3d6f2cebdcd3148b0049838dcce51ee745f52a4051428af6701e610afd0`). Storage-only messages live in the private, versioned `openshell.storage.v1` package under `crates/openshell-server/proto`. The server @@ -334,13 +334,20 @@ Go, Python, and TypeScript client generation inputs do not advertise them. | Public messages used directly as encoded storage roots | `Sandbox`, `SandboxWorkloadTemplate`, `Provider`, `Workspace`, `WorkspaceMember`, `SshSession`, `ServiceEndpoint` | The generated public type is also the persisted payload. `SshSession` is not in the current public RPC message closure. | | Embedded encoded root | `SandboxPolicy` | Stored in policy rows and inside the JSON settings envelope. | -The 12 encoded durable roots above have a closure of 81 messages and eight -enums (`920a5243dfb37ce709f0f562a47d17791a5ede90fd7f662ed01542abd60a0dfb`). -Its intersection with the public RPC closure contains 71 messages and eight -enums (`05add438ba041defc98d791038ae593d3f09352677cae43f2276d494205ce415`). +The 12 encoded durable roots above have a closure of 82 messages and nine +enums (`a6191e11d46430e5e32881f53b13f6c717717fbc6bff6e0a1d270fe8f9710d51`). +Its intersection with the public RPC closure contains 72 messages and nine +enums (`68127e24cdb88b67433f68c4a1443c22a322f37ed1225b7547614a96f768cfac`). The descriptor-derived test owns these full inventories; the tables here record the reviewed roots and classifications. +Configuration admission adds optional `SandboxStatus.configuration_admission` +at field 10, extending both the public and durable closures. Existing stored +sandboxes decode with no admission record; no database rewrite is required. +New supervisors register and validate before activation, and explicit restart +resets admission. A pre-admission byte fixture verifies that legacy phase and +policy-version fields survive decoding without fabricating acceptance. + | Dual-purpose encoded root | Current decision | |---|---| | `Sandbox` | Defer a storage twin; govern its complete dependency closure as durable. | diff --git a/architecture/sandbox.md b/architecture/sandbox.md index 7be66e97e6..1fbd206186 100644 --- a/architecture/sandbox.md +++ b/architecture/sandbox.md @@ -473,6 +473,44 @@ the structured 403 and authors the narrowest rule. Mechanistically mapping L7 would either over-broaden rules or require path-templating logic that rots quickly. +## Configuration Admission + +Gateway-managed supervisors reconcile configuration before launching the main +process or exposing workload services. Admission covers the effective policy, +provider layers, credential bindings, and gateway-derived provenance. Explicit +user and global policy precedence is unchanged; an image without a policy uses +the restrictive baseline. An invalid image policy does not become a launchable +default. + +The gateway tracks configuration admission independently of compute health. +A blocked startup remains `Provisioning` with a `ConfigurationInvalid` readiness +condition, even when the container backend reports readiness. Gateway management +operations remain available. Replacing the policy or repairing providers allows +the same supervisor to reconcile and launch; it does not recreate the sandbox. +Static policy fields can be replaced before the first accepted activation. +Admission validates policy composition; image and host setup failures, such as +an unresolved OCI user or unavailable isolation facilities, retain their existing +startup error behavior. + +Acceptance identifies the effective policy hash/version, configuration revision, +provider-environment revision, and reporting supervisor instance. Startup captures +the matching provider environment and constructs the runtime before reporting +acceptance. Live reconciliation begins only after the main process has spawned, +so it cannot replace the configuration captured for that launch. Restart resets +admission and requires a fresh accepted configuration. + +Policy and provider refreshes are prepared before publication. Publication +invalidates prior policy guards before exposing new provider material and swaps +the policy under the same publication locks. Rejected candidates cannot install +their credentials alongside the previous policy. Existing runtime fail-closed +checks remain necessary for in-flight traffic and invalid live updates. + +In sidecar topology, the authenticated process supervisor supplies discovery +from the workload image over the existing control socket. The network supervisor +withholds bootstrap until admission succeeds, then sends the accepted policy and +child environment together. Subsequent configuration messages carry both parts +and an ordered generation; older messages cannot restore stale child credentials. + ## Policy Revision Acknowledgement When the supervisor loads a sandbox-scoped policy from the gateway, it retains @@ -508,11 +546,11 @@ outages cannot block policy polling, enforcement, settings, or provider refreshes and cannot permanently lose the initial acknowledgement. Only sandbox-scoped revisions (`PolicySource::Sandbox`, version greater than -zero) are acknowledged. Global policies and local-file development policies do -not use the sandbox revision API and produce no acknowledgement. When explicit -local Rego and data files are configured, the supervisor continues polling the -gateway for settings and provider refreshes but never replaces the local OPA -engine with a gateway policy revision. +zero) use the policy revision acknowledgement API. Global policies use the +configuration admission contract without a sandbox policy revision acknowledgement. +Local Rego/data overrides remain available for standalone development; combining +them with a gateway-managed sandbox is rejected because the gateway cannot admit +the runtime policy it would enforce. ## Failure Behavior diff --git a/architecture/security-policy.md b/architecture/security-policy.md index 5b49118b93..4737b44ae3 100644 --- a/architecture/security-policy.md +++ b/architecture/security-policy.md @@ -142,6 +142,14 @@ flag defaults to `false` and is security-flagged in policy approval flows. Incremental merges only ever add the flag to a matching endpoint; clearing it requires removing the endpoint or replacing the policy. +Image discovery may persist a desired policy for repair, but does not authorize +workload activation. The gateway applies the credential gate after full provider +composition and provenance derivation. A rejected effective configuration keeps +startup blocked with a bounded diagnostic; the supervisor waits for management +repair instead of launching with connection-time denials or a fallback policy. +Accepted runtime state includes the matching provider-environment revision, so +policy and credential updates cannot activate independently. + The network supervisor independently enforces the same boundary. Credentialed WebSocket upgrades use the parsed relay, binary frames fail closed, and text placeholders require rewrite. REST bodies can continue streaming when body diff --git a/crates/openshell-cli/src/run.rs b/crates/openshell-cli/src/run.rs index fbad0d505f..fff14884c2 100644 --- a/crates/openshell-cli/src/run.rs +++ b/crates/openshell-cli/src/run.rs @@ -1510,11 +1510,23 @@ pub async fn sandbox_get( sandbox.object_id().to_string() }; - let config = client + let config_result = client .get_sandbox_config(GetSandboxConfigRequest { sandbox_id }) - .await - .into_diagnostic()? - .into_inner(); + .await; + let config = match config_result { + Ok(response) => response.into_inner(), + Err(_) if !policy_only && configuration_failure_message(&sandbox).is_some() => { + // An invalid desired policy must not hide the status needed to + // repair it. Keep payload-only reads strict. + GetSandboxConfigResponse { + configuration_error: configuration_failure_message(&sandbox) + .unwrap_or_default() + .to_string(), + ..Default::default() + } + } + Err(error) => return Err(error).into_diagnostic(), + }; if policy_only { let Some(ref policy) = config.policy else { @@ -1548,6 +1560,22 @@ pub async fn sandbox_get( println!(" {} {}", "Id:".dimmed(), id); println!(" {} {}", "Name:".dimmed(), name); println!(" {} {}", "Phase:".dimmed(), phase_name(sandbox.phase())); + if let Some(status) = sandbox.status.as_ref() { + for condition in &status.conditions { + if matches!( + condition.r#type.as_str(), + "ConfigurationReady" | "DesiredConfigurationReady" + ) && condition.status.eq_ignore_ascii_case("false") + { + println!( + " {} {}: {}", + "Configuration:".dimmed(), + condition.reason, + condition.message + ); + } + } + } if let Some(exit_code) = sandbox.status.as_ref().and_then(|status| status.exit_code) { println!(" {} {}", "Exit Code:".dimmed(), exit_code); } @@ -2367,7 +2395,19 @@ pub async fn sandbox_list( Ok(()) } +fn configuration_failure_message(sandbox: &Sandbox) -> Option<&str> { + sandbox + .status + .as_ref()? + .configuration_admission + .as_ref() + .map(|admission| admission.error.as_str()) + .filter(|message| !message.is_empty()) +} + fn sandbox_to_json(sandbox: &Sandbox) -> serde_json::Value { + use openshell_core::proto::ConfigurationAdmissionState; + let meta = sandbox.metadata.as_ref(); let labels = meta.map_or_else(|| serde_json::json!({}), |m| serde_json::json!(m.labels)); let annotations = meta.map_or_else( @@ -2384,6 +2424,39 @@ fn sandbox_to_json(sandbox: &Sandbox) -> serde_json::Value { "resource_version": provenance.resource_version, }) }); + let conditions: Vec<_> = sandbox + .status + .as_ref() + .into_iter() + .flat_map(|status| &status.conditions) + .map(|condition| { + serde_json::json!({ + "type": condition.r#type, + "status": condition.status, + "reason": condition.reason, + "message": condition.message, + }) + }) + .collect(); + let admission = sandbox + .status + .as_ref() + .and_then(|status| status.configuration_admission.as_ref()) + .map(|admission| { + serde_json::json!({ + "state": match ConfigurationAdmissionState::try_from(admission.state) { + Ok(ConfigurationAdmissionState::Pending) => "pending", + Ok(ConfigurationAdmissionState::Accepted) => "accepted", + Ok(ConfigurationAdmissionState::Rejected) => "rejected", + _ => "unknown", + }, + "error": admission.error, + "policy_version": admission.policy_version, + "policy_hash": admission.policy_hash, + "config_revision": admission.config_revision, + "provider_env_revision": admission.provider_env_revision, + }) + }); serde_json::json!({ "id": sandbox.object_id(), "name": sandbox.object_name(), @@ -2395,6 +2468,8 @@ fn sandbox_to_json(sandbox: &Sandbox) -> serde_json::Value { "phase": phase_name(sandbox.phase()), "current_policy_version": sandbox.current_policy_version(), "exit_code": sandbox.status.as_ref().and_then(|status| status.exit_code), + "conditions": conditions, + "configuration_admission": admission, "created_from_workload_template": created_from_workload_template, }) } @@ -7016,6 +7091,45 @@ mod tests { assert_eq!(json["resources"]["gpu"], 2); } + #[test] + fn sandbox_json_exposes_repair_diagnostic_and_accepted_generation() { + use openshell_core::proto::{ConfigurationAdmissionState, SandboxConfigurationAdmission}; + + let mut sandbox = Sandbox::default(); + sandbox.set_phase(SandboxPhase::Provisioning as i32); + let status = sandbox.status.as_mut().unwrap(); + status.configuration_admission = Some(SandboxConfigurationAdmission { + state: ConfigurationAdmissionState::Rejected as i32, + error: "rule image_api requires L7 inspection".to_string(), + policy_hash: "candidate-hash".to_string(), + ..Default::default() + }); + status.conditions.push(SandboxCondition { + r#type: "ConfigurationReady".to_string(), + status: "False".to_string(), + reason: "ConfigurationInvalid".to_string(), + message: "rule image_api requires L7 inspection".to_string(), + ..Default::default() + }); + let json = super::sandbox_to_json(&sandbox); + assert_eq!(json["configuration_admission"]["state"], "rejected"); + assert_eq!(json["conditions"][0]["reason"], "ConfigurationInvalid"); + assert_eq!( + super::configuration_failure_message(&sandbox), + Some("rule image_api requires L7 inspection") + ); + sandbox + .status + .as_mut() + .unwrap() + .configuration_admission + .as_mut() + .unwrap() + .error + .clear(); + assert_eq!(super::configuration_failure_message(&sandbox), None); + } + #[test] fn sandbox_detail_to_json_includes_policy_fields() { let mut sandbox = Sandbox { diff --git a/crates/openshell-cli/tests/ensure_providers_integration.rs b/crates/openshell-cli/tests/ensure_providers_integration.rs index 7545786a12..079ba04aa4 100644 --- a/crates/openshell-cli/tests/ensure_providers_integration.rs +++ b/crates/openshell-cli/tests/ensure_providers_integration.rs @@ -545,6 +545,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not implemented in test")) } + async fn report_sandbox_configuration( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented in test")) + } + async fn report_policy_status( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/mtls_integration.rs b/crates/openshell-cli/tests/mtls_integration.rs index 29de1fe6fe..cfff878373 100644 --- a/crates/openshell-cli/tests/mtls_integration.rs +++ b/crates/openshell-cli/tests/mtls_integration.rs @@ -408,6 +408,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not implemented in test")) } + async fn report_sandbox_configuration( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented in test")) + } + async fn report_policy_status( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/provider_commands_integration.rs b/crates/openshell-cli/tests/provider_commands_integration.rs index 2d1b3f25d3..34b27b3a8c 100644 --- a/crates/openshell-cli/tests/provider_commands_integration.rs +++ b/crates/openshell-cli/tests/provider_commands_integration.rs @@ -975,6 +975,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not implemented in test")) } + async fn report_sandbox_configuration( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented in test")) + } + async fn report_policy_status( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs index d9e3cdad98..e9542aa148 100644 --- a/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs +++ b/crates/openshell-cli/tests/sandbox_create_lifecycle_integration.rs @@ -804,6 +804,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not implemented in test")) } + async fn report_sandbox_configuration( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented in test")) + } + async fn report_policy_status( &self, _request: tonic::Request, diff --git a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs index fdb0ebbd0d..aa4f28d10f 100644 --- a/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs +++ b/crates/openshell-cli/tests/sandbox_name_fallback_integration.rs @@ -496,6 +496,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not implemented in test")) } + async fn report_sandbox_configuration( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented in test")) + } + async fn report_policy_status( &self, _request: tonic::Request, diff --git a/crates/openshell-core/src/grpc_client.rs b/crates/openshell-core/src/grpc_client.rs index 315ff0b72f..c29a78386a 100644 --- a/crates/openshell-core/src/grpc_client.rs +++ b/crates/openshell-core/src/grpc_client.rs @@ -821,6 +821,40 @@ pub async fn sync_policy_and_fetch_snapshot( fetch_settings_snapshot_with_client(&mut client, sandbox_id).await } +/// Report an exact runtime configuration generation. Pending registration uses +/// the snapshot's instance fence; retain that snapshot across registration retries. +pub async fn report_sandbox_configuration( + endpoint: &str, + sandbox_id: &str, + instance_id: &str, + snapshot: Option<&SettingsPollResult>, + state: crate::proto::ConfigurationAdmissionState, + error: &str, +) -> Result<()> { + let mut client = connect(endpoint).await?; + client + .report_sandbox_configuration(crate::proto::ReportSandboxConfigurationRequest { + sandbox_id: sandbox_id.to_string(), + expected_instance_id: snapshot.map_or_else(String::new, |snapshot| { + snapshot.configuration_instance_id.clone() + }), + admission: Some(crate::proto::SandboxConfigurationAdmission { + instance_id: instance_id.to_string(), + state: state.into(), + policy_version: snapshot.map_or(0, |snapshot| snapshot.version), + policy_hash: snapshot + .map_or_else(String::new, |snapshot| snapshot.policy_hash.clone()), + config_revision: snapshot.map_or(0, |snapshot| snapshot.config_revision), + provider_env_revision: snapshot + .map_or(0, |snapshot| snapshot.provider_env_revision), + error: error.to_string(), + }), + }) + .await + .into_diagnostic()?; + Ok(()) +} + /// Fetch provider environment variables for a sandbox from `OpenShell` server via gRPC. /// /// Returns a map of environment variable names to values derived from provider @@ -919,6 +953,9 @@ pub struct CachedOpenShellClient { /// Settings poll result returned by [`CachedOpenShellClient::poll_settings`]. #[derive(Clone, Debug)] pub struct SettingsPollResult { + pub configuration_instance_id: String, + pub configuration_admitted: bool, + pub configuration_error: String, pub policy: Option, pub version: u32, pub policy_hash: String, @@ -940,6 +977,9 @@ pub struct SettingsPollResult { fn settings_poll_result(inner: crate::proto::GetSandboxConfigResponse) -> SettingsPollResult { SettingsPollResult { + configuration_instance_id: inner.configuration_instance_id, + configuration_admitted: inner.configuration_admitted, + configuration_error: inner.configuration_error, policy: inner.policy, version: inner.version, policy_hash: inner.policy_hash, diff --git a/crates/openshell-core/src/provider_credentials.rs b/crates/openshell-core/src/provider_credentials.rs index 2b1537a21b..7caed1742c 100644 --- a/crates/openshell-core/src/provider_credentials.rs +++ b/crates/openshell-core/src/provider_credentials.rs @@ -572,6 +572,62 @@ impl ProviderCredentialState { Ok(inner.current.child_env.len()) } + /// Install a validated candidate without repeating fallible compilation. + /// + /// Existing clones keep observing this live state. Preserve suppressed + /// environment keys and identity history so refresh cannot restore removed + /// keys or authorize old placeholders for a different provider. Callers + /// must serialize installs and revocations, as for bound-environment installs. + pub fn install_prepared(&self, prepared: &Self) -> usize { + // Release the candidate lock before taking the live lock, including + // when a caller passes another handle to the same state. + let (snapshot, generations, current_resolver, bindings, non_secret_keys) = { + let candidate = prepared + .inner + .read() + .expect("provider credential state poisoned"); + ( + (*candidate.current).clone(), + candidate.generations.clone(), + candidate.current_resolver.clone(), + candidate.static_credential_bindings.clone(), + candidate.non_secret_environment_keys.clone(), + ) + }; + let mut inner = self + .inner + .write() + .expect("provider credential state poisoned"); + let mut snapshot = snapshot; + for key in &inner.suppressed_keys { + snapshot.child_env.remove(key); + } + if static_credential_identities(&inner.static_credential_bindings) + != static_credential_identities(&bindings) + { + inner.generations.clear(); + } + inner.generations.extend(generations); + while inner.generations.len() > MAX_RETAINED_CREDENTIAL_GENERATIONS { + inner.generations.pop_front(); + } + inner.current_resolver = current_resolver; + inner.combined_resolver = + merge_resolvers(&inner.generations, inner.current_resolver.as_ref()); + inner + .known_static_credential_keys + .extend(bindings.keys().cloned()); + update_static_credential_identity_epochs( + &mut inner.static_credential_identity_epochs, + snapshot.revision, + &bindings, + ); + inner.static_credential_bindings = bindings; + inner.non_secret_environment_keys = non_secret_keys; + inner.current = Arc::new(snapshot); + inner.current.child_env.len() + } + /// Atomically remove static provider material after a failed refresh. /// /// Dynamic token grants retain their independently endpoint-bound state @@ -2055,6 +2111,67 @@ mod tests { ); } + #[test] + fn prepared_install_retains_placeholders_for_same_provider_identity() { + let make_state = |revision, secret: &str| { + ProviderCredentialState::from_bound_environment( + revision, + HashMap::from([("API_KEY".to_string(), secret.to_string())]), + HashMap::new(), + HashMap::new(), + HashMap::from([( + "API_KEY".to_string(), + binding("api.example.com", 443, "/**"), + )]), + Vec::new(), + ) + .unwrap() + }; + let live = make_state(1, "first-secret"); + let old_placeholder = live.snapshot().child_env["API_KEY"].clone(); + live.install_prepared(&make_state(2, "second-secret")); + let resolver = live + .resolver_for_endpoint("api.example.com", 443, "/") + .unwrap(); + assert_eq!( + resolver.resolve_placeholder(&old_placeholder), + Some("first-secret") + ); + assert_eq!( + resolver.resolve_placeholder(&live.snapshot().child_env["API_KEY"]), + Some("second-secret"), + ); + } + + #[test] + fn prepared_install_preserves_suppression_and_rejects_replaced_identity() { + let make_state = |revision, identity: &str, secret: &str| { + let mut binding = binding("api.example.com", 443, "/**"); + binding.credential_identity = identity.to_string(); + ProviderCredentialState::from_bound_environment( + revision, + HashMap::from([("API_KEY".to_string(), secret.to_string())]), + HashMap::new(), + HashMap::new(), + HashMap::from([("API_KEY".to_string(), binding)]), + Vec::new(), + ) + .unwrap() + }; + let live = make_state(1, "first:API_KEY", "first-secret"); + let observer = live.clone(); + let old_placeholder = live.snapshot().child_env["API_KEY"].clone(); + live.remove_env_key("API_KEY"); + let candidate = make_state(2, "second:API_KEY", "second-secret"); + live.install_prepared(&candidate); + assert_eq!(observer.snapshot().revision, 2); + assert!(!observer.snapshot().child_env.contains_key("API_KEY")); + let resolver = observer + .resolver_for_endpoint("api.example.com", 443, "/") + .unwrap(); + assert!(resolver.resolve_placeholder(&old_placeholder).is_none()); + } + #[test] fn suppressed_keys_survive_install_environment() { let state = ProviderCredentialState::from_environment( diff --git a/crates/openshell-sandbox/src/lib.rs b/crates/openshell-sandbox/src/lib.rs index d86c94b97b..7cc607ea38 100644 --- a/crates/openshell-sandbox/src/lib.rs +++ b/crates/openshell-sandbox/src/lib.rs @@ -159,6 +159,31 @@ pub async fn run_sandbox( let process_enforcement_mode = process_enforcement_mode(); let process_uses_sidecar_control = process_enabled && !network_enabled && sidecar_network_enforcement; + #[cfg(target_os = "linux")] + let mut pending_sidecar_server = if network_enabled && sidecar_network_enforcement { + let socket = sidecar_control_socket() + .ok_or_else(|| miette::miette!("sidecar topology requires a control socket"))?; + Some(sidecar_control::spawn_pending_server( + &socket, + sidecar_expected_peer()?, + )?) + } else { + None + }; + #[cfg(target_os = "linux")] + let image_policy_discovery = if let Some(server) = pending_sidecar_server.as_mut() { + Some( + server + .take_discovered_policy_receiver() + .expect("new sidecar server owns discovery receiver") + .await + .map_err(|_| miette::miette!("sidecar image policy discovery channel closed"))?, + ) + } else { + None + }; + #[cfg(not(target_os = "linux"))] + let image_policy_discovery = None; let mut process_control_connection = None; let sidecar_bootstrap = if process_uses_sidecar_control { let socket = sidecar_control_socket().ok_or_else(|| { @@ -167,9 +192,10 @@ pub async fn run_sandbox( openshell_core::sandbox_env::SIDECAR_CONTROL_SOCKET ) })?; - let (bootstrap, connection) = sidecar_control::connect_process_client( + let (bootstrap, connection) = sidecar_control::connect_process_client_with_policy( &socket, Duration::from_secs(SIDECAR_READY_TIMEOUT_SECS), + discover_image_policy(), ) .await?; process_control_connection = Some(connection); @@ -194,6 +220,7 @@ pub async fn run_sandbox( loaded_policy_origin, initial_agent_proposals_enabled, initial_extension_authentication_enabled, + captured_provider_credentials, ) = if let Some(bootstrap) = sidecar_bootstrap.as_ref() { let (policy, opa_engine, retained_proto, loaded_policy_origin) = load_policy_from_sidecar_bootstrap(bootstrap)?; @@ -205,6 +232,7 @@ pub async fn run_sandbox( loaded_policy_origin, bootstrap.agent_proposals_enabled, false, + None, ) } else { load_policy( @@ -214,6 +242,7 @@ pub async fn run_sandbox( policy_rules, policy_data, &extension_credentials, + image_policy_discovery, ) .await? }; @@ -256,6 +285,9 @@ pub async fn run_sandbox( bootstrap.provider_child_env.clone(), ); (provider_credentials, bootstrap.provider_child_env.clone()) + } else if let Some(credentials) = captured_provider_credentials { + let environment = credentials.child_env_with_gcp_resolved(); + (credentials, environment) } else { // Fetch provider environment variables from the server. // This is done after loading the policy so the sandbox can still start @@ -371,6 +403,10 @@ pub async fn run_sandbox( // snapshot that produced the policy so networking and process setup agree // before the poll loop starts reconciling later changes. let agent_proposals = AgentProposals::new(initial_agent_proposals_enabled); + // Keep the accepted launch generation fixed until the child has actually + // spawned. Live reconciliation must not race its captured policy/env. + let (workload_started_tx, workload_started_rx) = + tokio::sync::watch::channel(!process_enabled && !sidecar_network_enforcement); let process_control_writer = process_control_connection .as_ref() @@ -568,31 +604,40 @@ pub async fn run_sandbox( "sidecar network enforcement requires proxy network mode" )); } - let socket = sidecar_control_socket().ok_or_else(|| { - miette::miette!( - "{} is required for sidecar topology", - openshell_core::sandbox_env::SIDECAR_CONTROL_SOCKET - ) - })?; let proto = retained_proto.as_ref().ok_or_else(|| { miette::miette!( "sidecar topology requires gateway policy data for the process supervisor" ) })?; let ca_paths = networking.as_ref().and_then(|n| n.ca_file_paths.clone()); - Some(sidecar_control::spawn_server( - &socket, - sidecar_control::BootstrapData { + let server = pending_sidecar_server + .take() + .expect("sidecar server started before admission"); + let (policy_hash, config_revision) = match &loaded_policy_origin { + LoadedPolicyOrigin::Gateway { + revision: Some(revision), + .. + } => (revision.policy_hash.clone(), revision.config_revision), + _ => { + return Err(miette::miette!( + "sidecar bootstrap requires an accepted gateway generation" + )); + } + }; + server + .publisher() + .publish_bootstrap(sidecar_control::BootstrapData { policy_proto: proto.clone(), + policy_hash, + config_revision, provider_env_revision: provider_credentials.snapshot().revision, provider_env_generation: 0, provider_child_env: provider_env.clone(), agent_proposals_enabled: agent_proposals.enabled(), proxy_ca_cert_path: ca_paths.as_ref().map(|paths| paths.0.clone()), proxy_ca_bundle_path: ca_paths.as_ref().map(|paths| paths.1.clone()), - }, - sidecar_expected_peer()?, - )?) + }); + Some(server) } else { None }; @@ -629,6 +674,7 @@ pub async fn run_sandbox( sandbox_id: sandbox_id.clone(), trusted_ssh_socket_path: std::path::PathBuf::from(trusted_ssh_socket_path), control_publisher: sidecar_control_publisher.clone(), + workload_started: workload_started_tx.clone(), }, ); } @@ -776,6 +822,10 @@ pub async fn run_sandbox( }; tokio::spawn(async move { + let mut workload_started = workload_started_rx; + if workload_started.wait_for(|started| *started).await.is_err() { + return; + } if let Err(e) = run_policy_poll_loop(poll_ctx).await { ocsf_emit!( AppLifecycleBuilder::new(ocsf_ctx()) @@ -879,28 +929,28 @@ pub async fn run_sandbox( }; tokio::pin!(ssh_exited); - let entrypoint_started_tx = - if process_uses_sidecar_control && let Some(writer) = process_control_writer.clone() { - let (tx, rx) = tokio::sync::oneshot::channel(); - tokio::spawn(async move { - match rx.await { - Ok((pid, instance_id)) => { - if let Err(err) = + let entrypoint_started_tx = { + let writer = process_control_writer.clone(); + let (tx, rx) = tokio::sync::oneshot::channel(); + tokio::spawn(async move { + match rx.await { + Ok((pid, instance_id)) => { + workload_started_tx.send_replace(true); + if let Some(writer) = writer + && let Err(err) = sidecar_control::send_entrypoint_started(&writer, pid, instance_id) .await - { - warn!(error = %err, "Failed to send sidecar entrypoint event"); - } - } - Err(_closed) => { - debug!("Entrypoint exited before sidecar entrypoint event was sent"); + { + warn!(error = %err, "Failed to send sidecar entrypoint event"); } } - }); - Some(tx) - } else { - None - }; + Err(_closed) => { + debug!("Entrypoint exited before sidecar entrypoint event was sent"); + } + } + }); + Some(tx) + }; let sidecar_exit_tx = if process_uses_sidecar_control && let Some(writer) = process_control_writer.clone() { @@ -1254,6 +1304,27 @@ fn spawn_sidecar_control_update_watcher( tokio::spawn(async move { while let Some(update) = updates.recv().await { match update { + sidecar_control::ControlUpdate::Configuration { + policy_proto, + policy_hash, + config_revision, + provider_env_revision, + provider_env_generation: generation, + provider_child_env, + } => { + if generation <= provider_env_generation + || OpaEngine::from_proto(&policy_proto).is_err() + { + continue; + } + provider_credentials + .install_child_env_snapshot(provider_env_revision, provider_child_env); + provider_env_generation = generation; + debug!( + policy_hash, + config_revision, "Accepted coherent sidecar configuration" + ); + } sidecar_control::ControlUpdate::ProviderEnv { revision, generation, @@ -1327,6 +1398,7 @@ struct SidecarEntrypointHandler { sandbox_id: Option, trusted_ssh_socket_path: std::path::PathBuf, control_publisher: Option, + workload_started: tokio::sync::watch::Sender, } #[cfg(target_os = "linux")] @@ -1343,6 +1415,7 @@ fn spawn_sidecar_entrypoint_handler( sandbox_id, trusted_ssh_socket_path, control_publisher, + workload_started, } = handler; let mut session_started = false; let mut session_task: Option> = None; @@ -1458,6 +1531,9 @@ fn spawn_sidecar_entrypoint_handler( session_started = true; info!("sidecar supervisor session task spawned"); } + if started.start_session { + workload_started.send_replace(true); + } } terminating.store(true, Ordering::Release); }); @@ -2288,6 +2364,81 @@ where )) } +#[tonic::async_trait] +trait StartupGateway: Send + Sync { + async fn snapshot(&self, id: &str) -> Result; + async fn provider( + &self, + id: &str, + ) -> Result; + async fn sync( + &self, + id: &str, + sandbox: &str, + policy: &openshell_core::proto::SandboxPolicy, + workspace: &str, + ) -> Result; + async fn report( + &self, + id: &str, + instance_id: &str, + snapshot: Option<&openshell_core::grpc_client::SettingsPollResult>, + state: openshell_core::proto::ConfigurationAdmissionState, + error: &str, + ) -> Result<()>; +} + +struct RemoteStartupGateway { + endpoint: String, +} + +#[tonic::async_trait] +impl StartupGateway for RemoteStartupGateway { + async fn snapshot(&self, id: &str) -> Result { + openshell_core::grpc_client::fetch_settings_snapshot(&self.endpoint, id).await + } + async fn provider( + &self, + id: &str, + ) -> Result { + openshell_core::grpc_client::fetch_provider_environment(&self.endpoint, id).await + } + async fn sync( + &self, + id: &str, + sandbox: &str, + policy: &openshell_core::proto::SandboxPolicy, + workspace: &str, + ) -> Result { + openshell_core::grpc_client::sync_policy_and_fetch_snapshot( + &self.endpoint, + id, + sandbox, + policy, + workspace, + ) + .await + } + async fn report( + &self, + id: &str, + instance_id: &str, + snapshot: Option<&openshell_core::grpc_client::SettingsPollResult>, + state: openshell_core::proto::ConfigurationAdmissionState, + error: &str, + ) -> Result<()> { + openshell_core::grpc_client::report_sandbox_configuration( + &self.endpoint, + id, + instance_id, + snapshot, + state, + error, + ) + .await + } +} + /// Load sandbox policy from local files or gRPC. /// /// Priority: @@ -2306,6 +2457,45 @@ async fn load_policy( policy_rules: Option, policy_data: Option, extension_credentials: &openshell_extension_core::ExtensionCredentialStore, + image_discovery: Option, +) -> Result<( + SandboxPolicy, + Option>, + Option, + MiddlewareRegistryStatus, + LoadedPolicyOrigin, + bool, + bool, + Option, +)> { + load_policy_with_gateway( + sandbox_id, + sandbox, + openshell_endpoint.clone(), + policy_rules, + policy_data, + extension_credentials, + image_discovery, + &RemoteStartupGateway { + endpoint: openshell_endpoint.unwrap_or_default(), + }, + ) + .await +} + +#[allow( + clippy::too_many_arguments, + reason = "Startup gateway injection preserves the production policy-loading inputs" +)] +async fn load_policy_with_gateway( + sandbox_id: Option, + sandbox: Option, + openshell_endpoint: Option, + policy_rules: Option, + policy_data: Option, + extension_credentials: &openshell_extension_core::ExtensionCredentialStore, + image_discovery: Option, + gateway: &impl StartupGateway, ) -> Result<( SandboxPolicy, Option>, @@ -2314,9 +2504,16 @@ async fn load_policy( LoadedPolicyOrigin, bool, bool, + Option, )> { + use openshell_core::proto::ConfigurationAdmissionState; // File mode: load OPA engine from rego rules + YAML data (dev override) if let (Some(policy_file), Some(data_file)) = (&policy_rules, &policy_data) { + if sandbox_id.is_some() && openshell_endpoint.is_some() { + return Err(miette::miette!( + "Local policy overrides cannot be combined with gateway-managed activation; replace the sandbox policy through the gateway" + )); + } ocsf_emit!(ConfigStateChangeBuilder::new(ocsf_ctx()) .severity(SeverityId::Informational) .status(StatusId::Success) @@ -2364,6 +2561,7 @@ async fn load_policy( LoadedPolicyOrigin::LocalOverride, false, false, + None, )); } @@ -2374,156 +2572,231 @@ async fn load_policy( endpoint = %endpoint, "Fetching sandbox policy via gRPC" ); - let mut snapshot = grpc_retry("Policy fetch", || { - openshell_core::grpc_client::fetch_settings_snapshot(endpoint, id) - }) - .await?; - - let mut proto_policy = if let Some(p) = snapshot.policy.clone() { - p - } else { - // No policy configured on the server. Discover from disk or - // fall back to the restrictive default, then sync to the - // gateway so it becomes the authoritative baseline. - ocsf_emit!( - ConfigStateChangeBuilder::new(ocsf_ctx()) - .severity(SeverityId::Informational) - .status(StatusId::Success) - .state(StateId::Other, "discovery") - .message("Server returned no policy; attempting local discovery") - .build() - ); - let mut discovered = discover_policy_from_disk_or_default(); - // Enrich before syncing so the gateway baseline includes - // baseline paths from the start. - enrich_proto_baseline_paths(&mut discovered); - strip_proto_provider_policy_entries(&mut discovered); - let sandbox = sandbox.as_deref().ok_or_else(|| { - miette::miette!( - "Cannot sync discovered policy: sandbox not available.\n\ - Set OPENSHELL_SANDBOX or --sandbox to enable policy sync." - ) - })?; - - // Sync and re-fetch over a single connection to avoid extra - // TLS handshakes. - let ws = snapshot.workspace.clone(); - snapshot = grpc_retry("Policy discovery sync", || { - openshell_core::grpc_client::sync_policy_and_fetch_snapshot( - endpoint, + let instance_id = uuid::Uuid::new_v4().to_string(); + // Capture the previous instance once. Registration retries must never + // rebase this fence and displace a newer supervisor instance. + let registration_snapshot = loop { + match gateway.snapshot(id).await { + Ok(snapshot) => break snapshot, + Err(_) => tokio::time::sleep(Duration::from_secs(2)).await, + } + }; + loop { + if gateway + .report( id, - sandbox, - &discovered, - &ws, + &instance_id, + Some(®istration_snapshot), + ConfigurationAdmissionState::Pending, + "", ) - }) - .await?; - snapshot.policy.clone().ok_or_else(|| { - miette::miette!("Server still returned no policy after sync — this is a bug") - })? - }; + .await + .is_ok() + { + break; + } + tokio::time::sleep(Duration::from_secs(2)).await; + } + let discovery = image_discovery.unwrap_or_else(discover_image_policy); + loop { + let Ok(mut snapshot) = gateway.snapshot(id).await else { + let _ = gateway.report(id, &instance_id, None, ConfigurationAdmissionState::Rejected, "Effective configuration is unavailable; inspect sandbox policy and providers").await; + tokio::time::sleep(Duration::from_secs(2)).await; + continue; + }; - // True only while `snapshot` describes the exact policy that will be - // constructed below. If enrichment cannot be synced and re-fetched, - // the policy remains enforceable but cannot be acknowledged by - // inferred structural equality. - let mut policy_bound_to_snapshot = true; - - // Ensure baseline filesystem paths are present for proxy-mode - // sandboxes. If the policy was enriched, sync the updated version - // back to the gateway so users can see the effective policy. - let enriched = enrich_proto_baseline_paths(&mut proto_policy); - let sync_policy = proto_sync_payload_for_enriched_policy(&proto_policy, enriched); - if let Some(sync_policy) = sync_policy { - if let Some(sandbox_name) = sandbox.as_deref() { - match openshell_core::grpc_client::sync_policy_and_fetch_snapshot( + if snapshot.policy.is_none() && !snapshot.configuration_error.is_empty() { + reject_startup_configuration( + gateway, endpoint, id, - sandbox_name, - &sync_policy, - &snapshot.workspace, + &instance_id, + &snapshot, + &snapshot.configuration_error, ) - .await - { - Ok(canonical) => { - if let Some(policy) = canonical.policy.clone() { - proto_policy = policy; - snapshot = canonical; - } else { + .await; + continue; + } + + let mut proto_policy = if let Some(p) = snapshot.policy.clone() { + p + } else { + // No policy configured on the server. Discover from disk or + // fall back to the restrictive default, then sync to the + // gateway so it becomes the authoritative baseline. + ocsf_emit!( + ConfigStateChangeBuilder::new(ocsf_ctx()) + .severity(SeverityId::Informational) + .status(StatusId::Success) + .state(StateId::Other, "discovery") + .message("Server returned no policy; attempting local discovery") + .build() + ); + let mut discovered = match &discovery { + sidecar_control::ImagePolicyDiscovery::Policy(policy) => *policy.clone(), + sidecar_control::ImagePolicyDiscovery::Missing => { + openshell_policy::restrictive_default_policy() + } + sidecar_control::ImagePolicyDiscovery::Invalid => { + reject_startup_configuration(gateway, endpoint, id, &instance_id, &snapshot, "Image policy is invalid; replace the sandbox policy to repair configuration").await; + continue; + } + }; + // Enrich before syncing so the gateway baseline includes + // baseline paths from the start. + enrich_proto_baseline_paths(&mut discovered); + strip_proto_provider_policy_entries(&mut discovered); + let sandbox = sandbox.as_deref().ok_or_else(|| { + miette::miette!( + "Cannot sync discovered policy: sandbox not available.\n\ + Set OPENSHELL_SANDBOX or --sandbox to enable policy sync." + ) + })?; + + // Sync and re-fetch over a single connection to avoid extra + // TLS handshakes. + let ws = snapshot.workspace.clone(); + snapshot = if let Ok(snapshot) = gateway.sync(id, sandbox, &discovered, &ws).await { + snapshot + } else { + reject_startup_configuration(gateway, endpoint, id, &instance_id, &snapshot, "Image policy synchronization failed; replace the sandbox policy to repair configuration").await; + continue; + }; + if let Some(policy) = snapshot.policy.clone() { + policy + } else { + reject_startup_configuration( + gateway, + endpoint, + id, + &instance_id, + &snapshot, + "Effective policy is unavailable after image discovery", + ) + .await; + continue; + } + }; + + // True only while `snapshot` describes the exact policy that will be + // constructed below. If enrichment cannot be synced and re-fetched, + // the policy remains enforceable but cannot be acknowledged by + // inferred structural equality. + let mut policy_bound_to_snapshot = true; + + // Ensure baseline filesystem paths are present for proxy-mode + // sandboxes. If the policy was enriched, sync the updated version + // back to the gateway so users can see the effective policy. + let enriched = enrich_proto_baseline_paths(&mut proto_policy); + let sync_policy = proto_sync_payload_for_enriched_policy(&proto_policy, enriched); + if let Some(sync_policy) = sync_policy { + if let Some(sandbox_name) = sandbox.as_deref() { + match gateway + .sync(id, sandbox_name, &sync_policy, &snapshot.workspace) + .await + { + Ok(canonical) => { + if let Some(policy) = canonical.policy.clone() { + proto_policy = policy; + snapshot = canonical; + } else { + policy_bound_to_snapshot = false; + warn!( + "Gateway returned no policy after enrichment sync; initial revision will be reconciled" + ); + } + } + Err(e) => { policy_bound_to_snapshot = false; warn!( - "Gateway returned no policy after enrichment sync; initial revision will be reconciled" + error = %e, + "Failed to sync enriched policy back to gateway; initial revision will be reconciled" ); } } - Err(e) => { - policy_bound_to_snapshot = false; - warn!( - error = %e, - "Failed to sync enriched policy back to gateway; initial revision will be reconciled" - ); - } + } else { + policy_bound_to_snapshot = false; } - } else { - policy_bound_to_snapshot = false; } - } - let mut loaded_policy_revision = - policy_bound_to_snapshot.then(|| LoadedPolicyRevision::from_snapshot(&snapshot)); - - // Build OPA engine from baked-in rules + typed proto data. - // In cluster mode, proxy networking is always enabled so OPA is - // always required for allow/deny decisions. - // The initial load uses pid=0 (no symlink resolution) because the - // container hasn't started yet. After the entrypoint spawns, the - // engine is rebuilt with the real PID for symlink resolution. - info!("Creating OPA engine from proto policy data"); - let mut has_last_valid_policy = true; - let engine = match OpaEngine::from_proto(&proto_policy) { - Ok(engine) => Arc::new(engine), - Err(e) => { - report_initial_policy_failure(endpoint, id, loaded_policy_revision.as_ref(), &e) - .await; - let validation_error = e.to_string(); - let candidate_version = snapshot.version; - let candidate_hash = snapshot.policy_hash.clone(); - // There is no in-memory last-known-good generation during - // startup, so both configured modes necessarily fail closed. - // Load the restrictive default atomically and keep the - // rejected revision unacknowledged for poll reconciliation. - has_last_valid_policy = false; - proto_policy = openshell_policy::restrictive_default_policy(); - let engine = Arc::new(OpaEngine::from_proto(&proto_policy)?); - let disposition = apply_policy_validation_failure( - &engine, - snapshot.policy_validation_failure_mode, - has_last_valid_policy, - candidate_version, - &validation_error, - )?; - emit_policy_validation_failure( - &disposition, - candidate_version, - &candidate_hash, - &validation_error, - ); - loaded_policy_revision = None; - engine - } - }; + let loaded_policy_revision = policy_bound_to_snapshot.then(|| { + let mut revision = LoadedPolicyRevision::from_snapshot(&snapshot); + revision.admission_instance_id = Some(instance_id.clone()); + revision + }); - // Install the in-process catalog before any external connection can - // fail. A newly started sandbox must always be able to resolve built-in - // bindings, even while operator-run services are unavailable. - install_builtin_middleware_registry(&engine).await?; - - // Connect operator-registered middleware services. A connect/describe - // failure keeps the built-in registry active so each request's - // `on_error` policy governs matched traffic. The policy poll loop - // retries the install without waiting for a config change. - let middleware_services = snapshot.supervisor_middleware_services.clone(); - let middleware_registry_status = if middleware_services.is_empty() { + // Build OPA engine from baked-in rules + typed proto data. + // In cluster mode, proxy networking is always enabled so OPA is + // always required for allow/deny decisions. + // The initial load uses pid=0 (no symlink resolution) because the + // container hasn't started yet. After the entrypoint spawns, the + // engine is rebuilt with the real PID for symlink resolution. + info!("Creating OPA engine from proto policy data"); + let has_last_valid_policy = true; + if !snapshot.configuration_admitted || !policy_bound_to_snapshot { + reject_startup_configuration( + gateway, + endpoint, + id, + &instance_id, + &snapshot, + if snapshot.configuration_error.is_empty() { + "Effective configuration was rejected by admission" + } else { + &snapshot.configuration_error + }, + ) + .await; + continue; + } + let Ok(provider) = gateway.provider(id).await else { + reject_startup_configuration( + gateway, + endpoint, + id, + &instance_id, + &snapshot, + "Provider environment is unavailable", + ) + .await; + continue; + }; + let (engine, policy, captured_provider_credentials) = + match prepare_startup_configuration(&snapshot, &proto_policy, provider) { + Ok(prepared) => prepared, + Err(error) => { + report_initial_policy_failure( + endpoint, + id, + loaded_policy_revision.as_ref(), + &error, + ) + .await; + reject_startup_configuration( + gateway, + endpoint, + id, + &instance_id, + &snapshot, + "Policy or provider environment failed runtime validation", + ) + .await; + continue; + } + }; + let engine = Arc::new(engine); + + // Install the in-process catalog before any external connection can + // fail. A newly started sandbox must always be able to resolve built-in + // bindings, even while operator-run services are unavailable. + install_builtin_middleware_registry(&engine).await?; + + // Connect operator-registered middleware services. A connect/describe + // failure keeps the built-in registry active so each request's + // `on_error` policy governs matched traffic. The policy poll loop + // retries the install without waiting for a config change. + let middleware_services = snapshot.supervisor_middleware_services.clone(); + let middleware_registry_status = if middleware_services.is_empty() { MiddlewareRegistryStatus::Synchronized } else if let Err(error) = grpc_retry("Middleware connect", || { let middleware_services = middleware_services.clone(); @@ -2574,28 +2847,39 @@ async fn load_policy( } else { MiddlewareRegistryStatus::Synchronized }; - let opa_engine = Some(engine); + let opa_engine = Some(engine); - let policy = match SandboxPolicy::try_from(proto_policy.clone()) { - Ok(policy) => policy, - Err(e) => { - report_initial_policy_failure(endpoint, id, loaded_policy_revision.as_ref(), &e) - .await; - return Err(e); + // The gateway compares the entire tuple again. A concurrent repair or + // provider rotation invalidates this candidate before any workload + // identity, child environment or services are captured. + if gateway + .report( + id, + &instance_id, + Some(&snapshot), + ConfigurationAdmissionState::Accepted, + "", + ) + .await + .is_err() + { + tokio::time::sleep(Duration::from_secs(2)).await; + continue; } - }; - return Ok(( - policy, - opa_engine, - Some(proto_policy), - middleware_registry_status, - LoadedPolicyOrigin::Gateway { - revision: loaded_policy_revision, - has_last_valid_policy, - }, - agent_proposals_enabled_from_settings(&snapshot.settings), - snapshot.extension_authentication_enabled, - )); + return Ok(( + policy, + opa_engine, + Some(proto_policy), + middleware_registry_status, + LoadedPolicyOrigin::Gateway { + revision: loaded_policy_revision, + has_last_valid_policy, + }, + agent_proposals_enabled_from_settings(&snapshot.settings), + snapshot.extension_authentication_enabled, + Some(captured_provider_credentials), + )); + } } // No policy source available @@ -2606,112 +2890,99 @@ async fn load_policy( )) } -/// Try to discover a sandbox policy from the well-known disk path, falling -/// back to the legacy path, then to the hardcoded restrictive default. -fn discover_policy_from_disk_or_default() -> openshell_core::proto::SandboxPolicy { - let primary = std::path::Path::new(openshell_policy::CONTAINER_POLICY_PATH); - if primary.exists() { - return discover_policy_from_path(primary); +/// Capture the policy from the workload filesystem, preserving invalid input +/// as a repairable error instead of silently substituting another policy. +fn discover_image_policy() -> sidecar_control::ImagePolicyDiscovery { + use sidecar_control::ImagePolicyDiscovery; + for path in [ + openshell_policy::CONTAINER_POLICY_PATH, + openshell_policy::LEGACY_CONTAINER_POLICY_PATH, + ] { + match discover_image_policy_from_path(std::path::Path::new(path)) { + ImagePolicyDiscovery::Missing => {} + discovered => return discovered, + } } - let legacy = std::path::Path::new(openshell_policy::LEGACY_CONTAINER_POLICY_PATH); - if legacy.exists() { - ocsf_emit!( - ConfigStateChangeBuilder::new(ocsf_ctx()) - .severity(SeverityId::Informational) - .status(StatusId::Success) - .state(StateId::Enabled, "loaded") - .unmapped( - "legacy_path", - serde_json::json!(legacy.display().to_string()) - ) - .unmapped("new_path", serde_json::json!(primary.display().to_string())) - .message(format!( - "Policy found at legacy path; consider moving [legacy_path:{} new_path:{}]", - legacy.display(), - primary.display() - )) - .build() - ); - return discover_policy_from_path(legacy); + ImagePolicyDiscovery::Missing +} + +fn discover_image_policy_from_path( + path: &std::path::Path, +) -> sidecar_control::ImagePolicyDiscovery { + use sidecar_control::ImagePolicyDiscovery; + match std::fs::read_to_string(path) { + Ok(yaml) => openshell_policy::parse_sandbox_policy(&yaml) + .map_or(ImagePolicyDiscovery::Invalid, |policy| { + ImagePolicyDiscovery::Policy(Box::new(policy)) + }), + Err(error) if error.kind() == std::io::ErrorKind::NotFound => ImagePolicyDiscovery::Missing, + Err(_) => ImagePolicyDiscovery::Invalid, } - discover_policy_from_path(primary) } -/// Try to read a sandbox policy YAML from `path`, falling back to the -/// hardcoded restrictive default if the file is missing or invalid. -fn discover_policy_from_path(path: &std::path::Path) -> openshell_core::proto::SandboxPolicy { - use openshell_policy::{ - parse_sandbox_policy, restrictive_default_policy, validate_sandbox_policy, - }; +/// Everything here is preparation: it cannot mutate an accepted generation. +fn prepare_startup_configuration( + snapshot: &openshell_core::grpc_client::SettingsPollResult, + policy: &openshell_core::proto::SandboxPolicy, + provider: openshell_core::grpc_client::ProviderEnvironmentResult, +) -> Result<(OpaEngine, SandboxPolicy, ProviderCredentialState)> { + if !snapshot.configuration_admitted { + return Err(miette::miette!( + "Effective configuration admission rejected" + )); + } + if snapshot.provider_env_revision != provider.provider_env_revision { + return Err(miette::miette!( + "Provider environment revision changed during configuration preparation" + )); + } + let engine = OpaEngine::from_proto(policy)?; + let process_policy = SandboxPolicy::try_from(policy.clone())?; + let credentials = prepare_provider_environment(provider)?; + Ok((engine, process_policy, credentials)) +} - let Ok(yaml) = std::fs::read_to_string(path) else { - ocsf_emit!( - ConfigStateChangeBuilder::new(ocsf_ctx()) - .severity(SeverityId::Informational) - .status(StatusId::Success) - .state(StateId::Enabled, "default") - .message(format!( - "No policy file on disk, using restrictive default [path:{}]", - path.display() - )) - .build() - ); - return restrictive_default_policy(); - }; +fn prepare_provider_environment( + provider: openshell_core::grpc_client::ProviderEnvironmentResult, +) -> Result { + ProviderCredentialState::from_bound_environment( + provider.provider_env_revision, + provider.environment, + provider.credential_expires_at_ms, + provider.dynamic_credentials, + provider.static_credential_bindings, + provider.non_secret_environment_keys, + ) + .map_err(|_| miette::miette!("Provider credential bindings are invalid")) +} + +async fn reject_startup_configuration( + gateway: &impl StartupGateway, + _endpoint: &str, + sandbox_id: &str, + instance_id: &str, + snapshot: &openshell_core::grpc_client::SettingsPollResult, + error: &str, +) { + let _ = gateway + .report( + sandbox_id, + instance_id, + Some(snapshot), + openshell_core::proto::ConfigurationAdmissionState::Rejected, + error, + ) + .await; + // Fixed, bounded diagnostics deliberately omit the candidate and credentials. ocsf_emit!( ConfigStateChangeBuilder::new(ocsf_ctx()) - .severity(SeverityId::Informational) - .status(StatusId::Success) - .state(StateId::Enabled, "loaded") - .message(format!( - "Loaded sandbox policy from container disk [path:{}]", - path.display() - )) + .severity(SeverityId::High) + .status(StatusId::Failure) + .state(StateId::Disabled, "configuration_error") + .message(error) .build() ); - match parse_sandbox_policy(&yaml) { - Ok(policy) => { - // Validate the disk-loaded policy for safety. - if let Err(violations) = validate_sandbox_policy(&policy) { - let messages: Vec = violations.iter().map(ToString::to_string).collect(); - ocsf_emit!(DetectionFindingBuilder::new(ocsf_ctx()) - .activity(ActivityId::Open) - .severity(SeverityId::Medium) - .action(ActionId::Denied) - .disposition(DispositionId::Blocked) - .finding_info( - FindingInfo::new( - "unsafe-disk-policy", - "Unsafe Disk Policy Content", - ) - .with_desc(&format!( - "Disk policy at {} contains unsafe content: {}", - path.display(), - messages.join("; "), - )), - ) - .message(format!( - "Disk policy contains unsafe content, using restrictive default [path:{}]", - path.display() - )) - .build()); - return restrictive_default_policy(); - } - policy - } - Err(e) => { - ocsf_emit!(ConfigStateChangeBuilder::new(ocsf_ctx()) - .severity(SeverityId::Medium) - .status(StatusId::Failure) - .state(StateId::Other, "fallback") - .message(format!( - "Failed to parse disk policy, using restrictive default [path:{} error:{e}]", - path.display() - )) - .build()); - restrictive_default_policy() - } - } + tokio::time::sleep(Duration::from_secs(2)).await; } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -2770,12 +3041,32 @@ struct MiddlewareReloadContext<'a> { connector: &'a MiddlewareConnector, } +#[cfg(test)] async fn reload_gateway_policy_runtime( engine: &OpaEngine, policy: Option<&openshell_core::proto::SandboxPolicy>, entrypoint_pid: u32, middleware: MiddlewareReloadContext<'_>, transparent_tcp: TransparentTcpReloadState, +) -> std::result::Result<(), GatewayRuntimeReloadError> { + reload_gateway_configuration_runtime( + engine, + policy, + entrypoint_pid, + middleware, + transparent_tcp, + || {}, + ) + .await +} + +async fn reload_gateway_configuration_runtime( + engine: &OpaEngine, + policy: Option<&openshell_core::proto::SandboxPolicy>, + entrypoint_pid: u32, + middleware: MiddlewareReloadContext<'_>, + transparent_tcp: TransparentTcpReloadState, + commit_credentials: impl FnOnce(), ) -> std::result::Result<(), GatewayRuntimeReloadError> { if let Some(policy) = policy && policy_contains_explicit_tcp(policy) @@ -2804,14 +3095,24 @@ async fn reload_gateway_policy_runtime( .await .map_err(GatewayRuntimeReloadError::MiddlewareRegistry)?; engine - .reload_policy_and_middleware_from_proto_with_pid(policy, entrypoint_pid, registry) + .reload_configuration_from_proto_with_pid( + policy, + entrypoint_pid, + Some(registry), + commit_credentials, + ) .map_err(GatewayRuntimeReloadError::PolicyValidation) } // Policy-only change: the installed registry already matches the // delivered service set, so swap the engine alone. This must not // require middleware reachability. Some(policy) => engine - .reload_from_proto_with_pid(policy, entrypoint_pid) + .reload_configuration_from_proto_with_pid( + policy, + entrypoint_pid, + None, + commit_credentials, + ) .map_err(GatewayRuntimeReloadError::PolicyValidation), None => Err(GatewayRuntimeReloadError::PolicyValidation( miette::miette!("runtime reload requires a policy payload but none was returned"), @@ -2873,6 +3174,8 @@ struct LoadedPolicyRevision { policy_hash: String, config_revision: u64, policy_source: openshell_core::proto::PolicySource, + admission_instance_id: Option, + provider_env_revision: u64, } /// Identifies where the policy currently loaded into OPA came from. @@ -2915,6 +3218,8 @@ impl LoadedPolicyRevision { policy_hash: snapshot.policy_hash.clone(), config_revision: snapshot.config_revision, policy_source: snapshot.policy_source, + admission_instance_id: None, + provider_env_revision: snapshot.provider_env_revision, } } } @@ -3002,6 +3307,11 @@ fn initial_policy_ack_candidate( canonical: &openshell_core::grpc_client::SettingsPollResult, ) -> Option { let loaded = loaded?; + if !canonical.configuration_admitted + || canonical.provider_env_revision != loaded.provider_env_revision + { + return None; + } if loaded.policy_source != openshell_core::proto::PolicySource::Sandbox || canonical.policy_source != openshell_core::proto::PolicySource::Sandbox { @@ -3730,6 +4040,49 @@ fn emit_policy_validation_failure( } } +async fn report_runtime_configuration( + ctx: &PolicyPollLoopContext, + snapshot: &openshell_core::grpc_client::SettingsPollResult, + accepted: bool, + error: &str, +) -> bool { + let LoadedPolicyOrigin::Gateway { + revision: Some(revision), + .. + } = &ctx.loaded_policy_origin + else { + return true; + }; + let Some(instance_id) = revision.admission_instance_id.as_deref() else { + return true; + }; + let state = if accepted { + openshell_core::proto::ConfigurationAdmissionState::Accepted + } else { + openshell_core::proto::ConfigurationAdmissionState::Rejected + }; + if !accepted { + ocsf_emit!( + ConfigStateChangeBuilder::new(ocsf_ctx()) + .severity(SeverityId::High) + .status(StatusId::Failure) + .state(StateId::Other, "configuration_error") + .message(error) + .build() + ); + } + openshell_core::grpc_client::report_sandbox_configuration( + &ctx.endpoint, + &ctx.sandbox_id, + instance_id, + Some(snapshot), + state, + error, + ) + .await + .is_ok() +} + async fn run_policy_poll_loop(ctx: PolicyPollLoopContext) -> Result<()> { let client = openshell_core::grpc_client::CachedOpenShellClient::connect_with_credentials( &ctx.endpoint, @@ -3884,6 +4237,30 @@ async fn run_policy_poll_loop_with_client( std::collections::HashMap::new() }; + if reloads_gateway_policy && !result.configuration_admitted { + let disposition = apply_policy_validation_failure( + &ctx.opa_engine, + result.policy_validation_failure_mode, + has_last_valid_policy, + result.version, + &result.configuration_error, + )?; + emit_policy_validation_failure( + &disposition, + result.version, + &result.policy_hash, + &result.configuration_error, + ); + rejected_policy_generation = Some(RejectedPolicyGeneration { + version: result.version, + policy_hash: result.policy_hash.clone(), + validation_error: result.configuration_error.clone(), + configured_mode: result.policy_validation_failure_mode, + }); + report_runtime_configuration(&ctx, &result, false, &result.configuration_error).await; + continue; + } + let config_changed = result.config_revision != current_config_revision; let provider_env_changed = result.provider_env_revision != current_provider_env_revision; let policy_changed = result.policy_hash != current_policy_hash; @@ -3900,10 +4277,10 @@ async fn run_policy_poll_loop_with_client( // equals `current_policy_hash`, but the runtime is still quarantined // and must reload (or it would remain deny-all indefinitely). let recovering_rejected_policy = reloads_gateway_policy - && rejected_policy_generation - .as_ref() - .is_some_and(|rejected| rejected.policy_hash != result.policy_hash); - let policy_runtime_changed = recovering_rejected_policy + && rejected_policy_generation.is_some() + && result.configuration_admitted; + let policy_runtime_changed = (reloads_gateway_policy && provider_env_changed) + || recovering_rejected_policy || extension_authentication_changed || gateway_policy_runtime_needs_reconciliation( reloads_gateway_policy, @@ -4002,83 +4379,48 @@ async fn run_policy_poll_loop_with_client( .build()); } - if provider_env_changed { - match openshell_core::grpc_client::fetch_provider_environment( + // Prepare the matching environment off to the side. Fetch errors and + // invalid bindings preserve the previously accepted credential state. + let prepared_provider = if provider_env_changed { + let provider = match openshell_core::grpc_client::fetch_provider_environment( &ctx.endpoint, &ctx.sandbox_id, ) .await { - Ok(env_result) => { - let provider_env_revision = env_result.provider_env_revision; - let install_result = ctx.provider_credentials.install_bound_environment( - provider_env_revision, - env_result.environment, - env_result.credential_expires_at_ms, - env_result.dynamic_credentials, - env_result.static_credential_bindings, - env_result.non_secret_environment_keys, - ); - if let Err(error) = install_result { - ocsf_emit!( - ConfigStateChangeBuilder::new(ocsf_ctx()) - .severity(SeverityId::High) - .status(StatusId::Failure) - .state(StateId::Disabled, "fail_closed") - .message(format!( - "Rejected provider environment refresh; static provider credentials were revoked; fetched dynamic token grants remain active: {error}" - )) - .build() - ); - } else { - let child_env = ctx.provider_credentials.child_env_with_gcp_resolved(); - let env_count = child_env.len(); - if let Some(publisher) = ctx.sidecar_control_publisher.as_ref() { - publisher - .publish_provider_env(provider_env_revision, child_env.clone()); - } - current_provider_env_revision = provider_env_revision; - ocsf_emit!( - ConfigStateChangeBuilder::new(ocsf_ctx()) - .severity(SeverityId::Informational) - .status(StatusId::Success) - .state(StateId::Enabled, "loaded") - .unmapped( - "provider_env_revision", - serde_json::json!(provider_env_revision) - ) - .message(format!( - "Provider environment refreshed [revision:{provider_env_revision} env_count:{env_count}]" - )) - .build() - ); - } + Ok(provider) if provider.provider_env_revision == result.provider_env_revision => { + provider } - Err(e) => { - ctx.provider_credentials - .revoke_static_provider_environment(result.provider_env_revision); - warn!( - error = %e, - provider_env_revision = result.provider_env_revision, - "Settings poll: failed to refresh provider environment; static provider credentials were revoked; previous dynamic token grants remain active" - ); - ocsf_emit!( - ConfigStateChangeBuilder::new(ocsf_ctx()) - .severity(SeverityId::High) - .status(StatusId::Failure) - .state(StateId::Disabled, "fail_closed") - .message( - "Provider environment refresh failed; static provider credentials were revoked; previous dynamic token grants remain active" - ) - .build() - ); + _ => { + report_runtime_configuration( + &ctx, + &result, + false, + "Provider environment is unavailable or changed during preparation", + ) + .await; + continue; } + }; + if let Ok(prepared) = prepare_provider_environment(provider) { + Some(prepared) + } else { + report_runtime_configuration( + &ctx, + &result, + false, + "Provider environment bindings failed validation", + ) + .await; + continue; } - } + } else { + None + }; if policy_runtime_changed { let pid = ctx.entrypoint_pid.load(Ordering::Acquire); - let runtime_result = reload_gateway_policy_runtime( + let runtime_result = reload_gateway_configuration_runtime( &ctx.opa_engine, result.policy.as_ref(), pid, @@ -4092,6 +4434,11 @@ async fn run_policy_poll_loop_with_client( connector: &ctx.middleware_connector, }, ctx.transparent_tcp, + || { + if let Some(prepared) = prepared_provider.as_ref() { + ctx.provider_credentials.install_prepared(prepared); + } + }, ) .await; @@ -4108,13 +4455,6 @@ async fn run_policy_poll_loop_with_client( if let Some(policy_local_ctx) = ctx.policy_local_ctx.as_ref() { policy_local_ctx.set_current_policy(policy.clone()).await; } - if let Some(publisher) = ctx.sidecar_control_publisher.as_ref() { - publisher.publish_policy( - policy.clone(), - result.policy_hash.clone(), - result.config_revision, - ); - } if result.global_policy_version > 0 { ocsf_emit!(ConfigStateChangeBuilder::new(ocsf_ctx()) .severity(SeverityId::Informational) @@ -4286,6 +4626,29 @@ async fn run_policy_poll_loop_with_client( } } + if policy_runtime_changed && !policy_runtime_reconciled { + report_runtime_configuration(&ctx, &result, false, "Effective configuration failed runtime preparation; prior credentials remain installed").await; + continue; + } + if !reloads_gateway_policy && let Some(prepared) = prepared_provider.as_ref() { + ctx.provider_credentials.install_prepared(prepared); + } + if provider_env_changed || policy_runtime_reconciled { + current_provider_env_revision = result.provider_env_revision; + if let (Some(publisher), Some(policy)) = ( + ctx.sidecar_control_publisher.as_ref(), + result.policy.as_ref(), + ) { + publisher.publish_configuration( + policy.clone(), + result.policy_hash.clone(), + result.config_revision, + current_provider_env_revision, + ctx.provider_credentials.child_env_with_gcp_resolved(), + ); + } + } + if let Some(version) = unchanged_policy_revision_ready_to_ack( unchanged_policy_revision, policy_runtime_changed, @@ -4318,6 +4681,11 @@ async fn run_policy_poll_loop_with_client( skills::install_static_skills, ); + if !report_runtime_configuration(&ctx, &result, true, "").await { + // Retry the exact status tuple on the next poll before advancing + // the observed revision; an old instance cannot claim readiness. + continue; + } current_config_revision = result.config_revision; if !reloads_gateway_policy { current_policy_hash = result.policy_hash; @@ -4829,15 +5197,12 @@ mod tests { // ---- Policy disk discovery tests ---- #[test] - fn discover_policy_from_nonexistent_path_returns_restrictive_default() { + fn discover_policy_from_nonexistent_path_is_missing() { let path = std::path::Path::new("/nonexistent/policy.yaml"); - let policy = discover_policy_from_path(path); - // Restrictive default has no network policies. - assert!(policy.network_policies.is_empty()); - // It keeps filesystem restrictions while leaving identity to the - // active compute driver. - assert!(policy.filesystem.is_some()); - assert!(policy.process.is_none()); + assert!(matches!( + discover_image_policy_from_path(path), + sidecar_control::ImagePolicyDiscovery::Missing + )); } #[test] @@ -4865,7 +5230,11 @@ network_policies: ) .unwrap(); - let policy = discover_policy_from_path(&path); + let sidecar_control::ImagePolicyDiscovery::Policy(policy) = + discover_image_policy_from_path(&path) + else { + panic!("expected parsed policy") + }; assert_eq!(policy.network_policies.len(), 1); assert!(policy.network_policies.contains_key("test")); let fs = policy.filesystem.unwrap(); @@ -4873,19 +5242,19 @@ network_policies: } #[test] - fn discover_policy_from_invalid_yaml_returns_restrictive_default() { + fn discover_policy_from_invalid_yaml_remains_invalid() { let dir = tempfile::tempdir().unwrap(); let path = dir.path().join("policy.yaml"); std::fs::write(&path, "this is not valid yaml: [[[").unwrap(); - let policy = discover_policy_from_path(&path); - // Falls back to restrictive default. - assert!(policy.network_policies.is_empty()); - assert!(policy.filesystem.is_some()); + assert!(matches!( + discover_image_policy_from_path(&path), + sidecar_control::ImagePolicyDiscovery::Invalid + )); } #[test] - fn discover_policy_from_unsafe_yaml_falls_back_to_default() { + fn discover_policy_from_unsafe_yaml_preserves_candidate_for_admission() { let dir = tempfile::tempdir().unwrap(); let path = dir.path().join("policy.yaml"); std::fs::write( @@ -4905,9 +5274,12 @@ filesystem_policy: ) .unwrap(); - let policy = discover_policy_from_path(&path); - // Falls back to restrictive default because of root user. - assert!(policy.process.is_none()); + let sidecar_control::ImagePolicyDiscovery::Policy(policy) = + discover_image_policy_from_path(&path) + else { + panic!("expected parsed policy") + }; + assert!(openshell_policy::validate_sandbox_policy(&policy).is_err()); } #[test] @@ -4961,7 +5333,252 @@ network_policies: workspace: String::new(), policy_validation_failure_mode: PolicyValidationFailureMode::default(), extension_authentication_enabled: false, + configuration_admitted: true, + configuration_error: String::new(), + configuration_instance_id: String::new(), + } + } + + #[derive(Clone)] + struct TestStartupGateway { + desired: Arc>, + reports: UnboundedSender, + reject_next_accept: Arc, + } + + #[tonic::async_trait] + impl StartupGateway for TestStartupGateway { + async fn snapshot( + &self, + _id: &str, + ) -> Result { + Ok(self.desired.lock().unwrap().clone()) + } + async fn provider( + &self, + _id: &str, + ) -> Result { + Ok(startup_provider( + self.desired.lock().unwrap().provider_env_revision, + )) + } + async fn sync( + &self, + _id: &str, + _sandbox: &str, + _policy: &openshell_core::proto::SandboxPolicy, + _workspace: &str, + ) -> Result { + self.snapshot("").await } + async fn report( + &self, + _id: &str, + _instance_id: &str, + snapshot: Option<&openshell_core::grpc_client::SettingsPollResult>, + state: openshell_core::proto::ConfigurationAdmissionState, + _error: &str, + ) -> Result<()> { + use openshell_core::proto::ConfigurationAdmissionState; + self.reports.send(state).unwrap(); + if state == ConfigurationAdmissionState::Accepted { + if self.reject_next_accept.swap(false, Ordering::SeqCst) { + return Err(miette::miette!( + "desired generation changed before activation" + )); + } + assert_eq!( + snapshot.unwrap().config_revision, + self.desired.lock().unwrap().config_revision + ); + } + Ok(()) + } + } + + #[tokio::test] + async fn startup_waits_for_repair_and_retries_stale_activation_before_returning() { + use openshell_core::proto::{ConfigurationAdmissionState, PolicySource}; + let mut policy = proto_policy_fixture(); + enrich_proto_baseline_paths(&mut policy); + let mut rejected = settings_poll_result(Some(policy), 1, PolicySource::Sandbox); + rejected.configuration_admitted = false; + let (reports, mut reported) = tokio::sync::mpsc::unbounded_channel(); + let gateway = TestStartupGateway { + desired: Arc::new(std::sync::Mutex::new(rejected)), + reports, + reject_next_accept: Arc::new(AtomicBool::new(true)), + }; + let active_gateway = gateway.clone(); + let handle = tokio::spawn(async move { + load_policy_with_gateway( + Some("sandbox-id".to_string()), + Some("sandbox".to_string()), + Some("http://unused.invalid".to_string()), + None, + None, + &openshell_extension_core::ExtensionCredentialStore::new(), + Some(sidecar_control::ImagePolicyDiscovery::Missing), + &active_gateway, + ) + .await + }); + assert_eq!( + reported.recv().await, + Some(ConfigurationAdmissionState::Pending) + ); + assert_eq!( + reported.recv().await, + Some(ConfigurationAdmissionState::Rejected) + ); + assert!( + !handle.is_finished(), + "rejected configuration must not return a launch bundle" + ); + { + let mut desired = gateway.desired.lock().unwrap(); + desired.configuration_admitted = true; + desired.config_revision += 1; + } + assert_eq!( + timeout(Duration::from_secs(5), reported.recv()) + .await + .unwrap(), + Some(ConfigurationAdmissionState::Accepted) + ); + assert!( + !handle.is_finished(), + "a stale activation acknowledgement must not return a launch bundle" + ); + assert_eq!( + timeout(Duration::from_secs(5), reported.recv()) + .await + .unwrap(), + Some(ConfigurationAdmissionState::Accepted) + ); + let bundle = timeout(Duration::from_secs(5), handle) + .await + .unwrap() + .unwrap() + .expect("repair returns one launch bundle"); + assert!( + bundle.7.is_some(), + "launch bundle retains matching provider state" + ); + } + + #[tokio::test] + async fn sidecar_configuration_rejects_invalid_and_reordered_generations() { + let credentials = + ProviderCredentialState::from_child_env_snapshot(1, std::collections::HashMap::new()); + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + let handle = spawn_sidecar_control_update_watcher( + rx, + credentials.clone(), + AgentProposals::new(false), + Arc::new(tokio::sync::Mutex::new(None)), + 1, + ); + let mut invalid = proto_tcp_policy_fixture(); + invalid + .network_policies + .values_mut() + .next() + .unwrap() + .endpoints[0] + .protocol = "invalid".to_string(); + for (generation, revision, policy) in [ + (3, 3, invalid), + (2, 2, proto_policy_fixture()), + (1, 99, proto_policy_fixture()), + ] { + tx.send(sidecar_control::ControlUpdate::Configuration { + policy_proto: Box::new(policy), + policy_hash: format!("hash-{revision}"), + config_revision: revision, + provider_env_revision: revision, + provider_env_generation: generation, + provider_child_env: std::collections::HashMap::from([( + "ACCEPTED".to_string(), + revision.to_string(), + )]), + }) + .unwrap(); + } + drop(tx); + handle.await.unwrap(); + assert_eq!(credentials.revision(), 2); + assert_eq!( + credentials + .snapshot() + .child_env + .get("ACCEPTED") + .map(String::as_str), + Some("2") + ); + } + + fn startup_provider(revision: u64) -> openshell_core::grpc_client::ProviderEnvironmentResult { + openshell_core::grpc_client::ProviderEnvironmentResult { + provider_env_revision: revision, + environment: std::collections::HashMap::new(), + credential_expires_at_ms: std::collections::HashMap::new(), + dynamic_credentials: std::collections::HashMap::new(), + static_credential_bindings: std::collections::HashMap::new(), + non_secret_environment_keys: Vec::new(), + } + } + + #[test] + fn startup_configuration_rejects_mixed_provider_revision() { + let policy = proto_policy_fixture(); + let mut snapshot = settings_poll_result( + Some(policy.clone()), + 1, + openshell_core::proto::PolicySource::Sandbox, + ); + snapshot.provider_env_revision = 10; + assert!(prepare_startup_configuration(&snapshot, &policy, startup_provider(11)).is_err()); + let (_, _, credentials) = + prepare_startup_configuration(&snapshot, &policy, startup_provider(10)) + .expect("matching generation is admitted"); + assert_eq!(credentials.revision(), 10); + } + + #[test] + fn startup_configuration_revalidates_on_restart_and_accepts_repair() { + let policy = proto_policy_fixture(); + let mut snapshot = settings_poll_result( + Some(policy.clone()), + 1, + openshell_core::proto::PolicySource::Sandbox, + ); + for _restart in 0..2 { + snapshot.configuration_admitted = false; + assert!( + prepare_startup_configuration(&snapshot, &policy, startup_provider(0)).is_err() + ); + snapshot.configuration_admitted = true; + assert!(prepare_startup_configuration(&snapshot, &policy, startup_provider(0)).is_ok()); + } + } + + #[test] + fn startup_configuration_does_not_substitute_invalid_opa_policy() { + let mut policy = proto_tcp_policy_fixture(); + policy + .network_policies + .values_mut() + .next() + .expect("fixture has policy") + .endpoints[0] + .protocol = "invalid-protocol".to_string(); + let snapshot = settings_poll_result( + Some(policy.clone()), + 1, + openshell_core::proto::PolicySource::Sandbox, + ); + assert!(prepare_startup_configuration(&snapshot, &policy, startup_provider(0)).is_err()); } #[derive(Clone)] diff --git a/crates/openshell-sandbox/src/sidecar_control.rs b/crates/openshell-sandbox/src/sidecar_control.rs index 11f3e68e23..b85636f53a 100644 --- a/crates/openshell-sandbox/src/sidecar_control.rs +++ b/crates/openshell-sandbox/src/sidecar_control.rs @@ -17,12 +17,27 @@ use std::time::Duration; use tokio::io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader}; use tokio::net::UnixListener; use tokio::net::unix::OwnedWriteHalf; -use tokio::sync::{Mutex, broadcast, mpsc}; +use tokio::sync::{Mutex, broadcast, mpsc, oneshot, watch}; + +/// Discovery belongs to the workload image, not the network sidecar image. +#[derive(Debug, Clone)] +pub enum ImagePolicyDiscovery { + Missing, + Policy(Box), + Invalid, +} + +struct AdmissionHandshake { + discovery: oneshot::Sender, + admitted: watch::Receiver, +} use tracing::{debug, info, warn}; #[derive(Debug, Clone)] pub struct BootstrapData { pub policy_proto: openshell_core::proto::SandboxPolicy, + pub policy_hash: String, + pub config_revision: u64, pub provider_env_revision: u64, pub provider_env_generation: u64, pub provider_child_env: HashMap, @@ -49,6 +64,14 @@ pub struct ExpectedPeer { #[derive(Debug, Clone)] pub enum ControlUpdate { + Configuration { + policy_proto: Box, + policy_hash: String, + config_revision: u64, + provider_env_revision: u64, + provider_env_generation: u64, + provider_child_env: HashMap, + }, ProviderEnv { revision: u64, generation: u64, @@ -72,9 +95,47 @@ pub enum ControlUpdate { pub struct Publisher { state: Arc>, updates: broadcast::Sender, + admitted: watch::Sender, } impl Publisher { + /// Release the initial handshake only after the complete configuration is accepted. + #[cfg_attr(not(target_os = "linux"), allow(dead_code))] + pub fn publish_bootstrap(&self, bootstrap: BootstrapData) { + *self.state.write().expect("sidecar control state poisoned") = bootstrap; + self.admitted.send_replace(true); + } + + /// Publish policy and child environment as one ordered configuration. + pub fn publish_configuration( + &self, + policy_proto: openshell_core::proto::SandboxPolicy, + policy_hash: String, + config_revision: u64, + provider_env_revision: u64, + provider_child_env: HashMap, + ) { + let mut state = self.state.write().expect("sidecar control state poisoned"); + state.policy_proto = policy_proto.clone(); + state.policy_hash.clone_from(&policy_hash); + state.config_revision = config_revision; + state.provider_env_revision = provider_env_revision; + state.provider_env_generation = state + .provider_env_generation + .checked_add(1) + .expect("sidecar configuration generation overflow"); + state.provider_child_env.clone_from(&provider_child_env); + let _ = self.updates.send(WireServerMessage::ConfigurationUpdated { + policy_proto: policy_proto.encode_to_vec(), + policy_hash, + config_revision, + provider_env_revision, + provider_env_generation: state.provider_env_generation, + provider_child_env, + }); + } + + #[cfg(test)] pub fn publish_provider_env(&self, revision: u64, provider_child_env: HashMap) { let mut state = self.state.write().expect("sidecar control state poisoned"); if revision == state.provider_env_revision { @@ -96,24 +157,6 @@ impl Publisher { }); } - pub fn publish_policy( - &self, - policy_proto: openshell_core::proto::SandboxPolicy, - policy_hash: String, - config_revision: u64, - ) { - { - let mut state = self.state.write().expect("sidecar control state poisoned"); - state.policy_proto = policy_proto.clone(); - } - - let _ = self.updates.send(WireServerMessage::PolicyUpdated { - policy_proto: policy_proto.encode_to_vec(), - policy_hash, - config_revision, - }); - } - pub fn publish_agent_proposals(&self, enabled: bool, config_revision: u64) { { let mut state = self.state.write().expect("sidecar control state poisoned"); @@ -140,11 +183,19 @@ impl Publisher { pub struct ServerHandle { publisher: Publisher, #[cfg_attr(not(target_os = "linux"), allow(dead_code))] + discovered_policy: Option>, + #[cfg_attr(not(target_os = "linux"), allow(dead_code))] entrypoint_rx: mpsc::Receiver, connection_task: tokio::task::JoinHandle<()>, } impl ServerHandle { + #[cfg_attr(not(target_os = "linux"), allow(dead_code))] + pub fn take_discovered_policy_receiver( + &mut self, + ) -> Option> { + self.discovered_policy.take() + } pub fn publisher(&self) -> Publisher { self.publisher.clone() } @@ -168,16 +219,28 @@ impl ServerHandle { pub struct ProcessConnection { pub writer: Arc>, pub updates: mpsc::UnboundedReceiver, - pub closed: tokio::sync::oneshot::Receiver<()>, + pub closed: oneshot::Receiver<()>, } #[derive(Debug, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] enum WireClientMessage { - BootstrapRequest { supervisor_pid: u32 }, - EntrypointStarted { pid: u32, instance_id: String }, - MainProcessExited { instance_id: String, exit_code: i32 }, - MainProcessFinalized { instance_id: String }, + BootstrapRequest { + supervisor_pid: u32, + image_policy: Option>, + image_policy_invalid: bool, + }, + EntrypointStarted { + pid: u32, + instance_id: String, + }, + MainProcessExited { + instance_id: String, + exit_code: i32, + }, + MainProcessFinalized { + instance_id: String, + }, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -185,6 +248,8 @@ enum WireClientMessage { enum WireServerMessage { BootstrapResponse { policy_proto: Vec, + policy_hash: String, + config_revision: u64, provider_env_revision: u64, provider_env_generation: u64, provider_child_env: HashMap, @@ -192,6 +257,14 @@ enum WireServerMessage { proxy_ca_cert_path: Option, proxy_ca_bundle_path: Option, }, + ConfigurationUpdated { + policy_proto: Vec, + policy_hash: String, + config_revision: u64, + provider_env_revision: u64, + provider_env_generation: u64, + provider_child_env: HashMap, + }, ProviderEnvUpdated { revision: u64, generation: u64, @@ -216,6 +289,8 @@ impl BootstrapData { fn to_wire(&self) -> WireServerMessage { WireServerMessage::BootstrapResponse { policy_proto: self.policy_proto.encode_to_vec(), + policy_hash: self.policy_hash.clone(), + config_revision: self.config_revision, provider_env_revision: self.provider_env_revision, provider_env_generation: self.provider_env_generation, provider_child_env: self.provider_child_env.clone(), @@ -238,6 +313,8 @@ impl TryFrom for BootstrapData { fn try_from(message: WireServerMessage) -> Result { let WireServerMessage::BootstrapResponse { policy_proto, + policy_hash, + config_revision, provider_env_revision, provider_env_generation, provider_child_env, @@ -261,6 +338,8 @@ impl TryFrom for BootstrapData { Ok(Self { policy_proto, + policy_hash, + config_revision, provider_env_revision, provider_env_generation, provider_child_env, @@ -276,6 +355,31 @@ impl TryFrom for ControlUpdate { fn try_from(message: WireServerMessage) -> Result { match message { + WireServerMessage::ConfigurationUpdated { + policy_proto, + policy_hash, + config_revision, + provider_env_revision, + provider_env_generation, + provider_child_env, + } => { + let policy = openshell_core::proto::SandboxPolicy::decode(policy_proto.as_slice()) + .map_err(|_| { + miette::miette!("failed to decode sidecar configuration policy") + })?; + let policy = canonicalize_sidecar_policy( + policy, + "sidecar configuration policy failed validation", + )?; + Ok(Self::Configuration { + policy_proto: Box::new(policy), + policy_hash, + config_revision, + provider_env_revision, + provider_env_generation, + provider_child_env, + }) + } WireServerMessage::ProviderEnvUpdated { revision, generation, @@ -321,11 +425,41 @@ impl TryFrom for ControlUpdate { } } -#[cfg_attr(not(target_os = "linux"), allow(dead_code))] +#[cfg(test)] pub fn spawn_server( path: &Path, bootstrap: BootstrapData, expected_peer: ExpectedPeer, +) -> Result { + spawn_server_inner(path, bootstrap, expected_peer, true) +} + +/// Bind before image discovery; the authenticated process peer waits for admission. +#[cfg_attr(not(target_os = "linux"), allow(dead_code))] +pub fn spawn_pending_server(path: &Path, expected_peer: ExpectedPeer) -> Result { + spawn_server_inner( + path, + BootstrapData { + policy_proto: openshell_policy::restrictive_default_policy(), + policy_hash: String::new(), + config_revision: 0, + provider_env_revision: 0, + provider_env_generation: 0, + provider_child_env: HashMap::new(), + agent_proposals_enabled: false, + proxy_ca_cert_path: None, + proxy_ca_bundle_path: None, + }, + expected_peer, + false, + ) +} + +fn spawn_server_inner( + path: &Path, + bootstrap: BootstrapData, + expected_peer: ExpectedPeer, + initially_admitted: bool, ) -> Result { if let Some(parent) = path.parent() { std::fs::create_dir_all(parent) @@ -370,9 +504,12 @@ pub fn spawn_server( let state = Arc::new(RwLock::new(bootstrap)); let (updates, _) = broadcast::channel(32); let (entrypoint_tx, entrypoint_rx) = mpsc::channel(8); + let (discovery_tx, discovery_rx) = oneshot::channel(); + let (admitted_tx, admitted_rx) = watch::channel(initially_admitted); let publisher = Publisher { state: state.clone(), updates: updates.clone(), + admitted: admitted_tx, }; let connection_task = tokio::spawn(accept_authoritative_connection( @@ -382,11 +519,16 @@ pub fn spawn_server( state, updates, entrypoint_tx, + AdmissionHandshake { + discovery: discovery_tx, + admitted: admitted_rx, + }, )); info!(path = %path.display(), "Sidecar control socket listening"); Ok(ServerHandle { publisher, + discovered_policy: Some(discovery_rx), entrypoint_rx, connection_task, }) @@ -400,6 +542,7 @@ async fn accept_authoritative_connection( state: Arc>, updates: broadcast::Sender, entrypoint_tx: mpsc::Sender, + admission: AdmissionHandshake, ) { let stream = match listener.accept().await { Ok((stream, _addr)) => stream, @@ -424,7 +567,16 @@ async fn accept_authoritative_connection( ); } - if let Err(err) = handle_connection(stream, expected_peer, state, updates, entrypoint_tx).await + if let Err(err) = handle_connection( + stream, + expected_peer, + state, + updates, + entrypoint_tx, + admission.discovery, + admission.admitted, + ) + .await { warn!(error = %err, "Authoritative sidecar control connection closed"); } @@ -437,6 +589,8 @@ async fn handle_connection( state: Arc>, updates: broadcast::Sender, entrypoint_tx: mpsc::Sender, + discovery_tx: oneshot::Sender, + mut admitted_rx: watch::Receiver, ) -> Result<()> { let credentials = stream .peer_cred() @@ -464,12 +618,27 @@ async fn handle_connection( miette::miette!("sidecar control client disconnected before bootstrap") })?; match decode_client_message(&first_line)? { - WireClientMessage::BootstrapRequest { supervisor_pid } => { + WireClientMessage::BootstrapRequest { + supervisor_pid, + image_policy, + image_policy_invalid, + } => { if supervisor_pid == 0 || supervisor_pid != peer_pid { return Err(miette::miette!( "sidecar bootstrap PID mismatch: peer PID {peer_pid}, claimed PID {supervisor_pid}" )); } + let discovery = if image_policy_invalid { + ImagePolicyDiscovery::Invalid + } else { + image_policy.map_or(ImagePolicyDiscovery::Missing, |bytes| { + openshell_core::proto::SandboxPolicy::decode(bytes.as_slice()) + .map_or(ImagePolicyDiscovery::Invalid, |policy| { + ImagePolicyDiscovery::Policy(Box::new(policy)) + }) + }) + }; + let _ = discovery_tx.send(discovery); entrypoint_tx .send(EntrypointStarted { pid: supervisor_pid, @@ -490,6 +659,13 @@ async fn handle_connection( } } + // No bootstrap policy or workload credentials are exposed while admission + // is pending. The gateway remains available to repair the desired policy. + admitted_rx + .wait_for(|admitted| *admitted) + .await + .map_err(|_| miette::miette!("sidecar configuration admission ended before activation"))?; + // Subscribe before taking the bootstrap snapshot so an update can neither // be missed between the snapshot and the live update stream nor omitted // from the snapshot itself. @@ -568,9 +744,18 @@ async fn handle_connection( } } +#[cfg(test)] pub async fn connect_process_client( path: &Path, timeout: Duration, +) -> Result<(BootstrapData, ProcessConnection)> { + connect_process_client_with_policy(path, timeout, ImagePolicyDiscovery::Missing).await +} + +pub async fn connect_process_client_with_policy( + path: &Path, + timeout: Duration, + discovery: ImagePolicyDiscovery, ) -> Result<(BootstrapData, ProcessConnection)> { let stream = connect_with_retry(path, timeout).await?; let (reader, mut writer) = stream.into_split(); @@ -578,6 +763,11 @@ pub async fn connect_process_client( &mut writer, &WireClientMessage::BootstrapRequest { supervisor_pid: std::process::id(), + image_policy: match &discovery { + ImagePolicyDiscovery::Policy(policy) => Some(policy.encode_to_vec()), + ImagePolicyDiscovery::Missing | ImagePolicyDiscovery::Invalid => None, + }, + image_policy_invalid: matches!(discovery, ImagePolicyDiscovery::Invalid), }, ) .await?; @@ -591,7 +781,7 @@ pub async fn connect_process_client( let bootstrap = BootstrapData::try_from(decode_server_message(&first_line)?)?; let (update_tx, updates) = mpsc::unbounded_channel(); - let (closed_tx, closed) = tokio::sync::oneshot::channel(); + let (closed_tx, closed) = oneshot::channel(); tokio::spawn(async move { while let Ok(Some(line)) = lines.next_line().await { match decode_server_message(&line).and_then(ControlUpdate::try_from) { @@ -753,6 +943,8 @@ mod tests { fn bootstrap_message(policy: &SandboxPolicy) -> WireServerMessage { WireServerMessage::BootstrapResponse { policy_proto: policy.encode_to_vec(), + policy_hash: "accepted-hash".to_string(), + config_revision: 1, provider_env_revision: 0, provider_env_generation: 0, provider_child_env: HashMap::new(), @@ -777,6 +969,112 @@ mod tests { } } + #[tokio::test] + async fn workload_image_discovery_precedes_bootstrap_and_repair_releases_client() { + let dir = tempfile::tempdir().unwrap(); + let socket = dir.path().join("control.sock"); + let mut server = spawn_pending_server(&socket, current_peer()).unwrap(); + let discovery_rx = server.take_discovered_policy_receiver().unwrap(); + let client = tokio::spawn(async move { + connect_process_client_with_policy( + &socket, + Duration::from_secs(1), + ImagePolicyDiscovery::Invalid, + ) + .await + }); + assert!(matches!( + discovery_rx.await.unwrap(), + ImagePolicyDiscovery::Invalid + )); + // Receipt of the authenticated discovery request is the synchronization + // point: no timing assumptions are needed to show admission is pending. + assert!(!client.is_finished()); + assert!(!*server.publisher.admitted.borrow()); + + let policy = openshell_policy::restrictive_default_policy(); + server.publisher().publish_bootstrap(BootstrapData { + policy_proto: policy.clone(), + policy_hash: "repaired".to_string(), + config_revision: 2, + provider_env_revision: 5, + provider_env_generation: 0, + provider_child_env: HashMap::new(), + agent_proposals_enabled: false, + proxy_ca_cert_path: None, + proxy_ca_bundle_path: None, + }); + let (bootstrap, mut connection) = tokio::time::timeout(Duration::from_secs(1), client) + .await + .unwrap() + .unwrap() + .unwrap(); + assert_eq!(bootstrap.policy_hash, "repaired"); + assert_eq!(bootstrap.config_revision, 2); + assert_eq!(bootstrap.provider_env_revision, 5); + + let environment = HashMap::from([("TOKEN".to_string(), "placeholder".to_string())]); + server.publisher().publish_configuration( + policy, + "updated".to_string(), + 3, + 6, + environment.clone(), + ); + let update = tokio::time::timeout(Duration::from_secs(1), connection.updates.recv()) + .await + .unwrap() + .unwrap(); + let ControlUpdate::Configuration { + policy_hash, + config_revision, + provider_env_revision, + provider_env_generation, + provider_child_env, + .. + } = update + else { + panic!("configuration must arrive in one message"); + }; + assert_eq!( + ( + policy_hash.as_str(), + config_revision, + provider_env_revision, + provider_env_generation + ), + ("updated", 3, 6, 1) + ); + assert_eq!(provider_child_env, environment); + let state = server.publisher.state.read().unwrap(); + assert_eq!(state.policy_hash, "updated"); + assert_eq!(state.provider_env_revision, 6); + } + + #[test] + fn configuration_update_rejects_invalid_policy_before_exposing_environment() { + let invalid = defaultable_mcp_policy(Some(McpOptions { + versions: vec!["secret-invalid-value".to_string()], + ..Default::default() + })); + let error = ControlUpdate::try_from(WireServerMessage::ConfigurationUpdated { + policy_proto: invalid.encode_to_vec(), + policy_hash: "invalid".to_string(), + config_revision: 1, + provider_env_revision: 1, + provider_env_generation: 1, + provider_child_env: HashMap::from([( + "TOKEN".to_string(), + "credential-value".to_string(), + )]), + }) + .unwrap_err() + .to_string(); + assert_eq!(error, "sidecar configuration policy failed validation"); + assert!(!error.contains("secret-invalid-value")); + assert!(!error.contains("credential-value")); + } + #[test] fn policy_messages_canonicalize_defaultable_mcp_versions() { for raw in [ @@ -830,6 +1128,8 @@ mod tests { version: 7, ..SandboxPolicy::default() }, + policy_hash: "accepted-hash".to_string(), + config_revision: 1, provider_env_revision: 3, provider_env_generation: 0, provider_child_env: env.clone(), @@ -866,6 +1166,8 @@ mod tests { &socket, BootstrapData { policy_proto: SandboxPolicy::default(), + policy_hash: "accepted-hash".to_string(), + config_revision: 1, provider_env_revision: u64::MAX, provider_env_generation: 7, provider_child_env: HashMap::from([("TOKEN".to_string(), "first".to_string())]), @@ -950,6 +1252,8 @@ mod tests { &socket, BootstrapData { policy_proto: SandboxPolicy::default(), + policy_hash: "accepted-hash".to_string(), + config_revision: 1, provider_env_revision: 0, provider_env_generation: 0, provider_child_env: HashMap::new(), @@ -991,6 +1295,8 @@ mod tests { &socket, BootstrapData { policy_proto: SandboxPolicy::default(), + policy_hash: "accepted-hash".to_string(), + config_revision: 1, provider_env_revision: 0, provider_env_generation: 0, provider_child_env: HashMap::new(), @@ -1072,6 +1378,8 @@ mod tests { &socket, BootstrapData { policy_proto: SandboxPolicy::default(), + policy_hash: "accepted-hash".to_string(), + config_revision: 1, provider_env_revision: 0, provider_env_generation: 0, provider_child_env: HashMap::new(), @@ -1107,6 +1415,8 @@ mod tests { &socket, BootstrapData { policy_proto: SandboxPolicy::default(), + policy_hash: "accepted-hash".to_string(), + config_revision: 1, provider_env_revision: 0, provider_env_generation: 0, provider_child_env: HashMap::new(), @@ -1137,6 +1447,8 @@ mod tests { &socket, BootstrapData { policy_proto: SandboxPolicy::default(), + policy_hash: "accepted-hash".to_string(), + config_revision: 1, provider_env_revision: 0, provider_env_generation: 0, provider_child_env: HashMap::new(), @@ -1168,6 +1480,8 @@ mod tests { &socket, BootstrapData { policy_proto: SandboxPolicy::default(), + policy_hash: "accepted-hash".to_string(), + config_revision: 1, provider_env_revision: 0, provider_env_generation: 0, provider_child_env: HashMap::new(), @@ -1185,6 +1499,8 @@ mod tests { &mut stream, &WireClientMessage::BootstrapRequest { supervisor_pid: std::process::id().saturating_add(1), + image_policy: None, + image_policy_invalid: false, }, ) .await diff --git a/crates/openshell-sdk/tests/client_mock.rs b/crates/openshell-sdk/tests/client_mock.rs index 89cc68bf0f..8325a181b3 100644 --- a/crates/openshell-sdk/tests/client_mock.rs +++ b/crates/openshell-sdk/tests/client_mock.rs @@ -638,6 +638,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("unused")) } + async fn report_sandbox_configuration( + &self, + _: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented in test")) + } + async fn report_policy_status( &self, _: tonic::Request, diff --git a/crates/openshell-server/src/auth/method_authz.rs b/crates/openshell-server/src/auth/method_authz.rs index 35ff82e925..92d3b0a56a 100644 --- a/crates/openshell-server/src/auth/method_authz.rs +++ b/crates/openshell-server/src/auth/method_authz.rs @@ -128,6 +128,9 @@ mod tests { assert!(!is_user_callable( "/openshell.v1.OpenShell/ReportPolicyStatus" )); + assert!(!is_user_callable( + "/openshell.v1.OpenShell/ReportSandboxConfiguration" + )); assert!(!is_user_callable("/openshell.v1.OpenShell/PushSandboxLogs")); assert!(!is_user_callable( "/openshell.v1.OpenShell/GetSandboxProviderEnvironment" diff --git a/crates/openshell-server/src/compute/mod.rs b/crates/openshell-server/src/compute/mod.rs index 70356e1add..b2c6eeefab 100644 --- a/crates/openshell-server/src/compute/mod.rs +++ b/crates/openshell-server/src/compute/mod.rs @@ -1484,6 +1484,17 @@ impl ComputeRuntime { // Retain the previous instance id as a tombstone until // the restarted supervisor registers its new id. status.exit_code = None; + if phase == SandboxPhase::Starting { + status.configuration_admission = + Some(openshell_core::proto::SandboxConfigurationAdmission { + // Fence delayed registrations from the previous runtime. + instance_id: uuid::Uuid::new_v4().to_string(), + state: + openshell_core::proto::ConfigurationAdmissionState::Pending + .into(), + ..Default::default() + }); + } } upsert_ready_condition( &mut sandbox.status, @@ -3101,6 +3112,7 @@ impl ComputeRuntime { ensure_supervisor_not_ready_status(&mut sandbox.status, &sandbox_name); sandbox.set_phase(SandboxPhase::Provisioning as i32); } + apply_configuration_readiness(sandbox); }) .await; @@ -4268,6 +4280,7 @@ fn public_status_from_driver( current_policy_version, main_process_instance_id: String::new(), exit_code: None, + configuration_admission: None, } } @@ -4345,6 +4358,21 @@ fn apply_driver_snapshot( SandboxPhase::Stopping if phase != SandboxPhase::Error => SandboxPhase::Stopping, SandboxPhase::Stopped => SandboxPhase::Stopped, SandboxPhase::Completed => SandboxPhase::Completed, + SandboxPhase::Starting + if phase != SandboxPhase::Error + && sandbox + .status + .as_ref() + .and_then(|status| status.configuration_admission.as_ref()) + .is_some_and(|admission| { + admission.state + != i32::from( + openshell_core::proto::ConfigurationAdmissionState::Accepted, + ) + }) => + { + SandboxPhase::Starting + } SandboxPhase::Starting if !matches!(phase, SandboxPhase::Ready | SandboxPhase::Error) => { SandboxPhase::Starting } @@ -4365,6 +4393,9 @@ fn apply_driver_snapshot( .main_process_instance_id .clone_from(¤t_status.main_process_instance_id); status.exit_code = current_status.exit_code; + status + .configuration_admission + .clone_from(¤t_status.configuration_admission); } if old_phase != phase { info!( @@ -4401,6 +4432,71 @@ fn apply_driver_snapshot( sandbox.status = status; sandbox.set_phase(phase as i32); sandbox.set_current_policy_version(cpv); + apply_configuration_readiness(sandbox); +} + +/// Configuration readiness is independent of compute/container readiness. +pub fn apply_configuration_readiness(sandbox: &mut Sandbox) { + use openshell_core::proto::ConfigurationAdmissionState; + let Some(status) = sandbox.status.as_mut() else { + return; + }; + let Some(admission) = status.configuration_admission.as_ref() else { + return; + }; + let accepted = admission.state == i32::from(ConfigurationAdmissionState::Accepted); + let reason = if accepted { + "ConfigurationAccepted" + } else if admission.state == i32::from(ConfigurationAdmissionState::Rejected) { + "ConfigurationInvalid" + } else { + "ConfigurationPending" + }; + let desired_error = admission.error.clone(); + let message = if accepted { + String::new() + } else if admission.error.is_empty() { + "Waiting for effective configuration validation before workload activation".to_string() + } else { + admission.error.clone() + }; + status.conditions.retain(|condition| { + condition.r#type != "ConfigurationReady" && condition.r#type != "DesiredConfigurationReady" + }); + status.conditions.push(SandboxCondition { + r#type: "ConfigurationReady".to_string(), + status: if accepted { "True" } else { "False" }.to_string(), + reason: reason.to_string(), + message: message.clone(), + ..Default::default() + }); + if accepted && !desired_error.is_empty() { + status.conditions.push(SandboxCondition { + r#type: "DesiredConfigurationReady".to_string(), + status: "False".to_string(), + reason: "ConfigurationInvalid".to_string(), + message: desired_error, + ..Default::default() + }); + } + if !accepted + && matches!( + SandboxPhase::try_from(status.phase), + Ok(SandboxPhase::Ready | SandboxPhase::Provisioning) + ) + { + status.phase = SandboxPhase::Provisioning as i32; + status + .conditions + .retain(|condition| condition.r#type != "Ready"); + status.conditions.push(SandboxCondition { + r#type: "Ready".to_string(), + status: "False".to_string(), + reason: reason.to_string(), + message, + ..Default::default() + }); + } } fn driver_snapshot_confirms_stopped(incoming: &DriverSandbox) -> bool { @@ -4965,6 +5061,82 @@ mod tests { use tokio::sync::{Notify, Semaphore, mpsc, oneshot}; use tokio_stream::wrappers::UnboundedReceiverStream; + #[test] + fn configuration_admission_survives_driver_ready_observations() { + use openshell_core::proto::{ + ConfigurationAdmissionState as Admission, SandboxConfigurationAdmission, + }; + let mut sandbox = Sandbox::default(); + sandbox.set_phase(SandboxPhase::Provisioning as i32); + sandbox.status.as_mut().unwrap().configuration_admission = + Some(SandboxConfigurationAdmission { + instance_id: "instance".to_string(), + state: Admission::Rejected.into(), + error: "Invalid credentialed endpoint in rule image".to_string(), + ..Default::default() + }); + let incoming = ready_driver_sandbox("sandbox", "sandbox"); + apply_driver_snapshot(&mut sandbox, &incoming, true, true); + assert_eq!(sandbox.phase(), SandboxPhase::Provisioning as i32); + assert!( + sandbox + .status + .as_ref() + .unwrap() + .conditions + .iter() + .any(|condition| condition.reason == "ConfigurationInvalid" + && condition.status == "False") + ); + sandbox + .status + .as_mut() + .unwrap() + .configuration_admission + .as_mut() + .unwrap() + .state = Admission::Accepted.into(); + apply_driver_snapshot(&mut sandbox, &incoming, true, true); + assert_eq!(sandbox.phase(), SandboxPhase::Ready as i32); + assert!( + sandbox + .status + .as_ref() + .unwrap() + .conditions + .iter() + .any(|condition| condition.reason == "ConfigurationAccepted" + && condition.status == "True") + ); + } + + #[test] + fn configuration_admission_preserves_starting_for_early_exit_reports() { + use openshell_core::proto::{ + ConfigurationAdmissionState as Admission, SandboxConfigurationAdmission, + }; + let mut sandbox = Sandbox::default(); + sandbox.set_phase(SandboxPhase::Starting as i32); + let status = sandbox.status.as_mut().unwrap(); + status.main_process_instance_id = "previous-instance".to_string(); + status.configuration_admission = Some(SandboxConfigurationAdmission { + state: Admission::Pending.into(), + ..Default::default() + }); + apply_configuration_readiness(&mut sandbox); + apply_driver_snapshot( + &mut sandbox, + &ready_driver_sandbox("sandbox", "sandbox"), + false, + true, + ); + assert_eq!(sandbox.phase(), SandboxPhase::Starting as i32); + assert_eq!( + sandbox.status.as_ref().unwrap().main_process_instance_id, + "previous-instance" + ); + } + fn string_value(value: &str) -> prost_types::Value { prost_types::Value { kind: Some(prost_types::value::Kind::StringValue(value.to_string())), @@ -7092,6 +7264,39 @@ mod tests { ); register_test_supervisor_session(&runtime, sandbox.object_id()); + runtime + .apply_sandbox_update(ready_driver_sandbox( + sandbox.object_id(), + sandbox.object_name(), + )) + .await + .unwrap(); + let blocked = runtime + .store + .get_message::(sandbox.object_id()) + .await + .unwrap() + .unwrap(); + assert_eq!( + blocked.phase(), + SandboxPhase::Starting as i32, + "driver/session readiness cannot bypass restart configuration admission" + ); + // Simulate the supervisor's successful exact-generation admission report. + runtime + .store + .update_message_cas::(sandbox.object_id(), 0, |sandbox| { + sandbox + .status + .as_mut() + .unwrap() + .configuration_admission + .as_mut() + .unwrap() + .state = openshell_core::proto::ConfigurationAdmissionState::Accepted.into(); + }) + .await + .unwrap(); runtime .apply_sandbox_update(ready_driver_sandbox( sandbox.object_id(), diff --git a/crates/openshell-server/src/grpc/mod.rs b/crates/openshell-server/src/grpc/mod.rs index c5a12a15b5..e438689490 100644 --- a/crates/openshell-server/src/grpc/mod.rs +++ b/crates/openshell-server/src/grpc/mod.rs @@ -610,6 +610,13 @@ impl OpenShell for OpenShellService { policy::handle_report_policy_status(&self.state, request).await } + async fn report_sandbox_configuration( + &self, + request: Request, + ) -> Result, Status> { + policy::handle_report_sandbox_configuration(&self.state, request).await + } + // --- Sandbox logs --- async fn get_sandbox_logs( diff --git a/crates/openshell-server/src/grpc/policy.rs b/crates/openshell-server/src/grpc/policy.rs index 4940cd1aa3..be22a33710 100644 --- a/crates/openshell-server/src/grpc/policy.rs +++ b/crates/openshell-server/src/grpc/policy.rs @@ -15,8 +15,10 @@ use crate::auth::principal::Principal; use crate::auth::workspace_authz::{ MinWorkspaceRole, authorize_sandbox_workspace, authorize_workspace, require_platform_admin, }; +#[cfg(test)] +use crate::persistence::ObjectType; use crate::persistence::{ - DraftChunkRecord, ObjectId, ObjectName, ObjectType, ObjectWorkspace, PolicyRecord, Store, + DraftChunkRecord, ObjectId, ObjectName, ObjectWorkspace, PolicyRecord, Store, }; use crate::policy_store::{AtomicPolicyRevisionWrite, PolicyStoreExt}; use crate::provider_profile_sources::EffectiveProviderProfileCatalog; @@ -1603,20 +1605,32 @@ async fn current_effective_policy_for_sandbox( .as_ref() .map(|spec| spec.providers.clone()) .unwrap_or_default(); + let records = super::provider::load_provider_environment_records( + state.store.as_ref(), + workspace, + &provider_names, + ) + .await?; + current_effective_policy_from_records(state, catalog, sandbox, sandbox_id, &records).await +} + +async fn current_effective_policy_from_records( + state: &ServerState, + catalog: &EffectiveProviderProfileCatalog, + sandbox: &Sandbox, + sandbox_id: &str, + records: &[super::provider::ProviderEnvironmentRecord], +) -> Result { let global_settings = load_global_settings(state.store.as_ref()).await?; if let Some(global_policy) = decode_policy_from_global_settings(&global_settings)? { // A global policy is the complete effective policy. Dormant sandbox // history and specs may predate the current schema, but they must not // prevent the valid global policy from being served. - return apply_effective_policy_context( - state, - catalog, - workspace, - &provider_names, + return apply_captured_policy_context( + provider_policy_context_from_records(catalog, records), global_policy, PolicySource::Global, - ) - .await; + ); } let policy = if let Some(record) = state @@ -1635,15 +1649,11 @@ async fn current_effective_policy_for_sandbox( } }; - apply_effective_policy_context( - state, - catalog, - workspace, - &provider_names, + apply_captured_policy_context( + provider_policy_context_from_records(catalog, records), policy, PolicySource::Sandbox, ) - .await } async fn effective_policy_for_source( @@ -1678,17 +1688,25 @@ async fn apply_effective_policy_context( catalog: &EffectiveProviderProfileCatalog, workspace: &str, provider_names: &[String], - mut policy: ProtoSandboxPolicy, + policy: ProtoSandboxPolicy, policy_source: PolicySource, ) -> Result { - clear_provider_credentialed_markers(&mut policy); - let mut provider_context = provider_policy_context_with_catalog( + let provider_context = provider_policy_context_with_catalog( state.store.as_ref(), catalog, workspace, provider_names, ) .await?; + apply_captured_policy_context(provider_context, policy, policy_source) +} + +fn apply_captured_policy_context( + mut provider_context: ProviderPolicyContext, + mut policy: ProtoSandboxPolicy, + policy_source: PolicySource, +) -> Result { + clear_provider_credentialed_markers(&mut policy); if !matches!(policy_source, PolicySource::Global) && !provider_context.layers.is_empty() { policy = compose_effective_policy(&policy, &provider_context.layers); } @@ -2303,9 +2321,17 @@ async fn persist_existing_policy_projection( let updated = state .store .update_message_cas::(sandbox_id, expected_resource_version, |sandbox| { + let startup_blocked = sandbox + .status + .as_ref() + .and_then(|status| status.configuration_admission.as_ref()) + .is_some_and(|admission| { + admission.state + != i32::from(openshell_core::proto::ConfigurationAdmissionState::Accepted) + }); if let Some(policy) = backfill_policy.as_ref() && let Some(spec) = sandbox.spec.as_mut() - && spec.policy.is_none() + && (spec.policy.is_none() || startup_blocked) { spec.policy = Some(policy.clone()); } @@ -2362,6 +2388,42 @@ async fn resolve_sandbox_by_name_for_principal( pub(super) async fn handle_get_sandbox_config( state: &Arc, request: Request, +) -> Result, Status> { + let principal = super::extract_principal(&request)?; + let sandbox_id = request.get_ref().sandbox_id.clone(); + let result = handle_get_sandbox_config_inner(state, request).await; + match result { + Err(error) + if matches!(principal, Principal::Sandbox(_)) + && matches!( + error.code(), + tonic::Code::FailedPrecondition | tonic::Code::InvalidArgument + ) => + { + // A malformed stored candidate must not prevent a supervisor + // from registering its startup fence and waiting for repair. + // Do not expose parser payloads or copy malformed policy history. + let sandbox = + super::sandbox::fetch_and_authorize_sandbox(state, &principal, &sandbox_id).await?; + Ok(Response::new(GetSandboxConfigResponse { + configuration_admitted: false, + configuration_error: configuration_failure_diagnostic(&error).to_string(), + configuration_instance_id: sandbox + .status + .as_ref() + .and_then(|status| status.configuration_admission.as_ref()) + .map_or_else(String::new, |admission| admission.instance_id.clone()), + workspace: sandbox.object_workspace().to_string(), + ..Default::default() + })) + } + result => result, + } +} + +async fn handle_get_sandbox_config_inner( + state: &Arc, + request: Request, ) -> Result, Status> { let principal = super::extract_principal(&request)?; let sandbox_id = request.get_ref().sandbox_id.clone(); @@ -2479,13 +2541,14 @@ pub(super) async fn handle_get_sandbox_config( let global_settings = load_global_settings(state.store.as_ref()).await?; let sandbox_settings = load_sandbox_settings(state.store.as_ref(), &workspace, sandbox.object_name()).await?; - let mut provider_policy_context = provider_policy_context_with_catalog( + let provider_records = super::provider::load_provider_environment_records( state.store.as_ref(), - &provider_profile_catalog, &workspace, &sandbox_provider_names, ) .await?; + let mut provider_policy_context = + provider_policy_context_from_records(&provider_profile_catalog, &provider_records); if matches!(policy_source, PolicySource::Global) && let Ok(Some(global_rev)) = state @@ -2531,12 +2594,15 @@ pub(super) async fn handle_get_sandbox_config( &policy_credential_bindings, &provider_policy_context.endpointless_provider_names, ); + let mut configuration_error = String::new(); if let Some(effective_policy) = policy.as_mut() { stamp_provider_credentialed_endpoints( effective_policy, &provider_policy_context.credentialed_scopes, ); - report_uninspected_credentialed_endpoints(effective_policy, &sandbox_id); + if let Err(error) = validate_uninspected_credentialed_endpoints(effective_policy) { + configuration_error = bounded_configuration_diagnostic(error.message()); + } policy_hash = deterministic_policy_hash(effective_policy); } @@ -2563,25 +2629,27 @@ pub(super) async fn handle_get_sandbox_config( state.sandbox_jwt_issuer.is_some(), ); if let Some(policy) = policy.as_ref() { - validate_policy_credential_bindings_for_sandbox( - state.as_ref(), + validate_policy_credential_binding_context( &provider_profile_catalog, - &workspace, - &sandbox_provider_names, + &provider_records, policy, - ) - .await?; + &policy_credential_bindings, + )?; } - let provider_env_revision = compute_provider_env_revision_with_catalog_and_policy_bindings( - state.store.as_ref(), + let provider_env_revision = compute_provider_env_revision_from_records_and_policy_bindings( &provider_profile_catalog, - &workspace, - &sandbox_provider_names, + &provider_records, &policy_credential_bindings, - ) - .await?; + )?; Ok(Response::new(GetSandboxConfigResponse { + configuration_instance_id: sandbox + .status + .as_ref() + .and_then(|status| status.configuration_admission.as_ref()) + .map_or_else(String::new, |admission| admission.instance_id.clone()), + configuration_admitted: policy.is_some() && configuration_error.is_empty(), + configuration_error, policy, version, policy_hash, @@ -2630,6 +2698,7 @@ pub(super) async fn compute_provider_env_revision_with_catalog( .await } +#[cfg(test)] async fn compute_provider_env_revision_with_catalog_and_policy_bindings( store: &Store, catalog: &EffectiveProviderProfileCatalog, @@ -2857,16 +2926,23 @@ async fn provider_policy_context_with_catalog( workspace: &str, provider_names: &[String], ) -> Result { + let records = + super::provider::load_provider_environment_records(store, workspace, provider_names) + .await?; + Ok(provider_policy_context_from_records(catalog, &records)) +} + +fn provider_policy_context_from_records( + catalog: &EffectiveProviderProfileCatalog, + records: &[super::provider::ProviderEnvironmentRecord], +) -> ProviderPolicyContext { let mut layers = Vec::new(); let mut credentialed_scopes = Vec::new(); let mut endpointless_provider_names = HashSet::new(); - for name in provider_names { - let provider = store - .get_message_by_name::(workspace, name) - .await - .map_err(|e| Status::internal(format!("failed to fetch provider '{name}': {e}")))? - .ok_or_else(|| Status::failed_precondition(format!("provider '{name}' not found")))?; + for record in records { + let name = &record.name; + let provider = &record.provider; let provider_type = provider.r#type.trim(); let Some(profile) = super::provider::get_provider_type_profile_for_scope( @@ -2882,7 +2958,7 @@ async fn provider_policy_context_with_catalog( continue; }; - if !super::provider::provider_profile_endpoints_are_active(&profile, &provider) { + if !super::provider::provider_profile_endpoints_are_active(&profile, provider) { endpointless_provider_names.insert(name.clone()); continue; } @@ -2910,11 +2986,11 @@ async fn provider_policy_context_with_catalog( }); } - Ok(ProviderPolicyContext { + ProviderPolicyContext { layers, credentialed_scopes, endpointless_provider_names, - }) + } } fn endpoint_ports(endpoint: &NetworkEndpoint) -> Vec { @@ -3058,22 +3134,6 @@ fn validate_uninspected_credentialed_endpoints(policy: &ProtoSandboxPolicy) -> R ))) } -/// Delivery-path reporting for an already-persisted policy. Sandbox config -/// delivery must not fail closed here: refusing the config would crash-loop a -/// running supervisor. The runtime backstop denies the traffic instead. -fn report_uninspected_credentialed_endpoints(policy: &ProtoSandboxPolicy, sandbox_id: &str) { - if let Some(violation) = find_uninspected_credentialed_endpoint(policy) { - warn!( - sandbox_id, - rule_name = %violation.rule_name, - host = %violation.host, - port = violation.port, - mode = violation.mode, - "delivering credentialed endpoint without L7 inspection; the sandbox proxy will deny this traffic unless allow_uninspected_credentials is set" - ); - } -} - pub(super) async fn handle_get_gateway_config( state: &Arc, _request: Request, @@ -3119,12 +3179,12 @@ pub(super) async fn handle_get_sandbox_provider_environment( &provider_names, ) .await?; - let effective_policy = current_effective_policy_for_sandbox( + let effective_policy = current_effective_policy_from_records( state.as_ref(), &provider_profile_catalog, - &workspace, &sandbox, &sandbox_id, + &provider_records, ) .await?; let policy_credential_bindings = @@ -3707,7 +3767,19 @@ async fn handle_update_config_inner( validate_no_reserved_provider_policy_keys(&new_policy)?; } - let should_backfill_policy = if let Some(baseline_policy) = spec.policy.as_ref() { + let startup_blocked = sandbox + .status + .as_ref() + .and_then(|status| status.configuration_admission.as_ref()) + .is_some_and(|admission| { + admission.state + != i32::from(openshell_core::proto::ConfigurationAdmissionState::Accepted) + }); + let should_backfill_policy = if startup_blocked && !sandbox_caller { + // No child has consumed static restrictions yet. A complete replacement + // must be able to repair every field before the first activation. + true + } else if let Some(baseline_policy) = spec.policy.as_ref() { let comparable_baseline = baseline_policy.clone(); validate_static_fields_unchanged(&comparable_baseline, &new_policy)?; false @@ -3739,9 +3811,9 @@ async fn handle_update_config_inner( &effective_policy, ) .await?; - // Sandbox-authored syncs replay a policy the supervisor already discovered - // on disk. Rejecting it here would crash-loop the sandbox instead of - // surfacing an operator decision, so only operator-authored updates gate. + // Image discovery persists the desired candidate for management repair. + // It never admits workload activation: GetSandboxConfig applies the complete + // composition gate and ReportSandboxConfiguration checks the exact result. if !sandbox_caller { validate_candidate_sandbox_credential_policy( state, @@ -4036,6 +4108,153 @@ pub(super) async fn handle_list_sandbox_policies( Ok(Response::new(ListSandboxPoliciesResponse { revisions })) } +fn bounded_configuration_diagnostic(message: &str) -> String { + message + .chars() + .filter(|character| !character.is_control()) + .take(512) + .collect() +} + +fn configuration_failure_diagnostic(error: &Status) -> &'static str { + let message = error.message(); + if message.contains("middleware") { + "Effective middleware configuration is invalid; repair the policy middleware bindings or registered services" + } else if message.contains("credential") || message.contains("provider") { + "Effective provider configuration is invalid; repair credential bindings, attached providers, or their policy layers" + } else { + "Stored policy structure or safety validation failed; submit a complete valid replacement policy" + } +} + +fn configuration_generation_matches( + admission: &openshell_core::proto::SandboxConfigurationAdmission, + config: &GetSandboxConfigResponse, +) -> bool { + ( + admission.policy_version, + &admission.policy_hash, + admission.config_revision, + admission.provider_env_revision, + ) == ( + config.version, + &config.policy_hash, + config.config_revision, + config.provider_env_revision, + ) +} + +pub(super) async fn handle_report_sandbox_configuration( + state: &Arc, + request: Request, +) -> Result, Status> { + use openshell_core::proto::ConfigurationAdmissionState; + let principal = super::extract_principal(&request)?; + let sandbox_id = request.get_ref().sandbox_id.clone(); + crate::auth::guard::enforce_sandbox_scope(&request, &sandbox_id)?; + let mut admission = request + .get_ref() + .admission + .clone() + .ok_or_else(|| Status::invalid_argument("admission is required"))?; + if uuid::Uuid::parse_str(&admission.instance_id).is_err() { + return Err(Status::invalid_argument("instance_id must be a UUID")); + } + let reported = ConfigurationAdmissionState::try_from(admission.state) + .map_err(|_| Status::invalid_argument("invalid admission state"))?; + if reported == ConfigurationAdmissionState::Unspecified { + return Err(Status::invalid_argument("admission state is required")); + } + let sandbox = + super::sandbox::fetch_and_authorize_sandbox(state, &principal, &sandbox_id).await?; + let current = sandbox + .status + .as_ref() + .and_then(|status| status.configuration_admission.as_ref()); + if reported == ConfigurationAdmissionState::Pending + && current.is_some_and(|current| current.instance_id != admission.instance_id) + && current.map_or("", |current| current.instance_id.as_str()) + != request.get_ref().expected_instance_id + { + return Err(Status::aborted("supervisor registration fence has changed")); + } + if reported != ConfigurationAdmissionState::Pending + && current.is_none_or(|current| current.instance_id != admission.instance_id) + { + return Err(Status::aborted( + "supervisor configuration instance has changed", + )); + } + if reported == ConfigurationAdmissionState::Accepted { + let mut config_request = Request::new(GetSandboxConfigRequest { + sandbox_id: sandbox_id.clone(), + }); + *config_request.extensions_mut() = request.extensions().clone(); + let config = handle_get_sandbox_config(state, config_request) + .await? + .into_inner(); + if !config.configuration_admitted || !configuration_generation_matches(&admission, &config) + { + return Err(Status::aborted( + "configuration changed or is not admitted; fetch and validate again", + )); + } + admission.error.clear(); + } else if reported == ConfigurationAdmissionState::Rejected { + // Runtime error strings may contain parser payloads. Only gateway-authored + // diagnostics may be exposed verbatim through public sandbox status. + let mut config_request = Request::new(GetSandboxConfigRequest { + sandbox_id: sandbox_id.clone(), + }); + *config_request.extensions_mut() = request.extensions().clone(); + admission.error = match handle_get_sandbox_config(state, config_request).await { + Ok(config) if !configuration_generation_matches(&admission, config.get_ref()) => { + return Err(Status::aborted("rejected configuration generation has changed")); + } + Ok(config) if !config.get_ref().configuration_error.is_empty() => config.into_inner().configuration_error, + _ => "Effective configuration could not be activated; replace the policy or repair attached providers".to_string(), + }; + if let Some(current) = current + && current.state == i32::from(ConfigurationAdmissionState::Accepted) + { + // A rejected desired update does not invalidate an accepted runtime. + let error = admission.error; + admission = current.clone(); + admission.error = error; + } + } else { + admission.error.clear(); + if let Some(current) = current + && current.instance_id == admission.instance_id + { + admission = current.clone(); + } + } + let expected_version = sandbox + .metadata + .as_ref() + .map_or(0, |metadata| metadata.resource_version); + let _guard = state.compute.sandbox_sync_guard().await; + let updated = state + .store + .update_message_cas::(&sandbox_id, expected_version, |sandbox| { + sandbox + .status + .get_or_insert_with(Default::default) + .configuration_admission = Some(admission.clone()); + crate::compute::apply_configuration_readiness(sandbox); + }) + .await + .map_err(|error| { + super::persistence_error_to_status(error, "report configuration admission") + })?; + state.sandbox_index.update_from_sandbox(&updated); + state.sandbox_watch_bus.notify(&sandbox_id); + Ok(Response::new( + openshell_core::proto::ReportSandboxConfigurationResponse {}, + )) +} + pub(super) async fn handle_report_policy_status( state: &Arc, request: Request, @@ -7117,6 +7336,229 @@ mod tests { request } + #[tokio::test] + async fn configuration_admission_rejects_stale_generation_and_instance() { + use openshell_core::proto::{ + ConfigurationAdmissionState as Admission, ReportSandboxConfigurationRequest, + SandboxConfigurationAdmission, + }; + let state = test_server_state().await; + let sandbox_id = "sb-admission"; + state + .store + .put_message(&test_sandbox( + sandbox_id, + "admission", + openshell_policy::restrictive_default_policy(), + Vec::new(), + )) + .await + .unwrap(); + let instance_id = uuid::Uuid::new_v4().to_string(); + let report = |admission| { + with_sandbox( + Request::new(ReportSandboxConfigurationRequest { + sandbox_id: sandbox_id.to_string(), + admission: Some(admission), + expected_instance_id: String::new(), + }), + sandbox_id, + ) + }; + handle_report_sandbox_configuration( + &state, + report(SandboxConfigurationAdmission { + instance_id: instance_id.clone(), + state: Admission::Pending.into(), + ..Default::default() + }), + ) + .await + .unwrap(); + let config = handle_get_sandbox_config( + &state, + with_sandbox( + Request::new(GetSandboxConfigRequest { + sandbox_id: sandbox_id.to_string(), + }), + sandbox_id, + ), + ) + .await + .unwrap() + .into_inner(); + assert!(config.configuration_admitted); + let accepted = SandboxConfigurationAdmission { + instance_id: instance_id.clone(), + state: Admission::Accepted.into(), + policy_version: config.version, + policy_hash: config.policy_hash, + config_revision: config.config_revision, + provider_env_revision: config.provider_env_revision, + error: String::new(), + }; + let mut outdated_admission = accepted.clone(); + outdated_admission.provider_env_revision = + outdated_admission.provider_env_revision.wrapping_add(1); + assert_eq!( + handle_report_sandbox_configuration(&state, report(outdated_admission)) + .await + .unwrap_err() + .code(), + Code::Aborted + ); + handle_report_sandbox_configuration(&state, report(accepted.clone())) + .await + .unwrap(); + let mut stale_rejection = accepted.clone(); + stale_rejection.state = Admission::Rejected.into(); + stale_rejection.policy_version += 1; + assert_eq!( + handle_report_sandbox_configuration(&state, report(stale_rejection)) + .await + .unwrap_err() + .code(), + Code::Aborted, + "a delayed rejection must not mark the accepted current generation invalid" + ); + let mut restart = report(SandboxConfigurationAdmission { + instance_id: uuid::Uuid::new_v4().to_string(), + state: Admission::Pending.into(), + ..Default::default() + }); + restart.get_mut().expected_instance_id = instance_id.clone(); + handle_report_sandbox_configuration(&state, restart) + .await + .unwrap(); + assert_eq!( + handle_report_sandbox_configuration( + &state, + report(SandboxConfigurationAdmission { + instance_id, + state: Admission::Pending.into(), + ..Default::default() + }) + ) + .await + .unwrap_err() + .code(), + Code::Aborted, + "delayed old Pending must not reclaim registration" + ); + assert_eq!( + handle_report_sandbox_configuration(&state, report(accepted)) + .await + .unwrap_err() + .code(), + Code::Aborted + ); + } + + #[test] + fn configuration_diagnostic_is_bounded_and_removes_control_characters() { + let diagnostic = bounded_configuration_diagnostic(&format!("rule\n{}", "é".repeat(1000))); + assert_eq!(diagnostic.chars().count(), 512); + assert!(!diagnostic.contains('\n')); + } + + #[tokio::test] + async fn configuration_admission_retains_invalid_image_composition_for_repair() { + use openshell_core::proto::{ + ConfigurationAdmissionState as Admission, ReportSandboxConfigurationRequest, + SandboxConfigurationAdmission, + }; + let state = test_server_state().await; + let sandbox_id = "sb-image-admission"; + let mut sandbox = test_sandbox( + sandbox_id, + "image-admission", + ProtoSandboxPolicy::default(), + vec!["work-github".to_string()], + ); + sandbox.spec.as_mut().unwrap().policy = None; + state + .store + .put_message(&test_provider("work-github", "github")) + .await + .unwrap(); + state.store.put_message(&sandbox).await.unwrap(); + let instance_id = uuid::Uuid::new_v4().to_string(); + handle_report_sandbox_configuration( + &state, + with_sandbox( + Request::new(ReportSandboxConfigurationRequest { + sandbox_id: sandbox_id.to_string(), + expected_instance_id: String::new(), + admission: Some(SandboxConfigurationAdmission { + instance_id, + state: Admission::Pending.into(), + ..Default::default() + }), + }), + sandbox_id, + ), + ) + .await + .unwrap(); + let image = test_policy_with_rule("image_github", "api.github.com"); + handle_update_config( + &state, + with_sandbox( + Request::new(UpdateConfigRequest { + name: "image-admission".to_string(), + policy: Some(image), + ..Default::default() + }), + sandbox_id, + ), + ) + .await + .expect("image candidate remains available for repair"); + let rejected = handle_get_sandbox_config( + &state, + with_sandbox( + Request::new(GetSandboxConfigRequest { + sandbox_id: sandbox_id.to_string(), + }), + sandbox_id, + ), + ) + .await + .unwrap() + .into_inner(); + assert!(!rejected.configuration_admitted); + assert!(rejected.configuration_error.contains("image_github")); + assert!(!rejected.configuration_error.contains("ghp-test")); + assert!(rejected.policy.is_some()); + handle_update_config( + &state, + with_user(Request::new(UpdateConfigRequest { + name: "image-admission".to_string(), + policy: Some(openshell_policy::restrictive_default_policy()), + ..Default::default() + })), + ) + .await + .expect("operator can replace static sections before first launch"); + let repaired = handle_get_sandbox_config( + &state, + with_sandbox( + Request::new(GetSandboxConfigRequest { + sandbox_id: sandbox_id.to_string(), + }), + sandbox_id, + ), + ) + .await + .unwrap() + .into_inner(); + assert!( + repaired.configuration_admitted, + "{}", + repaired.configuration_error + ); + } + fn security_notes_for_host(host: &str) -> String { generate_security_notes(&NetworkPolicyRule { endpoints: vec![NetworkEndpoint { @@ -7253,7 +7695,7 @@ mod tests { .await .expect("store legacy sandbox spec"); - let error = handle_get_sandbox_config( + let error = handle_get_sandbox_config_inner( &state, with_sandbox( Request::new(GetSandboxConfigRequest { @@ -7500,7 +7942,7 @@ mod tests { .await .expect("store legacy invalid history"); - let error = handle_get_sandbox_config( + let rejected = handle_get_sandbox_config( &state, with_sandbox( Request::new(GetSandboxConfigRequest { @@ -7510,10 +7952,12 @@ mod tests { ), ) .await - .expect_err("invalid latest history must fail closed"); + .expect("invalid latest history must remain repairable") + .into_inner(); - assert_eq!(error.code(), Code::FailedPrecondition); - assert!(error.message().contains(STORED_POLICY_SOURCE_HISTORY)); + assert!(!rejected.configuration_admitted); + assert!(rejected.policy.is_none()); + assert!(!rejected.configuration_error.is_empty()); let record = state .store diff --git a/crates/openshell-server/src/grpc/sandbox.rs b/crates/openshell-server/src/grpc/sandbox.rs index e0ff130ebc..5c3aa18930 100644 --- a/crates/openshell-server/src/grpc/sandbox.rs +++ b/crates/openshell-server/src/grpc/sandbox.rs @@ -471,6 +471,14 @@ async fn handle_create_sandbox_inner( created_from_workload_template, }; sandbox.set_phase(SandboxPhase::Provisioning as i32); + sandbox + .status + .get_or_insert_with(Default::default) + .configuration_admission = Some(openshell_core::proto::SandboxConfigurationAdmission { + state: openshell_core::proto::ConfigurationAdmissionState::Pending.into(), + ..Default::default() + }); + crate::compute::apply_configuration_readiness(&mut sandbox); // Ensure metadata is valid (defense in depth - should always be true for server-constructed metadata) super::validation::validate_object_metadata(sandbox.metadata.as_ref(), "sandbox")?; diff --git a/crates/openshell-server/src/policy_store.rs b/crates/openshell-server/src/policy_store.rs index 8b1b6df335..b9a99e6b19 100644 --- a/crates/openshell-server/src/policy_store.rs +++ b/crates/openshell-server/src/policy_store.rs @@ -20,6 +20,8 @@ pub struct AtomicPolicyRevisionWrite { pub provenance: HashMap, pub expected_resource_version: u64, pub annotations: HashMap, + /// Populate the create-time baseline, or replace it while startup admission + /// is blocked and no workload has consumed the static restrictions. pub backfill_policy: Option, } @@ -59,6 +61,14 @@ pub fn project_policy_revision_onto_sandbox( sandbox.set_resource_version(current_resource_version); let mut changed = false; + let startup_blocked = sandbox + .status + .as_ref() + .and_then(|status| status.configuration_admission.as_ref()) + .is_some_and(|admission| { + admission.state + != i32::from(openshell_core::proto::ConfigurationAdmissionState::Accepted) + }); if let Some(backfill_policy) = write.backfill_policy.as_ref() { let spec = sandbox .spec @@ -70,6 +80,10 @@ pub fn project_policy_revision_onto_sandbox( changed = true; } Some(current) if current == backfill_policy => {} + Some(_) if startup_blocked => { + spec.policy = Some(backfill_policy.clone()); + changed = true; + } Some(_) => { return Err(PersistenceError::Conflict { current_resource_version: Some(current_resource_version), diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index 0d6d33c01f..8421481a98 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -119,11 +119,11 @@ mod tests { const STORAGE_V1_SCHEMA_SHA256: &str = "79c72615d957fc0653c672f61998bf7d8d21b757bc05d07b3fff92bd70fc8f52"; const PUBLIC_RPC_SCHEMA_SHA256: &str = - "042034fe4d0000279ee4ed27e587ab8e530934b8d5c3aa36dc9769f81dfa6e51"; + "25b9b3d6f2cebdcd3148b0049838dcce51ee745f52a4051428af6701e610afd0"; const DURABLE_SCHEMA_SHA256: &str = - "920a5243dfb37ce709f0f562a47d17791a5ede90fd7f662ed01542abd60a0dfb"; + "a6191e11d46430e5e32881f53b13f6c717717fbc6bff6e0a1d270fe8f9710d51"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = - "05add438ba041defc98d791038ae593d3f09352677cae43f2276d494205ce415"; + "68127e24cdb88b67433f68c4a1443c22a322f37ed1225b7547614a96f768cfac"; // 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. @@ -447,14 +447,14 @@ mod tests { } } methods.sort(); - assert_eq!(compiled_method_count, 100, "classify every compiled RPC"); - assert_eq!(methods.len(), 74, "inventory every public gateway RPC"); + assert_eq!(compiled_method_count, 101, "classify every compiled RPC"); + assert_eq!(methods.len(), 75, "inventory every public gateway RPC"); assert_eq!( methods .iter() .filter(|method| method.starts_with("openshell.v1.OpenShell/")) .count(), - 74 + 75 ); assert!(methods.iter().all(|method| !method.contains(".storage."))); @@ -487,13 +487,13 @@ mod tests { assert_eq!( (public_closure.messages.len(), public_closure.enums.len()), - (276, 12) + (279, 13) ); assert_eq!( (durable_closure.messages.len(), durable_closure.enums.len()), - (81, 8) + (82, 9) ); - assert_eq!((overlap_messages.len(), overlap_enums.len()), (71, 8)); + assert_eq!((overlap_messages.len(), overlap_enums.len()), (72, 9)); assert_eq!( public_inventory_hash, PUBLIC_RPC_SCHEMA_SHA256, @@ -513,6 +513,21 @@ mod tests { hex::decode(encoded).expect("checked-in legacy fixture must be valid hex") } + #[test] + fn pre_admission_sandbox_decodes_without_fabricating_acceptance() { + use openshell_core::proto::{Sandbox, SandboxPhase}; + + // Encoded with openshell.proto at 0357daee, before status field 10. + let bytes = + legacy_bytes("0a180a096c65676163792d6964120b6c65676163792d6e616d651a0430023807"); + let sandbox = Sandbox::decode(bytes.as_slice()).unwrap(); + let status = sandbox.status.as_ref().unwrap(); + assert_eq!(status.phase, SandboxPhase::Ready as i32); + assert_eq!(status.current_policy_version, 7); + assert!(status.configuration_admission.is_none()); + assert_eq!(sandbox.encode_to_vec(), bytes); + } + #[test] fn pre_move_storage_payloads_decode_after_package_relocation() { let refresh = StoredProviderCredentialRefreshState::decode( diff --git a/crates/openshell-server/tests/common/mod.rs b/crates/openshell-server/tests/common/mod.rs index 695d8d8f2a..270a692d60 100644 --- a/crates/openshell-server/tests/common/mod.rs +++ b/crates/openshell-server/tests/common/mod.rs @@ -435,6 +435,13 @@ impl OpenShell for TestOpenShell { Err(Status::unimplemented("not implemented in test")) } + async fn report_sandbox_configuration( + &self, + _request: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented in test")) + } + async fn report_policy_status( &self, _request: tonic::Request, diff --git a/crates/openshell-server/tests/supervisor_relay_integration.rs b/crates/openshell-server/tests/supervisor_relay_integration.rs index 448ae2cc7b..7004aadbc0 100644 --- a/crates/openshell-server/tests/supervisor_relay_integration.rs +++ b/crates/openshell-server/tests/supervisor_relay_integration.rs @@ -409,6 +409,13 @@ impl OpenShell for RelayGateway { ) -> Result, Status> { Err(Status::unimplemented("unused")) } + async fn report_sandbox_configuration( + &self, + _: tonic::Request, + ) -> Result, Status> { + Err(Status::unimplemented("not implemented in test")) + } + async fn report_policy_status( &self, _: tonic::Request, diff --git a/crates/openshell-supervisor-network/src/opa.rs b/crates/openshell-supervisor-network/src/opa.rs index d2191f8ed3..279b4f17c2 100644 --- a/crates/openshell-supervisor-network/src/opa.rs +++ b/crates/openshell-supervisor-network/src/opa.rs @@ -700,44 +700,39 @@ impl OpaEngine { proto: &ProtoSandboxPolicy, entrypoint_pid: u32, ) -> Result<()> { - // Build a complete new engine through the same validated pipeline. - let new = Self::from_proto_with_pid(proto, entrypoint_pid)?; - let new_engine = new - .engine - .into_inner() - .map_err(|_| miette::miette!("lock poisoned on new engine"))?; - let mut engine = self - .engine - .lock() - .map_err(|_| miette::miette!("OPA engine lock poisoned"))?; - *engine = new_engine; - *self - .fail_closed_reason - .write() - .map_err(|_| miette::miette!("OPA fail-closed state lock poisoned"))? = None; - self.advance_generation(); - Ok(()) + self.reload_configuration_from_proto_with_pid(proto, entrypoint_pid, None, || {}) } /// Reload the policy and middleware registry as one runtime generation. - /// - /// Both replacements are prepared before the live locks are acquired. The - /// engine and runner are then swapped while holding both locks, followed by - /// a single generation increment. A preparation or lock failure leaves the - /// live pair and generation untouched. pub fn reload_policy_and_middleware_from_proto_with_pid( &self, proto: &ProtoSandboxPolicy, entrypoint_pid: u32, registry: MiddlewareRegistry, + ) -> Result<()> { + self.reload_configuration_from_proto_with_pid(proto, entrypoint_pid, Some(registry), || {}) + } + + /// Validate a complete candidate before publishing policy, middleware, and + /// prepared credentials together. A validation or lock failure leaves the + /// active configuration untouched and never invokes `commit_credentials`. + /// + /// The callback must be infallible and must not call back into this engine. + /// Existing policy guards become stale before credentials change; new + /// policy readers remain blocked until the complete configuration is live. + pub fn reload_configuration_from_proto_with_pid( + &self, + proto: &ProtoSandboxPolicy, + entrypoint_pid: u32, + registry: Option, + commit_credentials: impl FnOnce(), ) -> Result<()> { let new = Self::from_proto_with_pid(proto, entrypoint_pid)?; let new_engine = new .engine .into_inner() .map_err(|_| miette::miette!("lock poisoned on new engine"))?; - // Match clone_engine_for_tunnel's lock order (engine, then runner) so - // readers can observe only the old pair or the new pair. + // Match clone_engine_for_tunnel's lock order (engine, then runner). let mut engine = self .engine .lock() @@ -746,14 +741,18 @@ impl OpaEngine { .middleware_runner .write() .map_err(|_| miette::miette!("middleware runner lock poisoned"))?; - let new_runner = runner.with_replacement_registry(registry); - *engine = new_engine; - *runner = new_runner; - *self + let mut fail_closed_reason = self .fail_closed_reason .write() - .map_err(|_| miette::miette!("OPA fail-closed state lock poisoned"))? = None; + .map_err(|_| miette::miette!("OPA fail-closed state lock poisoned"))?; + let new_runner = registry.map(|registry| runner.with_replacement_registry(registry)); self.advance_generation(); + commit_credentials(); + *engine = new_engine; + if let Some(new_runner) = new_runner { + *runner = new_runner; + } + *fail_closed_reason = None; Ok(()) } @@ -8521,6 +8520,44 @@ network_policies: assert!(described[0].is_resolved()); } + #[test] + fn rejected_configuration_never_commits_credentials() { + let mut proto = test_proto(); + let engine = OpaEngine::from_proto(&proto).unwrap(); + proto.network_middlewares.insert( + String::new(), + NetworkMiddlewareConfig { + middleware: openshell_supervisor_middleware_builtins::BUILTIN_REGEX.into(), + ..Default::default() + }, + ); + engine + .reload_configuration_from_proto_with_pid(&proto, 0, None, || { + panic!("invalid candidate must not publish credentials"); + }) + .expect_err("invalid candidate"); + assert_eq!(engine.current_generation(), 0); + } + + #[test] + fn configuration_commit_invalidates_old_guards_before_credentials_change() { + let proto = test_proto(); + let engine = OpaEngine::from_proto(&proto).unwrap(); + let old = engine.clone_engine_for_tunnel(0).unwrap(); + engine.enter_fail_closed("invalid candidate").unwrap(); + let mut committed = false; + engine + .reload_configuration_from_proto_with_pid(&proto, 0, None, || { + assert!(old.generation_guard().is_stale()); + assert_eq!(engine.current_generation(), 2); + committed = true; + }) + .unwrap(); + assert!(committed); + assert!(engine.fail_closed_reason().is_none()); + assert!(engine.clone_engine_for_tunnel(2).is_ok()); + } + #[tokio::test] async fn failed_combined_reload_preserves_policy_registry_and_generation() { let proto = test_proto(); diff --git a/docs/reference/gateway-config.mdx b/docs/reference/gateway-config.mdx index 14cdb05ece..818702089e 100644 --- a/docs/reference/gateway-config.mdx +++ b/docs/reference/gateway-config.mdx @@ -209,7 +209,7 @@ Local Docker, Podman, and VM gateways can also set `[openshell.gateway.mtls_auth `[openshell.gateway.tls]` supports optional SNI-based dual-certificate mode for deployments that need separate internal and external server certificates. Set `external_cert_path` and `external_key_path` to point at the external (e.g. ACME/publicly-trusted) certificate and key. List the hostnames that should be served with the external certificate in `external_server_names`. Connections whose TLS SNI hostname matches one of those names receive the external certificate; all other connections (including those with no SNI) receive the primary internal certificate from `cert_path`/`key_path`. Both fields must be set together — providing only one is a configuration error. On Kubernetes with the Helm chart, the external certificate is managed automatically when `certManager.serverIssuerRef.name` is set; the chart populates these fields from the cert-manager-issued external server certificate. -`[openshell.gateway] policy_validation_failure_mode` controls what sandbox supervisors do when a complete candidate policy fails runtime validation. The default, `fail_closed`, deactivates the previous network policy, closes relays pinned to it, and denies new egress until a valid generation loads. `retain_last_valid` leaves the previous valid generation active. Both modes reject the candidate atomically; startup always fails closed when no previous valid generation exists. Gateway mutation paths that can preflight a known effective scope reject invalid candidates before persistence and leave the active policy unchanged regardless of this setting. Changing the value requires restarting the gateway so it can reload `gateway.toml` and distribute the new posture to sandbox supervisors. +`[openshell.gateway] policy_validation_failure_mode` controls what sandbox supervisors do when a complete candidate policy fails runtime validation. The default, `fail_closed`, deactivates the previous network policy, closes relays pinned to it, and denies new egress until a valid generation loads. `retain_last_valid` leaves the previous valid generation active. Both modes reject the candidate atomically; startup keeps the workload unstarted until the effective policy and matching provider configuration pass admission. A rejected startup exposes `ConfigurationInvalid` and remains available for policy/provider repair in either mode. Gateway mutation paths that can preflight a known effective scope reject invalid candidates before persistence and leave the active policy unchanged regardless of this setting. Changing the value requires restarting the gateway so it can reload `gateway.toml` and distribute the new posture to sandbox supervisors. `[openshell.gateway.gateway_jwt] ttl_secs` controls gateway-minted sandbox JWT lifetime. When omitted, it defaults to `0`: the token `exp` claim and `expires_at_ms` response field become `0`, and the sandbox JWT does not expire. Use that default only for local single-player Docker, Podman, or VM gateways. Kubernetes and other shared deployments should set a positive TTL; Helm renders `3600` seconds by default, and the gateway logs a warning when a Kubernetes gateway uses `0`. diff --git a/docs/sandboxes/manage-sandboxes.mdx b/docs/sandboxes/manage-sandboxes.mdx index dd192d40fe..ea2b94a0c4 100644 --- a/docs/sandboxes/manage-sandboxes.mdx +++ b/docs/sandboxes/manage-sandboxes.mdx @@ -694,6 +694,14 @@ after it attempts every requested deletion if any entry failed. Every sandbox moves through a defined set of phases: +Before workload activation, OpenShell validates the effective policy and matching +provider configuration. A rejection keeps the workload unstarted and exposes a +`ConfigurationInvalid` condition in `Provisioning`. Use `openshell sandbox get` +to inspect the diagnostic, then [repair the policy or provider configuration](/sandboxes/policies#validation-failures). +Management operations remain available while startup is blocked. After repair, +the supervisor completes startup without recreating the sandbox. Starting a +stopped sandbox repeats configuration admission before launching its workload. + | Phase | Description | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Provisioning | The runtime is setting up the sandbox environment, or the gateway is waiting for the sandbox supervisor to establish its authenticated control session. | diff --git a/docs/sandboxes/policies.mdx b/docs/sandboxes/policies.mdx index af25238a6b..e910a7276c 100644 --- a/docs/sandboxes/policies.mdx +++ b/docs/sandboxes/policies.mdx @@ -241,6 +241,29 @@ The following steps outline the hot-reload policy update workflow. ### Validation failures +Before starting a workload, OpenShell validates its effective policy together +with attached provider rules and credential bindings. An image policy can be +valid alone and fail after composition, for example when an L4-only endpoint +overlaps a credentialed provider that requires L7 inspection. + +When startup validation fails, the sandbox stays in `Provisioning` with a +`ConfigurationInvalid` readiness condition. Its workload has not started. Inspect +the condition with `openshell sandbox get `, then submit a complete repaired +policy or detach the conflicting provider: + +```shell +openshell policy set --policy repaired-policy.yaml --wait +openshell sandbox provider detach +``` + +These are alternative repairs; choose the one that matches the intended access. +The supervisor starts the workload after the repaired configuration passes +validation. You can replace static policy fields while startup is blocked; +after activation, the usual static-field restrictions apply. Images without an +embedded policy use the restrictive baseline and gain network access only from +operator-selected configuration. Explicit user/global policy precedence remains +unchanged. + OpenShell validates a complete candidate policy before activating any part of it. Endpoints may overlap when their connection and request-processing metadata agree. For example, two `api.example.com:443` REST entries can contribute different allow and deny rules when they use the same TLS, destination, credential, parser, and enforcement settings. A plain L4 endpoint may overlap an L7 endpoint because it authorizes the destination without contributing request-processing metadata. A more-specific path endpoint may override request-processing metadata from a broader endpoint, such as a `/graphql` GraphQL endpoint alongside a general REST endpoint for the same host. OpenShell rejects the candidate when overlapping exact or wildcard host selectors can both contribute equally specific endpoint configuration and disagree on those fields. Internal policy-advisor provenance does not make otherwise compatible endpoints ambiguous. This lets an advisor proposal extend a provider-covered host without modifying the provider rule. TLS, destination IP constraints, credential handling, protocol, parser, and equally specific enforcement settings must still agree. @@ -275,7 +298,7 @@ Operators that explicitly prioritize availability can retain the previous genera policy_validation_failure_mode = "retain_last_valid" ``` -In `retain_last_valid` mode, the rejected candidate remains inactive and the previous valid generation remains active. If no previous valid generation exists, such as during initial startup, OpenShell still fails closed. Restart the gateway after changing `gateway.toml`; connected sandbox supervisors receive the configured posture from the restarted gateway. Individual sandboxes cannot override it. +In `retain_last_valid` mode, the rejected candidate remains inactive and the previous valid generation remains active. During initial startup, a rejected configuration keeps the workload unstarted in either mode. Restart the gateway after changing `gateway.toml`; connected sandbox supervisors receive the configured posture from the restarted gateway. Individual sandboxes cannot override it. OCSF configuration and finding events identify the rejected candidate, validation rationale, configured and effective modes, active generation, and whether the previous policy is active. When `retain_last_valid` is configured without a previous valid generation, the effective mode remains `fail_closed`. Connection denials during quarantine include the validation failure as their policy denial rationale. diff --git a/e2e/rust/Cargo.toml b/e2e/rust/Cargo.toml index 4f34caa25c..1bd30bc311 100644 --- a/e2e/rust/Cargo.toml +++ b/e2e/rust/Cargo.toml @@ -38,6 +38,11 @@ e2e-oidc-pkce = [] e2e-provider-refresh-keycloak = [] e2e-vm = ["e2e", "e2e-host-gateway"] +[[test]] +name = "policy_activation" +path = "tests/policy_activation.rs" +required-features = ["e2e-docker"] + [[test]] name = "oidc_pkce" path = "tests/oidc_pkce.rs" diff --git a/e2e/rust/tests/policy_activation.rs b/e2e/rust/tests/policy_activation.rs new file mode 100644 index 0000000000..45c9019a63 --- /dev/null +++ b/e2e/rust/tests/policy_activation.rs @@ -0,0 +1,354 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![cfg(feature = "e2e-docker")] + +//! A rejected image/provider composition must never launch its main process. + +use std::process::Stdio; +use std::time::Duration; + +use openshell_e2e::harness::binary::{openshell_bin, openshell_cmd}; +use openshell_e2e::harness::cli::run_cli; +use openshell_e2e::harness::container::{ContainerEngine, ImageGuard}; +use openshell_e2e::harness::output::strip_ansi; + +const MARKER: &str = "/sandbox/activation-count"; +const WORKLOAD: &str = "echo started >> /sandbox/activation-count; exec sleep infinity"; +const POLICY: &str = r"version: 1 +filesystem_policy: + include_workdir: true + read_only: [/usr, /lib, /proc, /etc, /dev/urandom] + read_write: [/sandbox, /tmp, /dev/null] +landlock: + compatibility: best_effort +process: + run_as_user: sandbox + run_as_group: sandbox +network_policies: + image_api: + endpoints: + - host: api.example.com + port: 443 + binaries: + - path: /usr/bin/curl +"; + +struct Resources { + sandbox: String, + standalone_sandbox: String, + provider: String, +} + +impl Drop for Resources { + fn drop(&mut self) { + // Deletion drains asynchronously; retry dependencies on panic as well. + let bin = openshell_bin(); + let _ = std::process::Command::new(&bin) + .args(["sandbox", "delete", &self.sandbox]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status(); + let _ = std::process::Command::new(&bin) + .args(["sandbox", "delete", &self.standalone_sandbox]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status(); + for _ in 0..20 { + let deleted = std::process::Command::new(&bin) + .args(["provider", "delete", &self.provider]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status(); + if deleted.is_ok_and(|status| status.success()) { + break; + } + std::thread::sleep(Duration::from_millis(250)); + } + let _ = std::process::Command::new(&bin) + .args(["provider", "profile", "delete", &self.provider]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status(); + } +} + +async fn cli_ok(args: &[&str]) { + let (output, code) = run_cli(args).await; + assert_eq!(code, 0, "{} failed:\n{output}", args.join(" ")); +} + +fn container_id(engine: &ContainerEngine, name: &str) -> String { + let output = engine + .command() + .args([ + "ps", + "--quiet", + "--filter", + &format!("label=openshell.ai/sandbox-name={name}"), + ]) + .output() + .expect("find sandbox container"); + assert!(output.status.success(), "container lookup failed"); + let ids = String::from_utf8_lossy(&output.stdout); + let ids: Vec<_> = ids.split_whitespace().collect(); + assert_eq!( + ids.len(), + 1, + "expected one running sandbox container: {ids:?}" + ); + ids[0].to_string() +} + +fn assert_marker(engine: &ContainerEngine, container: &str, started: bool) { + let script = if started { + format!("test -f {MARKER} && test \"$(wc -l < {MARKER})\" -eq 1") + } else { + format!("test ! -e {MARKER}") + }; + let output = engine + .command() + .args(["exec", container, "sh", "-c", &script]) + .output() + .expect("inspect actual workload marker"); + assert!( + output.status.success(), + "workload marker assertion failed (started={started}): {}", + String::from_utf8_lossy(&output.stderr) + ); +} + +async fn wait_for_marker(engine: &ContainerEngine, container: &str) { + let deadline = tokio::time::Instant::now() + Duration::from_secs(30); + loop { + let output = engine + .command() + .args(["exec", container, "test", "-f", MARKER]) + .output() + .unwrap(); + if output.status.success() { + break; + } + assert!( + tokio::time::Instant::now() < deadline, + "admitted workload did not start" + ); + tokio::time::sleep(Duration::from_millis(250)).await; + } + assert_marker(engine, container, true); +} + +#[tokio::test] +async fn invalid_image_provider_bundle_waits_for_repair_before_launch() { + let suffix = format!("{:016x}", rand::random::()); + let resources = Resources { + sandbox: format!("ac-{suffix}"), + standalone_sandbox: format!("al-{suffix}"), + provider: format!("ap-{suffix}"), + }; + let context = tempfile::tempdir().unwrap(); + std::fs::write(context.path().join("policy.yaml"), POLICY).unwrap(); + std::fs::write(context.path().join("Dockerfile"), r#"FROM public.ecr.aws/docker/library/python:3.13-slim +RUN apt-get update && apt-get install -y --no-install-recommends iproute2 && rm -rf /var/lib/apt/lists/* \ + && groupadd sandbox && useradd -m -g sandbox sandbox && mkdir -p /sandbox && chown sandbox:sandbox /sandbox +COPY policy.yaml /etc/openshell/policy.yaml +WORKDIR /sandbox +USER sandbox +CMD ["sh", "-c", "echo started >> /sandbox/activation-count; exec sleep infinity"] +"#).unwrap(); + let image = ImageGuard::build( + "policy-activation", + &context.path().join("Dockerfile"), + context.path(), + ) + .unwrap(); + // The very same embedded policy is valid before provider composition. + tokio::time::timeout( + Duration::from_secs(120), + cli_ok(&[ + "sandbox", + "create", + "--name", + &resources.standalone_sandbox, + "--detach", + "--from", + image.tag(), + "--", + "sh", + "-c", + WORKLOAD, + ]), + ) + .await + .expect("standalone image policy activates"); + let engine = ContainerEngine::from_env().unwrap(); + wait_for_marker( + &engine, + &container_id(&engine, &resources.standalone_sandbox), + ) + .await; + cli_ok(&["sandbox", "delete", &resources.standalone_sandbox]).await; + + let profile = context.path().join("provider.yaml"); + std::fs::write( + &profile, + format!( + r"id: {} +display_name: Activation test +category: other +credentials: + - name: token + env_vars: [ACTIVATION_TOKEN] + required: true + auth_style: bearer + header_name: authorization +endpoints: + - host: api.example.com + port: 443 + protocol: rest + access: full +binaries: + - path: /usr/bin/curl +", + resources.provider + ), + ) + .unwrap(); + cli_ok(&[ + "provider", + "profile", + "import", + "--file", + profile.to_str().unwrap(), + ]) + .await; + cli_ok(&[ + "provider", + "create", + "--name", + &resources.provider, + "--type", + &resources.provider, + "--credential", + "ACTIVATION_TOKEN=activation-test-not-a-real-secret", + ]) + .await; + let mut create = openshell_cmd() + .args([ + "sandbox", + "create", + "--name", + &resources.sandbox, + "--detach", + "--from", + image.tag(), + "--provider", + &resources.provider, + "--", + "sh", + "-c", + WORKLOAD, + ]) + .stdout(Stdio::null()) + .stderr(Stdio::inherit()) + .spawn() + .expect("start sandbox create"); + let deadline = tokio::time::Instant::now() + Duration::from_secs(120); + loop { + let (output, code) = + run_cli(&["sandbox", "get", &resources.sandbox, "--output", "json"]).await; + let clean = strip_ansi(&output); + if code == 0 && clean.contains("ConfigurationInvalid") { + let details: serde_json::Value = serde_json::from_str(&clean).expect("sandbox JSON"); + let phase = details + .get("phase") + .and_then(serde_json::Value::as_str) + .expect("sandbox detail must expose a phase string"); + assert_eq!( + phase, "Provisioning", + "rejected configuration must not be usable" + ); + assert!(!clean.contains("activation-test-not-a-real-secret")); + break; + } + assert!( + tokio::time::Instant::now() < deadline, + "configuration did not reject:\n{clean}" + ); + tokio::time::sleep(Duration::from_millis(500)).await; + } + let container = container_id(&engine, &resources.sandbox); + assert_marker(&engine, &container, false); + // Repeated observation distinguishes a stable gate from a crash/relaunch loop. + tokio::time::sleep(Duration::from_secs(3)).await; + assert_eq!(container_id(&engine, &resources.sandbox), container); + let restarts = engine + .command() + .args(["inspect", "--format", "{{.RestartCount}}", &container]) + .output() + .expect("inspect supervisor restart count"); + assert!(restarts.status.success()); + assert_eq!( + String::from_utf8_lossy(&restarts.stdout).trim(), + "0", + "invalid configuration must not crash-loop" + ); + assert_marker(&engine, &container, false); + let repaired = context.path().join("repaired.yaml"); + std::fs::write( + &repaired, + POLICY.replace( + " port: 443", + " port: 443\n protocol: rest\n access: full", + ), + ) + .unwrap(); + cli_ok(&[ + "policy", + "set", + &resources.sandbox, + "--policy", + repaired.to_str().unwrap(), + ]) + .await; + let status = tokio::time::timeout(Duration::from_secs(120), create.wait()) + .await + .expect("create completes after repair") + .expect("wait for create"); + assert!(status.success(), "create failed after valid repair"); + wait_for_marker(&engine, &container).await; + // An invalid later replacement must not displace the admitted live policy. + let (output, code) = run_cli(&[ + "policy", + "set", + &resources.sandbox, + "--policy", + context.path().join("policy.yaml").to_str().unwrap(), + ]) + .await; + assert_ne!( + code, 0, + "unsafe replacement unexpectedly succeeded: {output}" + ); + assert_marker(&engine, &container, true); + // An explicit stop/start must run the admission gate again before the saved + // command launches. Clear the marker to distinguish that new launch. + let removed = engine + .command() + .args(["exec", &container, "rm", "-f", MARKER]) + .status() + .unwrap(); + assert!(removed.success()); + cli_ok(&["sandbox", "stop", &resources.sandbox]).await; + tokio::time::timeout( + Duration::from_secs(120), + cli_ok(&["sandbox", "start", &resources.sandbox]), + ) + .await + .expect("repaired configuration revalidates on restart"); + let restarted_container = container_id(&engine, &resources.sandbox); + wait_for_marker(&engine, &restarted_container).await; + drop(create); + drop(resources); + drop(image); +} diff --git a/proto/openshell.proto b/proto/openshell.proto index 36f1026d84..14daec6330 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -475,6 +475,12 @@ service OpenShell { }; } + // Register startup and acknowledge an exact validated runtime configuration. + rpc ReportSandboxConfiguration(ReportSandboxConfigurationRequest) + returns (ReportSandboxConfigurationResponse) { + option (openshell.options.v1.authorization) = { auth_mode: "sandbox" }; + } + // Get provider environment for a sandbox (called by sandbox supervisor at startup). rpc GetSandboxProviderEnvironment(GetSandboxProviderEnvironmentRequest) returns (GetSandboxProviderEnvironmentResponse) { @@ -1065,6 +1071,8 @@ message SandboxStatus { // Presence indicates that the canonical main process exited. Exit code 0 // produces Completed; nonzero and signal-normalized exits produce Error. optional int32 exit_code = 9; + // Independent of infrastructure phase; retained across driver observations. + SandboxConfigurationAdmission configuration_admission = 10; } // User-facing sandbox condition derived from driver-native conditions. @@ -2284,6 +2292,32 @@ message ReportPolicyStatusRequest { // Report policy status response. message ReportPolicyStatusResponse {} +enum ConfigurationAdmissionState { + CONFIGURATION_ADMISSION_STATE_UNSPECIFIED = 0; + CONFIGURATION_ADMISSION_STATE_PENDING = 1; + CONFIGURATION_ADMISSION_STATE_ACCEPTED = 2; + CONFIGURATION_ADMISSION_STATE_REJECTED = 3; +} + +message SandboxConfigurationAdmission { + string instance_id = 1; + ConfigurationAdmissionState state = 2; + uint32 policy_version = 3; + string policy_hash = 4; + uint64 config_revision = 5; + uint64 provider_env_revision = 6; + string error = 7; +} + +message ReportSandboxConfigurationRequest { + string sandbox_id = 1; + SandboxConfigurationAdmission admission = 2; + // Pending registration replaces only this previously observed instance. + string expected_instance_id = 3; +} + +message ReportSandboxConfigurationResponse {} + // A versioned policy revision with metadata. message SandboxPolicyRevision { // Policy version (monotonically increasing per sandbox). diff --git a/proto/sandbox.proto b/proto/sandbox.proto index c2b61d0b3a..db92c3cc88 100644 --- a/proto/sandbox.proto +++ b/proto/sandbox.proto @@ -398,6 +398,13 @@ message GetSandboxConfigResponse { // False also covers older gateways that do not advertise this capability; // supervisors preserve their legacy unauthenticated connection behavior. bool extension_authentication_enabled = 12; + // True only after validating this complete policy/provider composition. + // Missing (older gateway) is deliberately not admission. + bool configuration_admitted = 13; + // Bounded, credential-free admission diagnostic. Empty for admitted policy. + string configuration_error = 14; + // Registration fence for a new supervisor; capture once and retain on retry. + string configuration_instance_id = 15; } // Connection details for one operator-registered supervisor middleware service. diff --git a/sdk/go/openshell/v1/internal/converter/coverage_test.go b/sdk/go/openshell/v1/internal/converter/coverage_test.go index 16929f672c..5a10be789f 100644 --- a/sdk/go/openshell/v1/internal/converter/coverage_test.go +++ b/sdk/go/openshell/v1/internal/converter/coverage_test.go @@ -110,14 +110,15 @@ func TestConverterCoversAllProtoFields_SandboxStartup(t *testing.T) { func TestConverterCoversAllProtoFields_SandboxStatus(t *testing.T) { handled := fieldSet{ - "sandbox_name": true, - "agent_pod": true, - "agent_fd": true, - "sandbox_fd": true, - "phase": true, - "conditions": true, - "current_policy_version": true, - "exit_code": true, + "sandbox_name": true, + "agent_pod": true, + "agent_fd": true, + "sandbox_fd": true, + "phase": true, + "conditions": true, + "current_policy_version": true, + "exit_code": true, + "configuration_admission": true, } // The instance ID coordinates internal gateway/supervisor lifecycle // fencing. It is exposed only through the raw protobuf API. diff --git a/sdk/go/openshell/v1/internal/converter/sandbox.go b/sdk/go/openshell/v1/internal/converter/sandbox.go index bf15f11059..d981588e9b 100644 --- a/sdk/go/openshell/v1/internal/converter/sandbox.go +++ b/sdk/go/openshell/v1/internal/converter/sandbox.go @@ -114,6 +114,25 @@ func sandboxStatusFromProto(status *pb.SandboxStatus) types.SandboxStatus { }) } result.ExitCode = CopyInt32Ptr(status.ExitCode) + if admission := status.GetConfigurationAdmission(); admission != nil { + state := types.ConfigurationAdmissionUnknown + switch admission.GetState() { + case pb.ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_PENDING: + state = types.ConfigurationAdmissionPending + case pb.ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_ACCEPTED: + state = types.ConfigurationAdmissionAccepted + case pb.ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_REJECTED: + state = types.ConfigurationAdmissionRejected + } + result.ConfigurationAdmission = &types.SandboxConfigurationAdmission{ + State: state, + PolicyVersion: admission.GetPolicyVersion(), + PolicyHash: admission.GetPolicyHash(), + ConfigRevision: admission.GetConfigRevision(), + ProviderEnvRevision: admission.GetProviderEnvRevision(), + Error: admission.GetError(), + } + } return result } diff --git a/sdk/go/openshell/v1/internal/converter/sandbox_test.go b/sdk/go/openshell/v1/internal/converter/sandbox_test.go index 6087933616..023376de20 100644 --- a/sdk/go/openshell/v1/internal/converter/sandbox_test.go +++ b/sdk/go/openshell/v1/internal/converter/sandbox_test.go @@ -18,6 +18,33 @@ import ( "google.golang.org/protobuf/types/known/structpb" ) +func TestSandboxConfigurationAdmissionFromProto(t *testing.T) { + for _, tc := range []struct { + wire pb.ConfigurationAdmissionState + want v1.ConfigurationAdmissionState + }{ + {pb.ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_PENDING, v1.ConfigurationAdmissionPending}, + {pb.ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_ACCEPTED, v1.ConfigurationAdmissionAccepted}, + {pb.ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_REJECTED, v1.ConfigurationAdmissionRejected}, + {pb.ConfigurationAdmissionState(99), v1.ConfigurationAdmissionUnknown}, + } { + t.Run(string(tc.want), func(t *testing.T) { + wire := &pb.SandboxStatus{ConfigurationAdmission: &pb.SandboxConfigurationAdmission{ + State: tc.wire, PolicyVersion: 4, PolicyHash: "hash", ConfigRevision: 5, + ProviderEnvRevision: 6, Error: "invalid endpoint", + }} + got := sandboxStatusFromProto(wire) + assert.Equal(t, &v1.SandboxConfigurationAdmission{ + State: tc.want, PolicyVersion: 4, PolicyHash: "hash", ConfigRevision: 5, + ProviderEnvRevision: 6, Error: "invalid endpoint", + }, got.ConfigurationAdmission) + wire.ConfigurationAdmission.Error = "changed" + assert.Equal(t, "invalid endpoint", got.ConfigurationAdmission.Error) + }) + } + assert.Nil(t, sandboxStatusFromProto(&pb.SandboxStatus{}).ConfigurationAdmission) +} + func TestSandboxFromProto(t *testing.T) { userNS := true gpuCount := uint32(2) diff --git a/sdk/go/openshell/v1/types/sandbox.go b/sdk/go/openshell/v1/types/sandbox.go index 8be13888ba..a8df6cea35 100644 --- a/sdk/go/openshell/v1/types/sandbox.go +++ b/sdk/go/openshell/v1/types/sandbox.go @@ -109,14 +109,37 @@ type SandboxWorkloadTemplateProvenance struct { // SandboxStatus holds the observed state of a sandbox. type SandboxStatus struct { - SandboxName string - AgentPod string - AgentFd string - SandboxFd string - Phase SandboxPhase - Conditions []SandboxCondition - CurrentPolicyVersion uint32 - ExitCode *int32 + SandboxName string + AgentPod string + AgentFd string + SandboxFd string + Phase SandboxPhase + Conditions []SandboxCondition + CurrentPolicyVersion uint32 + ExitCode *int32 + ConfigurationAdmission *SandboxConfigurationAdmission +} + +// ConfigurationAdmissionState describes validation of an effective configuration. +type ConfigurationAdmissionState string + +// Configuration admission states reported by the gateway. +const ( + ConfigurationAdmissionUnknown ConfigurationAdmissionState = "unknown" + ConfigurationAdmissionPending ConfigurationAdmissionState = "pending" + ConfigurationAdmissionAccepted ConfigurationAdmissionState = "accepted" + ConfigurationAdmissionRejected ConfigurationAdmissionState = "rejected" +) + +// SandboxConfigurationAdmission identifies a validated or rejected configuration. +// Supervisor instance fencing remains available through the raw protobuf API. +type SandboxConfigurationAdmission struct { + State ConfigurationAdmissionState + PolicyVersion uint32 + PolicyHash string + ConfigRevision uint64 + ProviderEnvRevision uint64 + Error string } // SandboxCondition describes an observed condition of a sandbox. diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index 1716e006ee..476e33c0c8 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -281,6 +281,58 @@ func (ProviderProfileCategory) EnumDescriptor() ([]byte, []int) { return file_openshell_proto_rawDescGZIP(), []int{3} } +type ConfigurationAdmissionState int32 + +const ( + ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_UNSPECIFIED ConfigurationAdmissionState = 0 + ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_PENDING ConfigurationAdmissionState = 1 + ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_ACCEPTED ConfigurationAdmissionState = 2 + ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_REJECTED ConfigurationAdmissionState = 3 +) + +// Enum value maps for ConfigurationAdmissionState. +var ( + ConfigurationAdmissionState_name = map[int32]string{ + 0: "CONFIGURATION_ADMISSION_STATE_UNSPECIFIED", + 1: "CONFIGURATION_ADMISSION_STATE_PENDING", + 2: "CONFIGURATION_ADMISSION_STATE_ACCEPTED", + 3: "CONFIGURATION_ADMISSION_STATE_REJECTED", + } + ConfigurationAdmissionState_value = map[string]int32{ + "CONFIGURATION_ADMISSION_STATE_UNSPECIFIED": 0, + "CONFIGURATION_ADMISSION_STATE_PENDING": 1, + "CONFIGURATION_ADMISSION_STATE_ACCEPTED": 2, + "CONFIGURATION_ADMISSION_STATE_REJECTED": 3, + } +) + +func (x ConfigurationAdmissionState) Enum() *ConfigurationAdmissionState { + p := new(ConfigurationAdmissionState) + *p = x + return p +} + +func (x ConfigurationAdmissionState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ConfigurationAdmissionState) Descriptor() protoreflect.EnumDescriptor { + return file_openshell_proto_enumTypes[4].Descriptor() +} + +func (ConfigurationAdmissionState) Type() protoreflect.EnumType { + return &file_openshell_proto_enumTypes[4] +} + +func (x ConfigurationAdmissionState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ConfigurationAdmissionState.Descriptor instead. +func (ConfigurationAdmissionState) EnumDescriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{4} +} + // Policy load status. type PolicyStatus int32 @@ -327,11 +379,11 @@ func (x PolicyStatus) String() string { } func (PolicyStatus) Descriptor() protoreflect.EnumDescriptor { - return file_openshell_proto_enumTypes[4].Descriptor() + return file_openshell_proto_enumTypes[5].Descriptor() } func (PolicyStatus) Type() protoreflect.EnumType { - return &file_openshell_proto_enumTypes[4] + return &file_openshell_proto_enumTypes[5] } func (x PolicyStatus) Number() protoreflect.EnumNumber { @@ -340,7 +392,7 @@ func (x PolicyStatus) Number() protoreflect.EnumNumber { // Deprecated: Use PolicyStatus.Descriptor instead. func (PolicyStatus) EnumDescriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{4} + return file_openshell_proto_rawDescGZIP(), []int{5} } // Service status enum. @@ -380,11 +432,11 @@ func (x ServiceStatus) String() string { } func (ServiceStatus) Descriptor() protoreflect.EnumDescriptor { - return file_openshell_proto_enumTypes[5].Descriptor() + return file_openshell_proto_enumTypes[6].Descriptor() } func (ServiceStatus) Type() protoreflect.EnumType { - return &file_openshell_proto_enumTypes[5] + return &file_openshell_proto_enumTypes[6] } func (x ServiceStatus) Number() protoreflect.EnumNumber { @@ -393,7 +445,7 @@ func (x ServiceStatus) Number() protoreflect.EnumNumber { // Deprecated: Use ServiceStatus.Descriptor instead. func (ServiceStatus) EnumDescriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{5} + return file_openshell_proto_rawDescGZIP(), []int{6} } // Workspace-scoped role for members. @@ -430,11 +482,11 @@ func (x WorkspaceRole) String() string { } func (WorkspaceRole) Descriptor() protoreflect.EnumDescriptor { - return file_openshell_proto_enumTypes[6].Descriptor() + return file_openshell_proto_enumTypes[7].Descriptor() } func (WorkspaceRole) Type() protoreflect.EnumType { - return &file_openshell_proto_enumTypes[6] + return &file_openshell_proto_enumTypes[7] } func (x WorkspaceRole) Number() protoreflect.EnumNumber { @@ -443,7 +495,7 @@ func (x WorkspaceRole) Number() protoreflect.EnumNumber { // Deprecated: Use WorkspaceRole.Descriptor instead. func (WorkspaceRole) EnumDescriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{6} + return file_openshell_proto_rawDescGZIP(), []int{7} } // Stable recovery action for the most recent provider credential refresh @@ -489,11 +541,11 @@ func (x ProviderCredentialRefreshRecoveryAction) String() string { } func (ProviderCredentialRefreshRecoveryAction) Descriptor() protoreflect.EnumDescriptor { - return file_openshell_proto_enumTypes[7].Descriptor() + return file_openshell_proto_enumTypes[8].Descriptor() } func (ProviderCredentialRefreshRecoveryAction) Type() protoreflect.EnumType { - return &file_openshell_proto_enumTypes[7] + return &file_openshell_proto_enumTypes[8] } func (x ProviderCredentialRefreshRecoveryAction) Number() protoreflect.EnumNumber { @@ -502,7 +554,7 @@ func (x ProviderCredentialRefreshRecoveryAction) Number() protoreflect.EnumNumbe // Deprecated: Use ProviderCredentialRefreshRecoveryAction.Descriptor instead. func (ProviderCredentialRefreshRecoveryAction) EnumDescriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{7} + return file_openshell_proto_rawDescGZIP(), []int{8} } // IssueSandboxToken request. Empty body; identity is established by the @@ -2196,9 +2248,11 @@ type SandboxStatus struct { // Normalized main process result. Signal exits use 128 + signal number. // Presence indicates that the canonical main process exited. Exit code 0 // produces Completed; nonzero and signal-normalized exits produce Error. - ExitCode *int32 `protobuf:"varint,9,opt,name=exit_code,json=exitCode,proto3,oneof" json:"exit_code,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + ExitCode *int32 `protobuf:"varint,9,opt,name=exit_code,json=exitCode,proto3,oneof" json:"exit_code,omitempty"` + // Independent of infrastructure phase; retained across driver observations. + ConfigurationAdmission *SandboxConfigurationAdmission `protobuf:"bytes,10,opt,name=configuration_admission,json=configurationAdmission,proto3" json:"configuration_admission,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SandboxStatus) Reset() { @@ -2294,6 +2348,13 @@ func (x *SandboxStatus) GetExitCode() int32 { return 0 } +func (x *SandboxStatus) GetConfigurationAdmission() *SandboxConfigurationAdmission { + if x != nil { + return x.ConfigurationAdmission + } + return nil +} + // User-facing sandbox condition derived from driver-native conditions. type SandboxCondition struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -9980,6 +10041,195 @@ func (*ReportPolicyStatusResponse) Descriptor() ([]byte, []int) { return file_openshell_proto_rawDescGZIP(), []int{141} } +type SandboxConfigurationAdmission struct { + state protoimpl.MessageState `protogen:"open.v1"` + InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` + State ConfigurationAdmissionState `protobuf:"varint,2,opt,name=state,proto3,enum=openshell.v1.ConfigurationAdmissionState" json:"state,omitempty"` + PolicyVersion uint32 `protobuf:"varint,3,opt,name=policy_version,json=policyVersion,proto3" json:"policy_version,omitempty"` + PolicyHash string `protobuf:"bytes,4,opt,name=policy_hash,json=policyHash,proto3" json:"policy_hash,omitempty"` + ConfigRevision uint64 `protobuf:"varint,5,opt,name=config_revision,json=configRevision,proto3" json:"config_revision,omitempty"` + ProviderEnvRevision uint64 `protobuf:"varint,6,opt,name=provider_env_revision,json=providerEnvRevision,proto3" json:"provider_env_revision,omitempty"` + Error string `protobuf:"bytes,7,opt,name=error,proto3" json:"error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxConfigurationAdmission) Reset() { + *x = SandboxConfigurationAdmission{} + mi := &file_openshell_proto_msgTypes[142] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxConfigurationAdmission) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxConfigurationAdmission) ProtoMessage() {} + +func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[142] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxConfigurationAdmission.ProtoReflect.Descriptor instead. +func (*SandboxConfigurationAdmission) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{142} +} + +func (x *SandboxConfigurationAdmission) GetInstanceId() string { + if x != nil { + return x.InstanceId + } + return "" +} + +func (x *SandboxConfigurationAdmission) GetState() ConfigurationAdmissionState { + if x != nil { + return x.State + } + return ConfigurationAdmissionState_CONFIGURATION_ADMISSION_STATE_UNSPECIFIED +} + +func (x *SandboxConfigurationAdmission) GetPolicyVersion() uint32 { + if x != nil { + return x.PolicyVersion + } + return 0 +} + +func (x *SandboxConfigurationAdmission) GetPolicyHash() string { + if x != nil { + return x.PolicyHash + } + return "" +} + +func (x *SandboxConfigurationAdmission) GetConfigRevision() uint64 { + if x != nil { + return x.ConfigRevision + } + return 0 +} + +func (x *SandboxConfigurationAdmission) GetProviderEnvRevision() uint64 { + if x != nil { + return x.ProviderEnvRevision + } + return 0 +} + +func (x *SandboxConfigurationAdmission) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +type ReportSandboxConfigurationRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + Admission *SandboxConfigurationAdmission `protobuf:"bytes,2,opt,name=admission,proto3" json:"admission,omitempty"` + // Pending registration replaces only this previously observed instance. + ExpectedInstanceId string `protobuf:"bytes,3,opt,name=expected_instance_id,json=expectedInstanceId,proto3" json:"expected_instance_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReportSandboxConfigurationRequest) Reset() { + *x = ReportSandboxConfigurationRequest{} + mi := &file_openshell_proto_msgTypes[143] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReportSandboxConfigurationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReportSandboxConfigurationRequest) ProtoMessage() {} + +func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[143] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReportSandboxConfigurationRequest.ProtoReflect.Descriptor instead. +func (*ReportSandboxConfigurationRequest) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{143} +} + +func (x *ReportSandboxConfigurationRequest) GetSandboxId() string { + if x != nil { + return x.SandboxId + } + return "" +} + +func (x *ReportSandboxConfigurationRequest) GetAdmission() *SandboxConfigurationAdmission { + if x != nil { + return x.Admission + } + return nil +} + +func (x *ReportSandboxConfigurationRequest) GetExpectedInstanceId() string { + if x != nil { + return x.ExpectedInstanceId + } + return "" +} + +type ReportSandboxConfigurationResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReportSandboxConfigurationResponse) Reset() { + *x = ReportSandboxConfigurationResponse{} + mi := &file_openshell_proto_msgTypes[144] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReportSandboxConfigurationResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReportSandboxConfigurationResponse) ProtoMessage() {} + +func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[144] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReportSandboxConfigurationResponse.ProtoReflect.Descriptor instead. +func (*ReportSandboxConfigurationResponse) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{144} +} + // A versioned policy revision with metadata. type SandboxPolicyRevision struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -10010,7 +10260,7 @@ type SandboxPolicyRevision struct { func (x *SandboxPolicyRevision) Reset() { *x = SandboxPolicyRevision{} - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10022,7 +10272,7 @@ func (x *SandboxPolicyRevision) String() string { func (*SandboxPolicyRevision) ProtoMessage() {} func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[145] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10035,7 +10285,7 @@ func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxPolicyRevision.ProtoReflect.Descriptor instead. func (*SandboxPolicyRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{142} + return file_openshell_proto_rawDescGZIP(), []int{145} } func (x *SandboxPolicyRevision) GetVersion() uint32 { @@ -10115,7 +10365,7 @@ type GetSandboxLogsRequest struct { func (x *GetSandboxLogsRequest) Reset() { *x = GetSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10127,7 +10377,7 @@ func (x *GetSandboxLogsRequest) String() string { func (*GetSandboxLogsRequest) ProtoMessage() {} func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[146] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10140,7 +10390,7 @@ func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*GetSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{143} + return file_openshell_proto_rawDescGZIP(), []int{146} } func (x *GetSandboxLogsRequest) GetSandboxId() string { @@ -10198,7 +10448,7 @@ type PushSandboxLogsRequest struct { func (x *PushSandboxLogsRequest) Reset() { *x = PushSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[147] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10210,7 +10460,7 @@ func (x *PushSandboxLogsRequest) String() string { func (*PushSandboxLogsRequest) ProtoMessage() {} func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[147] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10223,7 +10473,7 @@ func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*PushSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{144} + return file_openshell_proto_rawDescGZIP(), []int{147} } func (x *PushSandboxLogsRequest) GetSandboxId() string { @@ -10249,7 +10499,7 @@ type PushSandboxLogsResponse struct { func (x *PushSandboxLogsResponse) Reset() { *x = PushSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10261,7 +10511,7 @@ func (x *PushSandboxLogsResponse) String() string { func (*PushSandboxLogsResponse) ProtoMessage() {} func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[148] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10274,7 +10524,7 @@ func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*PushSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{145} + return file_openshell_proto_rawDescGZIP(), []int{148} } // Get sandbox logs response. @@ -10290,7 +10540,7 @@ type GetSandboxLogsResponse struct { func (x *GetSandboxLogsResponse) Reset() { *x = GetSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10302,7 +10552,7 @@ func (x *GetSandboxLogsResponse) String() string { func (*GetSandboxLogsResponse) ProtoMessage() {} func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[149] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10315,7 +10565,7 @@ func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*GetSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{146} + return file_openshell_proto_rawDescGZIP(), []int{149} } func (x *GetSandboxLogsResponse) GetLogs() []*SandboxLogLine { @@ -10348,7 +10598,7 @@ type SupervisorMessage struct { func (x *SupervisorMessage) Reset() { *x = SupervisorMessage{} - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10360,7 +10610,7 @@ func (x *SupervisorMessage) String() string { func (*SupervisorMessage) ProtoMessage() {} func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[150] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10373,7 +10623,7 @@ func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMessage.ProtoReflect.Descriptor instead. func (*SupervisorMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{147} + return file_openshell_proto_rawDescGZIP(), []int{150} } func (x *SupervisorMessage) GetPayload() isSupervisorMessage_Payload { @@ -10464,7 +10714,7 @@ type GatewayMessage struct { func (x *GatewayMessage) Reset() { *x = GatewayMessage{} - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10476,7 +10726,7 @@ func (x *GatewayMessage) String() string { func (*GatewayMessage) ProtoMessage() {} func (x *GatewayMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[151] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10489,7 +10739,7 @@ func (x *GatewayMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayMessage.ProtoReflect.Descriptor instead. func (*GatewayMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{148} + return file_openshell_proto_rawDescGZIP(), []int{151} } func (x *GatewayMessage) GetPayload() isGatewayMessage_Payload { @@ -10591,7 +10841,7 @@ type SupervisorHello struct { func (x *SupervisorHello) Reset() { *x = SupervisorHello{} - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10603,7 +10853,7 @@ func (x *SupervisorHello) String() string { func (*SupervisorHello) ProtoMessage() {} func (x *SupervisorHello) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[152] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10616,7 +10866,7 @@ func (x *SupervisorHello) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHello.ProtoReflect.Descriptor instead. func (*SupervisorHello) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{149} + return file_openshell_proto_rawDescGZIP(), []int{152} } func (x *SupervisorHello) GetSandboxId() string { @@ -10646,7 +10896,7 @@ type SessionAccepted struct { func (x *SessionAccepted) Reset() { *x = SessionAccepted{} - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10658,7 +10908,7 @@ func (x *SessionAccepted) String() string { func (*SessionAccepted) ProtoMessage() {} func (x *SessionAccepted) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[153] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10671,7 +10921,7 @@ func (x *SessionAccepted) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionAccepted.ProtoReflect.Descriptor instead. func (*SessionAccepted) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{150} + return file_openshell_proto_rawDescGZIP(), []int{153} } func (x *SessionAccepted) GetSessionId() string { @@ -10699,7 +10949,7 @@ type SessionRejected struct { func (x *SessionRejected) Reset() { *x = SessionRejected{} - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[154] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10711,7 +10961,7 @@ func (x *SessionRejected) String() string { func (*SessionRejected) ProtoMessage() {} func (x *SessionRejected) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[154] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10724,7 +10974,7 @@ func (x *SessionRejected) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRejected.ProtoReflect.Descriptor instead. func (*SessionRejected) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{151} + return file_openshell_proto_rawDescGZIP(), []int{154} } func (x *SessionRejected) GetReason() string { @@ -10743,7 +10993,7 @@ type SupervisorHeartbeat struct { func (x *SupervisorHeartbeat) Reset() { *x = SupervisorHeartbeat{} - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[155] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10755,7 +11005,7 @@ func (x *SupervisorHeartbeat) String() string { func (*SupervisorHeartbeat) ProtoMessage() {} func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[155] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10768,7 +11018,7 @@ func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHeartbeat.ProtoReflect.Descriptor instead. func (*SupervisorHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{152} + return file_openshell_proto_rawDescGZIP(), []int{155} } // Gateway heartbeat. @@ -10780,7 +11030,7 @@ type GatewayHeartbeat struct { func (x *GatewayHeartbeat) Reset() { *x = GatewayHeartbeat{} - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[156] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10792,7 +11042,7 @@ func (x *GatewayHeartbeat) String() string { func (*GatewayHeartbeat) ProtoMessage() {} func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[156] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10805,7 +11055,7 @@ func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayHeartbeat.ProtoReflect.Descriptor instead. func (*GatewayHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{153} + return file_openshell_proto_rawDescGZIP(), []int{156} } // Terminal result reported before the supervisor shuts down. A successful RPC @@ -10822,7 +11072,7 @@ type ReportMainProcessExitRequest struct { func (x *ReportMainProcessExitRequest) Reset() { *x = ReportMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[157] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10834,7 +11084,7 @@ func (x *ReportMainProcessExitRequest) String() string { func (*ReportMainProcessExitRequest) ProtoMessage() {} func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[157] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10847,7 +11097,7 @@ func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{154} + return file_openshell_proto_rawDescGZIP(), []int{157} } func (x *ReportMainProcessExitRequest) GetSandboxId() string { @@ -10879,7 +11129,7 @@ type ReportMainProcessExitResponse struct { func (x *ReportMainProcessExitResponse) Reset() { *x = ReportMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[158] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10891,7 +11141,7 @@ func (x *ReportMainProcessExitResponse) String() string { func (*ReportMainProcessExitResponse) ProtoMessage() {} func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[158] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10904,7 +11154,7 @@ func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{155} + return file_openshell_proto_rawDescGZIP(), []int{158} } // Terminal-delivery completion reported after all expected foreground SSH @@ -10919,7 +11169,7 @@ type FinalizeMainProcessExitRequest struct { func (x *FinalizeMainProcessExitRequest) Reset() { *x = FinalizeMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[159] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10931,7 +11181,7 @@ func (x *FinalizeMainProcessExitRequest) String() string { func (*FinalizeMainProcessExitRequest) ProtoMessage() {} func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[159] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10944,7 +11194,7 @@ func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{156} + return file_openshell_proto_rawDescGZIP(), []int{159} } func (x *FinalizeMainProcessExitRequest) GetSandboxId() string { @@ -10969,7 +11219,7 @@ type FinalizeMainProcessExitResponse struct { func (x *FinalizeMainProcessExitResponse) Reset() { *x = FinalizeMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[160] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10981,7 +11231,7 @@ func (x *FinalizeMainProcessExitResponse) String() string { func (*FinalizeMainProcessExitResponse) ProtoMessage() {} func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[160] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10994,7 +11244,7 @@ func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{157} + return file_openshell_proto_rawDescGZIP(), []int{160} } // Gateway requests the supervisor to open a relay channel. @@ -11023,7 +11273,7 @@ type RelayOpen struct { func (x *RelayOpen) Reset() { *x = RelayOpen{} - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[161] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11035,7 +11285,7 @@ func (x *RelayOpen) String() string { func (*RelayOpen) ProtoMessage() {} func (x *RelayOpen) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[161] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11048,7 +11298,7 @@ func (x *RelayOpen) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpen.ProtoReflect.Descriptor instead. func (*RelayOpen) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{158} + return file_openshell_proto_rawDescGZIP(), []int{161} } func (x *RelayOpen) GetChannelId() string { @@ -11115,7 +11365,7 @@ type SshRelayTarget struct { func (x *SshRelayTarget) Reset() { *x = SshRelayTarget{} - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[162] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11127,7 +11377,7 @@ func (x *SshRelayTarget) String() string { func (*SshRelayTarget) ProtoMessage() {} func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[162] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11140,7 +11390,7 @@ func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use SshRelayTarget.ProtoReflect.Descriptor instead. func (*SshRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{159} + return file_openshell_proto_rawDescGZIP(), []int{162} } // TCP target dialed by the supervisor from inside the sandbox. @@ -11156,7 +11406,7 @@ type TcpRelayTarget struct { func (x *TcpRelayTarget) Reset() { *x = TcpRelayTarget{} - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[163] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11168,7 +11418,7 @@ func (x *TcpRelayTarget) String() string { func (*TcpRelayTarget) ProtoMessage() {} func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[163] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11181,7 +11431,7 @@ func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpRelayTarget.ProtoReflect.Descriptor instead. func (*TcpRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{160} + return file_openshell_proto_rawDescGZIP(), []int{163} } func (x *TcpRelayTarget) GetHost() string { @@ -11209,7 +11459,7 @@ type RelayInit struct { func (x *RelayInit) Reset() { *x = RelayInit{} - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[164] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11221,7 +11471,7 @@ func (x *RelayInit) String() string { func (*RelayInit) ProtoMessage() {} func (x *RelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[164] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11234,7 +11484,7 @@ func (x *RelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayInit.ProtoReflect.Descriptor instead. func (*RelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{161} + return file_openshell_proto_rawDescGZIP(), []int{164} } func (x *RelayInit) GetChannelId() string { @@ -11261,7 +11511,7 @@ type RelayFrame struct { func (x *RelayFrame) Reset() { *x = RelayFrame{} - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[165] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11273,7 +11523,7 @@ func (x *RelayFrame) String() string { func (*RelayFrame) ProtoMessage() {} func (x *RelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[165] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11286,7 +11536,7 @@ func (x *RelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayFrame.ProtoReflect.Descriptor instead. func (*RelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{162} + return file_openshell_proto_rawDescGZIP(), []int{165} } func (x *RelayFrame) GetPayload() isRelayFrame_Payload { @@ -11345,7 +11595,7 @@ type RelayOpenResult struct { func (x *RelayOpenResult) Reset() { *x = RelayOpenResult{} - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[166] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11357,7 +11607,7 @@ func (x *RelayOpenResult) String() string { func (*RelayOpenResult) ProtoMessage() {} func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[166] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11370,7 +11620,7 @@ func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpenResult.ProtoReflect.Descriptor instead. func (*RelayOpenResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{163} + return file_openshell_proto_rawDescGZIP(), []int{166} } func (x *RelayOpenResult) GetChannelId() string { @@ -11407,7 +11657,7 @@ type RelayClose struct { func (x *RelayClose) Reset() { *x = RelayClose{} - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[167] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11419,7 +11669,7 @@ func (x *RelayClose) String() string { func (*RelayClose) ProtoMessage() {} func (x *RelayClose) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[167] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11432,7 +11682,7 @@ func (x *RelayClose) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayClose.ProtoReflect.Descriptor instead. func (*RelayClose) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{164} + return file_openshell_proto_rawDescGZIP(), []int{167} } func (x *RelayClose) GetChannelId() string { @@ -11466,7 +11716,7 @@ type L7RequestSample struct { func (x *L7RequestSample) Reset() { *x = L7RequestSample{} - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[168] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11478,7 +11728,7 @@ func (x *L7RequestSample) String() string { func (*L7RequestSample) ProtoMessage() {} func (x *L7RequestSample) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[168] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11491,7 +11741,7 @@ func (x *L7RequestSample) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RequestSample.ProtoReflect.Descriptor instead. func (*L7RequestSample) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{165} + return file_openshell_proto_rawDescGZIP(), []int{168} } func (x *L7RequestSample) GetMethod() string { @@ -11565,7 +11815,7 @@ type DenialSummary struct { func (x *DenialSummary) Reset() { *x = DenialSummary{} - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[169] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11577,7 +11827,7 @@ func (x *DenialSummary) String() string { func (*DenialSummary) ProtoMessage() {} func (x *DenialSummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[169] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11590,7 +11840,7 @@ func (x *DenialSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialSummary.ProtoReflect.Descriptor instead. func (*DenialSummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{166} + return file_openshell_proto_rawDescGZIP(), []int{169} } func (x *DenialSummary) GetSandboxId() string { @@ -11725,7 +11975,7 @@ type DenialGroupCount struct { func (x *DenialGroupCount) Reset() { *x = DenialGroupCount{} - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[170] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11737,7 +11987,7 @@ func (x *DenialGroupCount) String() string { func (*DenialGroupCount) ProtoMessage() {} func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[170] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11750,7 +12000,7 @@ func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialGroupCount.ProtoReflect.Descriptor instead. func (*DenialGroupCount) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{167} + return file_openshell_proto_rawDescGZIP(), []int{170} } func (x *DenialGroupCount) GetDenyGroup() string { @@ -11783,7 +12033,7 @@ type NetworkActivitySummary struct { func (x *NetworkActivitySummary) Reset() { *x = NetworkActivitySummary{} - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[171] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11795,7 +12045,7 @@ func (x *NetworkActivitySummary) String() string { func (*NetworkActivitySummary) ProtoMessage() {} func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[171] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11808,7 +12058,7 @@ func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkActivitySummary.ProtoReflect.Descriptor instead. func (*NetworkActivitySummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{168} + return file_openshell_proto_rawDescGZIP(), []int{171} } func (x *NetworkActivitySummary) GetNetworkActivityCount() uint32 { @@ -11896,7 +12146,7 @@ type PolicyChunk struct { func (x *PolicyChunk) Reset() { *x = PolicyChunk{} - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[172] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11908,7 +12158,7 @@ func (x *PolicyChunk) String() string { func (*PolicyChunk) ProtoMessage() {} func (x *PolicyChunk) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[172] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11921,7 +12171,7 @@ func (x *PolicyChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyChunk.ProtoReflect.Descriptor instead. func (*PolicyChunk) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{169} + return file_openshell_proto_rawDescGZIP(), []int{172} } func (x *PolicyChunk) GetId() string { @@ -12109,7 +12359,7 @@ type DraftPolicyUpdate struct { func (x *DraftPolicyUpdate) Reset() { *x = DraftPolicyUpdate{} - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[173] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12121,7 +12371,7 @@ func (x *DraftPolicyUpdate) String() string { func (*DraftPolicyUpdate) ProtoMessage() {} func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[173] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12134,7 +12384,7 @@ func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftPolicyUpdate.ProtoReflect.Descriptor instead. func (*DraftPolicyUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{170} + return file_openshell_proto_rawDescGZIP(), []int{173} } func (x *DraftPolicyUpdate) GetDraftVersion() uint64 { @@ -12192,7 +12442,7 @@ type SubmitPolicyAnalysisRequest struct { func (x *SubmitPolicyAnalysisRequest) Reset() { *x = SubmitPolicyAnalysisRequest{} - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[174] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12204,7 +12454,7 @@ func (x *SubmitPolicyAnalysisRequest) String() string { func (*SubmitPolicyAnalysisRequest) ProtoMessage() {} func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[174] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12217,7 +12467,7 @@ func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisRequest.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{171} + return file_openshell_proto_rawDescGZIP(), []int{174} } func (x *SubmitPolicyAnalysisRequest) GetSummaries() []*DenialSummary { @@ -12280,7 +12530,7 @@ type SubmitPolicyAnalysisResponse struct { func (x *SubmitPolicyAnalysisResponse) Reset() { *x = SubmitPolicyAnalysisResponse{} - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[175] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12292,7 +12542,7 @@ func (x *SubmitPolicyAnalysisResponse) String() string { func (*SubmitPolicyAnalysisResponse) ProtoMessage() {} func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[175] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12305,7 +12555,7 @@ func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisResponse.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{172} + return file_openshell_proto_rawDescGZIP(), []int{175} } func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunks() uint32 { @@ -12351,7 +12601,7 @@ type GetDraftPolicyRequest struct { func (x *GetDraftPolicyRequest) Reset() { *x = GetDraftPolicyRequest{} - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[176] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12363,7 +12613,7 @@ func (x *GetDraftPolicyRequest) String() string { func (*GetDraftPolicyRequest) ProtoMessage() {} func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[176] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12376,7 +12626,7 @@ func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyRequest.ProtoReflect.Descriptor instead. func (*GetDraftPolicyRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{173} + return file_openshell_proto_rawDescGZIP(), []int{176} } func (x *GetDraftPolicyRequest) GetName() string { @@ -12416,7 +12666,7 @@ type GetDraftPolicyResponse struct { func (x *GetDraftPolicyResponse) Reset() { *x = GetDraftPolicyResponse{} - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[177] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12428,7 +12678,7 @@ func (x *GetDraftPolicyResponse) String() string { func (*GetDraftPolicyResponse) ProtoMessage() {} func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[177] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12441,7 +12691,7 @@ func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyResponse.ProtoReflect.Descriptor instead. func (*GetDraftPolicyResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{174} + return file_openshell_proto_rawDescGZIP(), []int{177} } func (x *GetDraftPolicyResponse) GetChunks() []*PolicyChunk { @@ -12490,7 +12740,7 @@ type ApproveDraftChunkRequest struct { func (x *ApproveDraftChunkRequest) Reset() { *x = ApproveDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[178] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12502,7 +12752,7 @@ func (x *ApproveDraftChunkRequest) String() string { func (*ApproveDraftChunkRequest) ProtoMessage() {} func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[178] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12515,7 +12765,7 @@ func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkRequest.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{175} + return file_openshell_proto_rawDescGZIP(), []int{178} } func (x *ApproveDraftChunkRequest) GetName() string { @@ -12558,7 +12808,7 @@ type ApproveDraftChunkResponse struct { func (x *ApproveDraftChunkResponse) Reset() { *x = ApproveDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[179] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12570,7 +12820,7 @@ func (x *ApproveDraftChunkResponse) String() string { func (*ApproveDraftChunkResponse) ProtoMessage() {} func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[179] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12583,7 +12833,7 @@ func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkResponse.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{176} + return file_openshell_proto_rawDescGZIP(), []int{179} } func (x *ApproveDraftChunkResponse) GetPolicyVersion() uint32 { @@ -12617,7 +12867,7 @@ type RejectDraftChunkRequest struct { func (x *RejectDraftChunkRequest) Reset() { *x = RejectDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[180] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12629,7 +12879,7 @@ func (x *RejectDraftChunkRequest) String() string { func (*RejectDraftChunkRequest) ProtoMessage() {} func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[180] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12642,7 +12892,7 @@ func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkRequest.ProtoReflect.Descriptor instead. func (*RejectDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{177} + return file_openshell_proto_rawDescGZIP(), []int{180} } func (x *RejectDraftChunkRequest) GetName() string { @@ -12681,7 +12931,7 @@ type RejectDraftChunkResponse struct { func (x *RejectDraftChunkResponse) Reset() { *x = RejectDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[181] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12693,7 +12943,7 @@ func (x *RejectDraftChunkResponse) String() string { func (*RejectDraftChunkResponse) ProtoMessage() {} func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[181] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12706,7 +12956,7 @@ func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkResponse.ProtoReflect.Descriptor instead. func (*RejectDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{178} + return file_openshell_proto_rawDescGZIP(), []int{181} } // Approve all pending chunks. @@ -12720,7 +12970,7 @@ type DraftChunkApproval struct { func (x *DraftChunkApproval) Reset() { *x = DraftChunkApproval{} - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[182] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12732,7 +12982,7 @@ func (x *DraftChunkApproval) String() string { func (*DraftChunkApproval) ProtoMessage() {} func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[182] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12745,7 +12995,7 @@ func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftChunkApproval.ProtoReflect.Descriptor instead. func (*DraftChunkApproval) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{179} + return file_openshell_proto_rawDescGZIP(), []int{182} } func (x *DraftChunkApproval) GetChunkId() string { @@ -12779,7 +13029,7 @@ type ApproveAllDraftChunksRequest struct { func (x *ApproveAllDraftChunksRequest) Reset() { *x = ApproveAllDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[183] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12791,7 +13041,7 @@ func (x *ApproveAllDraftChunksRequest) String() string { func (*ApproveAllDraftChunksRequest) ProtoMessage() {} func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[183] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12804,7 +13054,7 @@ func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{180} + return file_openshell_proto_rawDescGZIP(), []int{183} } func (x *ApproveAllDraftChunksRequest) GetName() string { @@ -12852,7 +13102,7 @@ type ApproveAllDraftChunksResponse struct { func (x *ApproveAllDraftChunksResponse) Reset() { *x = ApproveAllDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[184] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12864,7 +13114,7 @@ func (x *ApproveAllDraftChunksResponse) String() string { func (*ApproveAllDraftChunksResponse) ProtoMessage() {} func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[184] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12877,7 +13127,7 @@ func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{181} + return file_openshell_proto_rawDescGZIP(), []int{184} } func (x *ApproveAllDraftChunksResponse) GetPolicyVersion() uint32 { @@ -12925,7 +13175,7 @@ type EditDraftChunkRequest struct { func (x *EditDraftChunkRequest) Reset() { *x = EditDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[185] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12937,7 +13187,7 @@ func (x *EditDraftChunkRequest) String() string { func (*EditDraftChunkRequest) ProtoMessage() {} func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[185] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12950,7 +13200,7 @@ func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkRequest.ProtoReflect.Descriptor instead. func (*EditDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{182} + return file_openshell_proto_rawDescGZIP(), []int{185} } func (x *EditDraftChunkRequest) GetName() string { @@ -12989,7 +13239,7 @@ type EditDraftChunkResponse struct { func (x *EditDraftChunkResponse) Reset() { *x = EditDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[186] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13001,7 +13251,7 @@ func (x *EditDraftChunkResponse) String() string { func (*EditDraftChunkResponse) ProtoMessage() {} func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[186] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13014,7 +13264,7 @@ func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkResponse.ProtoReflect.Descriptor instead. func (*EditDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{183} + return file_openshell_proto_rawDescGZIP(), []int{186} } // Reverse an approval (remove merged rule from active policy). @@ -13032,7 +13282,7 @@ type UndoDraftChunkRequest struct { func (x *UndoDraftChunkRequest) Reset() { *x = UndoDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[187] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13044,7 +13294,7 @@ func (x *UndoDraftChunkRequest) String() string { func (*UndoDraftChunkRequest) ProtoMessage() {} func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[187] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13057,7 +13307,7 @@ func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkRequest.ProtoReflect.Descriptor instead. func (*UndoDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{184} + return file_openshell_proto_rawDescGZIP(), []int{187} } func (x *UndoDraftChunkRequest) GetName() string { @@ -13093,7 +13343,7 @@ type UndoDraftChunkResponse struct { func (x *UndoDraftChunkResponse) Reset() { *x = UndoDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[188] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13105,7 +13355,7 @@ func (x *UndoDraftChunkResponse) String() string { func (*UndoDraftChunkResponse) ProtoMessage() {} func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[188] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13118,7 +13368,7 @@ func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkResponse.ProtoReflect.Descriptor instead. func (*UndoDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{185} + return file_openshell_proto_rawDescGZIP(), []int{188} } func (x *UndoDraftChunkResponse) GetPolicyVersion() uint32 { @@ -13148,7 +13398,7 @@ type ClearDraftChunksRequest struct { func (x *ClearDraftChunksRequest) Reset() { *x = ClearDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[189] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13160,7 +13410,7 @@ func (x *ClearDraftChunksRequest) String() string { func (*ClearDraftChunksRequest) ProtoMessage() {} func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[189] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13173,7 +13423,7 @@ func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ClearDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{186} + return file_openshell_proto_rawDescGZIP(), []int{189} } func (x *ClearDraftChunksRequest) GetName() string { @@ -13200,7 +13450,7 @@ type ClearDraftChunksResponse struct { func (x *ClearDraftChunksResponse) Reset() { *x = ClearDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[190] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13212,7 +13462,7 @@ func (x *ClearDraftChunksResponse) String() string { func (*ClearDraftChunksResponse) ProtoMessage() {} func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[190] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13225,7 +13475,7 @@ func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ClearDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{187} + return file_openshell_proto_rawDescGZIP(), []int{190} } func (x *ClearDraftChunksResponse) GetChunksCleared() uint32 { @@ -13248,7 +13498,7 @@ type GetDraftHistoryRequest struct { func (x *GetDraftHistoryRequest) Reset() { *x = GetDraftHistoryRequest{} - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[191] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13260,7 +13510,7 @@ func (x *GetDraftHistoryRequest) String() string { func (*GetDraftHistoryRequest) ProtoMessage() {} func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[191] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13273,7 +13523,7 @@ func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryRequest.ProtoReflect.Descriptor instead. func (*GetDraftHistoryRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{188} + return file_openshell_proto_rawDescGZIP(), []int{191} } func (x *GetDraftHistoryRequest) GetName() string { @@ -13307,7 +13557,7 @@ type DraftHistoryEntry struct { func (x *DraftHistoryEntry) Reset() { *x = DraftHistoryEntry{} - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[192] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13319,7 +13569,7 @@ func (x *DraftHistoryEntry) String() string { func (*DraftHistoryEntry) ProtoMessage() {} func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[192] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13332,7 +13582,7 @@ func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftHistoryEntry.ProtoReflect.Descriptor instead. func (*DraftHistoryEntry) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{189} + return file_openshell_proto_rawDescGZIP(), []int{192} } func (x *DraftHistoryEntry) GetTimestampMs() int64 { @@ -13373,7 +13623,7 @@ type GetDraftHistoryResponse struct { func (x *GetDraftHistoryResponse) Reset() { *x = GetDraftHistoryResponse{} - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13385,7 +13635,7 @@ func (x *GetDraftHistoryResponse) String() string { func (*GetDraftHistoryResponse) ProtoMessage() {} func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[193] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13398,7 +13648,7 @@ func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryResponse.ProtoReflect.Descriptor instead. func (*GetDraftHistoryResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{190} + return file_openshell_proto_rawDescGZIP(), []int{193} } func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry { @@ -13421,7 +13671,7 @@ type CreateWorkspaceRequest struct { func (x *CreateWorkspaceRequest) Reset() { *x = CreateWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13433,7 +13683,7 @@ func (x *CreateWorkspaceRequest) String() string { func (*CreateWorkspaceRequest) ProtoMessage() {} func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[194] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13446,7 +13696,7 @@ func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceRequest.ProtoReflect.Descriptor instead. func (*CreateWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{191} + return file_openshell_proto_rawDescGZIP(), []int{194} } func (x *CreateWorkspaceRequest) GetName() string { @@ -13473,7 +13723,7 @@ type CreateWorkspaceResponse struct { func (x *CreateWorkspaceResponse) Reset() { *x = CreateWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13485,7 +13735,7 @@ func (x *CreateWorkspaceResponse) String() string { func (*CreateWorkspaceResponse) ProtoMessage() {} func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[195] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13498,7 +13748,7 @@ func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceResponse.ProtoReflect.Descriptor instead. func (*CreateWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{192} + return file_openshell_proto_rawDescGZIP(), []int{195} } func (x *CreateWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -13519,7 +13769,7 @@ type GetWorkspaceRequest struct { func (x *GetWorkspaceRequest) Reset() { *x = GetWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13531,7 +13781,7 @@ func (x *GetWorkspaceRequest) String() string { func (*GetWorkspaceRequest) ProtoMessage() {} func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[196] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13544,7 +13794,7 @@ func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceRequest.ProtoReflect.Descriptor instead. func (*GetWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{193} + return file_openshell_proto_rawDescGZIP(), []int{196} } func (x *GetWorkspaceRequest) GetName() string { @@ -13564,7 +13814,7 @@ type GetWorkspaceResponse struct { func (x *GetWorkspaceResponse) Reset() { *x = GetWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13576,7 +13826,7 @@ func (x *GetWorkspaceResponse) String() string { func (*GetWorkspaceResponse) ProtoMessage() {} func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[197] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13589,7 +13839,7 @@ func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceResponse.ProtoReflect.Descriptor instead. func (*GetWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{194} + return file_openshell_proto_rawDescGZIP(), []int{197} } func (x *GetWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -13612,7 +13862,7 @@ type ListWorkspacesRequest struct { func (x *ListWorkspacesRequest) Reset() { *x = ListWorkspacesRequest{} - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13624,7 +13874,7 @@ func (x *ListWorkspacesRequest) String() string { func (*ListWorkspacesRequest) ProtoMessage() {} func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[198] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13637,7 +13887,7 @@ func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesRequest.ProtoReflect.Descriptor instead. func (*ListWorkspacesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{195} + return file_openshell_proto_rawDescGZIP(), []int{198} } func (x *ListWorkspacesRequest) GetLimit() uint32 { @@ -13671,7 +13921,7 @@ type ListWorkspacesResponse struct { func (x *ListWorkspacesResponse) Reset() { *x = ListWorkspacesResponse{} - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13683,7 +13933,7 @@ func (x *ListWorkspacesResponse) String() string { func (*ListWorkspacesResponse) ProtoMessage() {} func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[199] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13696,7 +13946,7 @@ func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesResponse.ProtoReflect.Descriptor instead. func (*ListWorkspacesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{196} + return file_openshell_proto_rawDescGZIP(), []int{199} } func (x *ListWorkspacesResponse) GetWorkspaces() []*datamodelv1.Workspace { @@ -13717,7 +13967,7 @@ type DeleteWorkspaceRequest struct { func (x *DeleteWorkspaceRequest) Reset() { *x = DeleteWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[200] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13729,7 +13979,7 @@ func (x *DeleteWorkspaceRequest) String() string { func (*DeleteWorkspaceRequest) ProtoMessage() {} func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[200] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13742,7 +13992,7 @@ func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{197} + return file_openshell_proto_rawDescGZIP(), []int{200} } func (x *DeleteWorkspaceRequest) GetName() string { @@ -13762,7 +14012,7 @@ type DeleteWorkspaceResponse struct { func (x *DeleteWorkspaceResponse) Reset() { *x = DeleteWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[201] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13774,7 +14024,7 @@ func (x *DeleteWorkspaceResponse) String() string { func (*DeleteWorkspaceResponse) ProtoMessage() {} func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[201] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13787,7 +14037,7 @@ func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceResponse.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{198} + return file_openshell_proto_rawDescGZIP(), []int{201} } func (x *DeleteWorkspaceResponse) GetDeleted() bool { @@ -13811,7 +14061,7 @@ type WorkspaceMember struct { func (x *WorkspaceMember) Reset() { *x = WorkspaceMember{} - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[202] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13823,7 +14073,7 @@ func (x *WorkspaceMember) String() string { func (*WorkspaceMember) ProtoMessage() {} func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[202] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13836,7 +14086,7 @@ func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkspaceMember.ProtoReflect.Descriptor instead. func (*WorkspaceMember) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{199} + return file_openshell_proto_rawDescGZIP(), []int{202} } func (x *WorkspaceMember) GetMetadata() *datamodelv1.ObjectMeta { @@ -13875,7 +14125,7 @@ type AddWorkspaceMemberRequest struct { func (x *AddWorkspaceMemberRequest) Reset() { *x = AddWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[203] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13887,7 +14137,7 @@ func (x *AddWorkspaceMemberRequest) String() string { func (*AddWorkspaceMemberRequest) ProtoMessage() {} func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[203] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13900,7 +14150,7 @@ func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{200} + return file_openshell_proto_rawDescGZIP(), []int{203} } func (x *AddWorkspaceMemberRequest) GetWorkspace() string { @@ -13934,7 +14184,7 @@ type AddWorkspaceMemberResponse struct { func (x *AddWorkspaceMemberResponse) Reset() { *x = AddWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[204] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13946,7 +14196,7 @@ func (x *AddWorkspaceMemberResponse) String() string { func (*AddWorkspaceMemberResponse) ProtoMessage() {} func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[204] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13959,7 +14209,7 @@ func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{201} + return file_openshell_proto_rawDescGZIP(), []int{204} } func (x *AddWorkspaceMemberResponse) GetMember() *WorkspaceMember { @@ -13982,7 +14232,7 @@ type RemoveWorkspaceMemberRequest struct { func (x *RemoveWorkspaceMemberRequest) Reset() { *x = RemoveWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[205] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13994,7 +14244,7 @@ func (x *RemoveWorkspaceMemberRequest) String() string { func (*RemoveWorkspaceMemberRequest) ProtoMessage() {} func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[205] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14007,7 +14257,7 @@ func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{202} + return file_openshell_proto_rawDescGZIP(), []int{205} } func (x *RemoveWorkspaceMemberRequest) GetWorkspace() string { @@ -14034,7 +14284,7 @@ type RemoveWorkspaceMemberResponse struct { func (x *RemoveWorkspaceMemberResponse) Reset() { *x = RemoveWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[206] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14046,7 +14296,7 @@ func (x *RemoveWorkspaceMemberResponse) String() string { func (*RemoveWorkspaceMemberResponse) ProtoMessage() {} func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[206] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14059,7 +14309,7 @@ func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{203} + return file_openshell_proto_rawDescGZIP(), []int{206} } func (x *RemoveWorkspaceMemberResponse) GetRemoved() bool { @@ -14082,7 +14332,7 @@ type ListWorkspaceMembersRequest struct { func (x *ListWorkspaceMembersRequest) Reset() { *x = ListWorkspaceMembersRequest{} - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[207] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14094,7 +14344,7 @@ func (x *ListWorkspaceMembersRequest) String() string { func (*ListWorkspaceMembersRequest) ProtoMessage() {} func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[207] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14107,7 +14357,7 @@ func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersRequest.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{204} + return file_openshell_proto_rawDescGZIP(), []int{207} } func (x *ListWorkspaceMembersRequest) GetWorkspace() string { @@ -14141,7 +14391,7 @@ type ListWorkspaceMembersResponse struct { func (x *ListWorkspaceMembersResponse) Reset() { *x = ListWorkspaceMembersResponse{} - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[208] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14153,7 +14403,7 @@ func (x *ListWorkspaceMembersResponse) String() string { func (*ListWorkspaceMembersResponse) ProtoMessage() {} func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[208] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14166,7 +14416,7 @@ func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersResponse.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{205} + return file_openshell_proto_rawDescGZIP(), []int{208} } func (x *ListWorkspaceMembersResponse) GetMembers() []*WorkspaceMember { @@ -14194,7 +14444,7 @@ type ExtensionServiceCredential struct { func (x *ExtensionServiceCredential) Reset() { *x = ExtensionServiceCredential{} - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[209] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14206,7 +14456,7 @@ func (x *ExtensionServiceCredential) String() string { func (*ExtensionServiceCredential) ProtoMessage() {} func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[209] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14219,7 +14469,7 @@ func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionServiceCredential.ProtoReflect.Descriptor instead. func (*ExtensionServiceCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{206} + return file_openshell_proto_rawDescGZIP(), []int{209} } func (x *ExtensionServiceCredential) GetServiceName() string { @@ -14364,7 +14614,7 @@ const file_openshell_proto_rawDesc = "" + "\tmax_burst\x18\x02 \x01(\rR\bmaxBurst\"b\n" + "!SandboxWorkloadTemplateProvenance\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12)\n" + - "\x10resource_version\x18\x02 \x01(\tR\x0fresourceVersion\"\x9a\x03\n" + + "\x10resource_version\x18\x02 \x01(\tR\x0fresourceVersion\"\x80\x04\n" + "\rSandboxStatus\x12!\n" + "\fsandbox_name\x18\x01 \x01(\tR\vsandboxName\x12\x1b\n" + "\tagent_pod\x18\x02 \x01(\tR\bagentPod\x12\x19\n" + @@ -14377,7 +14627,9 @@ const file_openshell_proto_rawDesc = "" + "\x05phase\x18\x06 \x01(\x0e2\x1a.openshell.v1.SandboxPhaseR\x05phase\x124\n" + "\x16current_policy_version\x18\a \x01(\rR\x14currentPolicyVersion\x127\n" + "\x18main_process_instance_id\x18\b \x01(\tR\x15mainProcessInstanceId\x12 \n" + - "\texit_code\x18\t \x01(\x05H\x00R\bexitCode\x88\x01\x01B\f\n" + + "\texit_code\x18\t \x01(\x05H\x00R\bexitCode\x88\x01\x01\x12d\n" + + "\x17configuration_admission\x18\n" + + " \x01(\v2+.openshell.v1.SandboxConfigurationAdmissionR\x16configurationAdmissionB\f\n" + "\n" + "_exit_code\"\xa2\x01\n" + "\x10SandboxCondition\x12\x12\n" + @@ -14959,7 +15211,23 @@ const file_openshell_proto_rawDesc = "" + "\x06status\x18\x03 \x01(\x0e2\x1a.openshell.v1.PolicyStatusR\x06status\x12\x1d\n" + "\n" + "load_error\x18\x04 \x01(\tR\tloadError\"\x1c\n" + - "\x1aReportPolicyStatusResponse\"\xbc\x03\n" + + "\x1aReportPolicyStatusResponse\"\xbc\x02\n" + + "\x1dSandboxConfigurationAdmission\x12\x1f\n" + + "\vinstance_id\x18\x01 \x01(\tR\n" + + "instanceId\x12?\n" + + "\x05state\x18\x02 \x01(\x0e2).openshell.v1.ConfigurationAdmissionStateR\x05state\x12%\n" + + "\x0epolicy_version\x18\x03 \x01(\rR\rpolicyVersion\x12\x1f\n" + + "\vpolicy_hash\x18\x04 \x01(\tR\n" + + "policyHash\x12'\n" + + "\x0fconfig_revision\x18\x05 \x01(\x04R\x0econfigRevision\x122\n" + + "\x15provider_env_revision\x18\x06 \x01(\x04R\x13providerEnvRevision\x12\x14\n" + + "\x05error\x18\a \x01(\tR\x05error\"\xbf\x01\n" + + "!ReportSandboxConfigurationRequest\x12\x1d\n" + + "\n" + + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12I\n" + + "\tadmission\x18\x02 \x01(\v2+.openshell.v1.SandboxConfigurationAdmissionR\tadmission\x120\n" + + "\x14expected_instance_id\x18\x03 \x01(\tR\x12expectedInstanceId\"$\n" + + "\"ReportSandboxConfigurationResponse\"\xbc\x03\n" + "\x15SandboxPolicyRevision\x12\x18\n" + "\aversion\x18\x01 \x01(\rR\aversion\x12\x1f\n" + "\vpolicy_hash\x18\x02 \x01(\tR\n" + @@ -15298,7 +15566,12 @@ const file_openshell_proto_rawDesc = "" + "(PROVIDER_PROFILE_CATEGORY_SOURCE_CONTROL\x10\x04\x12'\n" + "#PROVIDER_PROFILE_CATEGORY_MESSAGING\x10\x05\x12\"\n" + "\x1ePROVIDER_PROFILE_CATEGORY_DATA\x10\x06\x12'\n" + - "#PROVIDER_PROFILE_CATEGORY_KNOWLEDGE\x10\a*\x9a\x01\n" + + "#PROVIDER_PROFILE_CATEGORY_KNOWLEDGE\x10\a*\xcf\x01\n" + + "\x1bConfigurationAdmissionState\x12-\n" + + ")CONFIGURATION_ADMISSION_STATE_UNSPECIFIED\x10\x00\x12)\n" + + "%CONFIGURATION_ADMISSION_STATE_PENDING\x10\x01\x12*\n" + + "&CONFIGURATION_ADMISSION_STATE_ACCEPTED\x10\x02\x12*\n" + + "&CONFIGURATION_ADMISSION_STATE_REJECTED\x10\x03*\x9a\x01\n" + "\fPolicyStatus\x12\x1d\n" + "\x19POLICY_STATUS_UNSPECIFIED\x10\x00\x12\x19\n" + "\x15POLICY_STATUS_PENDING\x10\x01\x12\x18\n" + @@ -15319,7 +15592,7 @@ const file_openshell_proto_rawDesc = "" + "1PROVIDER_CREDENTIAL_REFRESH_RECOVERY_ACTION_RETRY\x10\x01\x12;\n" + "7PROVIDER_CREDENTIAL_REFRESH_RECOVERY_ACTION_REAUTHORIZE\x10\x02\x12A\n" + "=PROVIDER_CREDENTIAL_REFRESH_RECOVERY_ACTION_FIX_CONFIGURATION\x10\x03\x12;\n" + - "7PROVIDER_CREDENTIAL_REFRESH_RECOVERY_ACTION_INVESTIGATE\x10\x042\x8dM\n" + + "7PROVIDER_CREDENTIAL_REFRESH_RECOVERY_ACTION_INVESTIGATE\x10\x042\x9eN\n" + "\tOpenShell\x12Z\n" + "\x06Health\x12\x1b.openshell.v1.HealthRequest\x1a\x1c.openshell.v1.HealthResponse\"\x15\x82\xb5\x18\x11\n" + "\x0funauthenticated\x12i\n" + @@ -15417,6 +15690,8 @@ const file_openshell_proto_rawDesc = "" + "\x13ListSandboxPolicies\x12(.openshell.v1.ListSandboxPoliciesRequest\x1a).openshell.v1.ListSandboxPoliciesResponse\" \x82\xb5\x18\x1c\n" + "\x06bearer\x12\x04user\"\fsandbox:read\x12v\n" + "\x12ReportPolicyStatus\x12'.openshell.v1.ReportPolicyStatusRequest\x1a(.openshell.v1.ReportPolicyStatusResponse\"\r\x82\xb5\x18\t\n" + + "\asandbox\x12\x8e\x01\n" + + "\x1aReportSandboxConfiguration\x12/.openshell.v1.ReportSandboxConfigurationRequest\x1a0.openshell.v1.ReportSandboxConfigurationResponse\"\r\x82\xb5\x18\t\n" + "\asandbox\x12\x97\x01\n" + "\x1dGetSandboxProviderEnvironment\x122.openshell.v1.GetSandboxProviderEnvironmentRequest\x1a3.openshell.v1.GetSandboxProviderEnvironmentResponse\"\r\x82\xb5\x18\t\n" + "\asandbox\x12\x94\x01\n" + @@ -15485,581 +15760,590 @@ func file_openshell_proto_rawDescGZIP() []byte { return file_openshell_proto_rawDescData } -var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 8) -var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 228) +var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 9) +var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 231) var file_openshell_proto_goTypes = []any{ (SandboxPhase)(0), // 0: openshell.v1.SandboxPhase (ProviderCredentialTokenGrantType)(0), // 1: openshell.v1.ProviderCredentialTokenGrantType (ProviderCredentialRefreshStrategy)(0), // 2: openshell.v1.ProviderCredentialRefreshStrategy (ProviderProfileCategory)(0), // 3: openshell.v1.ProviderProfileCategory - (PolicyStatus)(0), // 4: openshell.v1.PolicyStatus - (ServiceStatus)(0), // 5: openshell.v1.ServiceStatus - (WorkspaceRole)(0), // 6: openshell.v1.WorkspaceRole - (ProviderCredentialRefreshRecoveryAction)(0), // 7: openshell.v1.ProviderCredentialRefreshRecoveryAction - (*IssueSandboxTokenRequest)(nil), // 8: openshell.v1.IssueSandboxTokenRequest - (*IssueSandboxTokenResponse)(nil), // 9: openshell.v1.IssueSandboxTokenResponse - (*RefreshSandboxTokenRequest)(nil), // 10: openshell.v1.RefreshSandboxTokenRequest - (*RefreshSandboxTokenResponse)(nil), // 11: openshell.v1.RefreshSandboxTokenResponse - (*HealthRequest)(nil), // 12: openshell.v1.HealthRequest - (*HealthResponse)(nil), // 13: openshell.v1.HealthResponse - (*GetCurrentUserRequest)(nil), // 14: openshell.v1.GetCurrentUserRequest - (*GetCurrentUserResponse)(nil), // 15: openshell.v1.GetCurrentUserResponse - (*GetGatewayInfoRequest)(nil), // 16: openshell.v1.GetGatewayInfoRequest - (*GetGatewayInfoResponse)(nil), // 17: openshell.v1.GetGatewayInfoResponse - (*ComputeDriverInfo)(nil), // 18: openshell.v1.ComputeDriverInfo - (*ComputeDriverCapabilities)(nil), // 19: openshell.v1.ComputeDriverCapabilities - (*ResourceCapabilities)(nil), // 20: openshell.v1.ResourceCapabilities - (*CpuResourceCapabilities)(nil), // 21: openshell.v1.CpuResourceCapabilities - (*MemoryResourceCapabilities)(nil), // 22: openshell.v1.MemoryResourceCapabilities - (*GpuResourceCapabilities)(nil), // 23: openshell.v1.GpuResourceCapabilities - (*Sandbox)(nil), // 24: openshell.v1.Sandbox - (*SandboxSpec)(nil), // 25: openshell.v1.SandboxSpec - (*ResourceRequirements)(nil), // 26: openshell.v1.ResourceRequirements - (*GpuResourceRequirements)(nil), // 27: openshell.v1.GpuResourceRequirements - (*SandboxTemplate)(nil), // 28: openshell.v1.SandboxTemplate - (*SandboxWorkloadTemplate)(nil), // 29: openshell.v1.SandboxWorkloadTemplate - (*SandboxWorkloadTemplateSpec)(nil), // 30: openshell.v1.SandboxWorkloadTemplateSpec - (*SandboxWorkloadConfig)(nil), // 31: openshell.v1.SandboxWorkloadConfig - (*SandboxResources)(nil), // 32: openshell.v1.SandboxResources - (*SandboxServiceLevel)(nil), // 33: openshell.v1.SandboxServiceLevel - (*SandboxStartup)(nil), // 34: openshell.v1.SandboxStartup - (*SandboxWorkloadTemplateProvenance)(nil), // 35: openshell.v1.SandboxWorkloadTemplateProvenance - (*SandboxStatus)(nil), // 36: openshell.v1.SandboxStatus - (*SandboxCondition)(nil), // 37: openshell.v1.SandboxCondition - (*PlatformEvent)(nil), // 38: openshell.v1.PlatformEvent - (*CreateSandboxRequest)(nil), // 39: openshell.v1.CreateSandboxRequest - (*CreateSandboxTemplateRequest)(nil), // 40: openshell.v1.CreateSandboxTemplateRequest - (*GetSandboxTemplateRequest)(nil), // 41: openshell.v1.GetSandboxTemplateRequest - (*ListSandboxTemplatesRequest)(nil), // 42: openshell.v1.ListSandboxTemplatesRequest - (*DeleteSandboxTemplateRequest)(nil), // 43: openshell.v1.DeleteSandboxTemplateRequest - (*SandboxTemplateResponse)(nil), // 44: openshell.v1.SandboxTemplateResponse - (*ListSandboxTemplatesResponse)(nil), // 45: openshell.v1.ListSandboxTemplatesResponse - (*DeleteSandboxTemplateResponse)(nil), // 46: openshell.v1.DeleteSandboxTemplateResponse - (*BeginRootfsTarStagingRequest)(nil), // 47: openshell.v1.BeginRootfsTarStagingRequest - (*BeginRootfsTarStagingResponse)(nil), // 48: openshell.v1.BeginRootfsTarStagingResponse - (*GetSandboxRequest)(nil), // 49: openshell.v1.GetSandboxRequest - (*ListSandboxesRequest)(nil), // 50: openshell.v1.ListSandboxesRequest - (*ListSandboxProvidersRequest)(nil), // 51: openshell.v1.ListSandboxProvidersRequest - (*AttachSandboxProviderRequest)(nil), // 52: openshell.v1.AttachSandboxProviderRequest - (*DetachSandboxProviderRequest)(nil), // 53: openshell.v1.DetachSandboxProviderRequest - (*DeleteSandboxRequest)(nil), // 54: openshell.v1.DeleteSandboxRequest - (*StopSandboxRequest)(nil), // 55: openshell.v1.StopSandboxRequest - (*StartSandboxRequest)(nil), // 56: openshell.v1.StartSandboxRequest - (*SandboxResponse)(nil), // 57: openshell.v1.SandboxResponse - (*ListSandboxesResponse)(nil), // 58: openshell.v1.ListSandboxesResponse - (*ListSandboxProvidersResponse)(nil), // 59: openshell.v1.ListSandboxProvidersResponse - (*AttachSandboxProviderResponse)(nil), // 60: openshell.v1.AttachSandboxProviderResponse - (*DetachSandboxProviderResponse)(nil), // 61: openshell.v1.DetachSandboxProviderResponse - (*DeleteSandboxResponse)(nil), // 62: openshell.v1.DeleteSandboxResponse - (*CreateSshSessionRequest)(nil), // 63: openshell.v1.CreateSshSessionRequest - (*CreateSshSessionResponse)(nil), // 64: openshell.v1.CreateSshSessionResponse - (*ExposeServiceRequest)(nil), // 65: openshell.v1.ExposeServiceRequest - (*GetServiceRequest)(nil), // 66: openshell.v1.GetServiceRequest - (*ListServicesRequest)(nil), // 67: openshell.v1.ListServicesRequest - (*ListServicesResponse)(nil), // 68: openshell.v1.ListServicesResponse - (*DeleteServiceRequest)(nil), // 69: openshell.v1.DeleteServiceRequest - (*DeleteServiceResponse)(nil), // 70: openshell.v1.DeleteServiceResponse - (*ServiceEndpoint)(nil), // 71: openshell.v1.ServiceEndpoint - (*ServiceEndpointResponse)(nil), // 72: openshell.v1.ServiceEndpointResponse - (*RevokeSshSessionRequest)(nil), // 73: openshell.v1.RevokeSshSessionRequest - (*RevokeSshSessionResponse)(nil), // 74: openshell.v1.RevokeSshSessionResponse - (*ExecSandboxRequest)(nil), // 75: openshell.v1.ExecSandboxRequest - (*ExecSandboxStdout)(nil), // 76: openshell.v1.ExecSandboxStdout - (*ExecSandboxStderr)(nil), // 77: openshell.v1.ExecSandboxStderr - (*ExecSandboxExit)(nil), // 78: openshell.v1.ExecSandboxExit - (*ExecSandboxEvent)(nil), // 79: openshell.v1.ExecSandboxEvent - (*TcpForwardInit)(nil), // 80: openshell.v1.TcpForwardInit - (*TcpForwardFrame)(nil), // 81: openshell.v1.TcpForwardFrame - (*ExecSandboxInput)(nil), // 82: openshell.v1.ExecSandboxInput - (*ExecSandboxWindowResize)(nil), // 83: openshell.v1.ExecSandboxWindowResize - (*SshSession)(nil), // 84: openshell.v1.SshSession - (*WatchSandboxRequest)(nil), // 85: openshell.v1.WatchSandboxRequest - (*SandboxStreamEvent)(nil), // 86: openshell.v1.SandboxStreamEvent - (*SandboxLogLine)(nil), // 87: openshell.v1.SandboxLogLine - (*SandboxStreamWarning)(nil), // 88: openshell.v1.SandboxStreamWarning - (*CreateProviderRequest)(nil), // 89: openshell.v1.CreateProviderRequest - (*GetProviderRequest)(nil), // 90: openshell.v1.GetProviderRequest - (*ListProvidersRequest)(nil), // 91: openshell.v1.ListProvidersRequest - (*UpdateProviderRequest)(nil), // 92: openshell.v1.UpdateProviderRequest - (*DeleteProviderRequest)(nil), // 93: openshell.v1.DeleteProviderRequest - (*ProviderResponse)(nil), // 94: openshell.v1.ProviderResponse - (*ListProvidersResponse)(nil), // 95: openshell.v1.ListProvidersResponse - (*ListProviderProfilesRequest)(nil), // 96: openshell.v1.ListProviderProfilesRequest - (*GetProviderProfileRequest)(nil), // 97: openshell.v1.GetProviderProfileRequest - (*ProviderProfileImportItem)(nil), // 98: openshell.v1.ProviderProfileImportItem - (*ProviderProfileDiagnostic)(nil), // 99: openshell.v1.ProviderProfileDiagnostic - (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 100: openshell.v1.ProviderCredentialTokenGrantAudienceOverride - (*ProviderCredentialTokenGrantSubjectToken)(nil), // 101: openshell.v1.ProviderCredentialTokenGrantSubjectToken - (*ProviderCredentialTokenGrant)(nil), // 102: openshell.v1.ProviderCredentialTokenGrant - (*ProviderProfileCredential)(nil), // 103: openshell.v1.ProviderProfileCredential - (*ProviderCredentialRefreshMaterial)(nil), // 104: openshell.v1.ProviderCredentialRefreshMaterial - (*ProviderCredentialRefreshOutput)(nil), // 105: openshell.v1.ProviderCredentialRefreshOutput - (*ProviderCredentialRefresh)(nil), // 106: openshell.v1.ProviderCredentialRefresh - (*ProviderCredentialRefreshStatus)(nil), // 107: openshell.v1.ProviderCredentialRefreshStatus - (*ProviderProfileDiscovery)(nil), // 108: openshell.v1.ProviderProfileDiscovery - (*GetProviderRefreshStatusRequest)(nil), // 109: openshell.v1.GetProviderRefreshStatusRequest - (*GetProviderRefreshStatusResponse)(nil), // 110: openshell.v1.GetProviderRefreshStatusResponse - (*ConfigureProviderRefreshRequest)(nil), // 111: openshell.v1.ConfigureProviderRefreshRequest - (*ConfigureProviderRefreshResponse)(nil), // 112: openshell.v1.ConfigureProviderRefreshResponse - (*RotateProviderCredentialRequest)(nil), // 113: openshell.v1.RotateProviderCredentialRequest - (*RotateProviderCredentialResponse)(nil), // 114: openshell.v1.RotateProviderCredentialResponse - (*DeleteProviderRefreshRequest)(nil), // 115: openshell.v1.DeleteProviderRefreshRequest - (*DeleteProviderRefreshResponse)(nil), // 116: openshell.v1.DeleteProviderRefreshResponse - (*ProviderProfile)(nil), // 117: openshell.v1.ProviderProfile - (*ProviderProfileResponse)(nil), // 118: openshell.v1.ProviderProfileResponse - (*ListProviderProfilesResponse)(nil), // 119: openshell.v1.ListProviderProfilesResponse - (*ImportProviderProfilesRequest)(nil), // 120: openshell.v1.ImportProviderProfilesRequest - (*ImportProviderProfilesResponse)(nil), // 121: openshell.v1.ImportProviderProfilesResponse - (*UpdateProviderProfilesRequest)(nil), // 122: openshell.v1.UpdateProviderProfilesRequest - (*UpdateProviderProfilesResponse)(nil), // 123: openshell.v1.UpdateProviderProfilesResponse - (*LintProviderProfilesRequest)(nil), // 124: openshell.v1.LintProviderProfilesRequest - (*LintProviderProfilesResponse)(nil), // 125: openshell.v1.LintProviderProfilesResponse - (*DeleteProviderResponse)(nil), // 126: openshell.v1.DeleteProviderResponse - (*DeleteProviderProfileRequest)(nil), // 127: openshell.v1.DeleteProviderProfileRequest - (*DeleteProviderProfileResponse)(nil), // 128: openshell.v1.DeleteProviderProfileResponse - (*GetSandboxProviderEnvironmentRequest)(nil), // 129: openshell.v1.GetSandboxProviderEnvironmentRequest - (*StaticCredentialEndpointBinding)(nil), // 130: openshell.v1.StaticCredentialEndpointBinding - (*StaticCredentialBinding)(nil), // 131: openshell.v1.StaticCredentialBinding - (*GetSandboxProviderEnvironmentResponse)(nil), // 132: openshell.v1.GetSandboxProviderEnvironmentResponse - (*ExchangeProviderSubjectTokenRequest)(nil), // 133: openshell.v1.ExchangeProviderSubjectTokenRequest - (*ExchangeProviderSubjectTokenResponse)(nil), // 134: openshell.v1.ExchangeProviderSubjectTokenResponse - (*UpdateConfigRequest)(nil), // 135: openshell.v1.UpdateConfigRequest - (*PolicyMergeOperation)(nil), // 136: openshell.v1.PolicyMergeOperation - (*AddNetworkRule)(nil), // 137: openshell.v1.AddNetworkRule - (*RemoveNetworkEndpoint)(nil), // 138: openshell.v1.RemoveNetworkEndpoint - (*RemoveNetworkRule)(nil), // 139: openshell.v1.RemoveNetworkRule - (*AddDenyRules)(nil), // 140: openshell.v1.AddDenyRules - (*AddAllowRules)(nil), // 141: openshell.v1.AddAllowRules - (*RemoveNetworkBinary)(nil), // 142: openshell.v1.RemoveNetworkBinary - (*UpdateConfigResponse)(nil), // 143: openshell.v1.UpdateConfigResponse - (*GetSandboxPolicyStatusRequest)(nil), // 144: openshell.v1.GetSandboxPolicyStatusRequest - (*GetSandboxPolicyStatusResponse)(nil), // 145: openshell.v1.GetSandboxPolicyStatusResponse - (*ListSandboxPoliciesRequest)(nil), // 146: openshell.v1.ListSandboxPoliciesRequest - (*ListSandboxPoliciesResponse)(nil), // 147: openshell.v1.ListSandboxPoliciesResponse - (*ReportPolicyStatusRequest)(nil), // 148: openshell.v1.ReportPolicyStatusRequest - (*ReportPolicyStatusResponse)(nil), // 149: openshell.v1.ReportPolicyStatusResponse - (*SandboxPolicyRevision)(nil), // 150: openshell.v1.SandboxPolicyRevision - (*GetSandboxLogsRequest)(nil), // 151: openshell.v1.GetSandboxLogsRequest - (*PushSandboxLogsRequest)(nil), // 152: openshell.v1.PushSandboxLogsRequest - (*PushSandboxLogsResponse)(nil), // 153: openshell.v1.PushSandboxLogsResponse - (*GetSandboxLogsResponse)(nil), // 154: openshell.v1.GetSandboxLogsResponse - (*SupervisorMessage)(nil), // 155: openshell.v1.SupervisorMessage - (*GatewayMessage)(nil), // 156: openshell.v1.GatewayMessage - (*SupervisorHello)(nil), // 157: openshell.v1.SupervisorHello - (*SessionAccepted)(nil), // 158: openshell.v1.SessionAccepted - (*SessionRejected)(nil), // 159: openshell.v1.SessionRejected - (*SupervisorHeartbeat)(nil), // 160: openshell.v1.SupervisorHeartbeat - (*GatewayHeartbeat)(nil), // 161: openshell.v1.GatewayHeartbeat - (*ReportMainProcessExitRequest)(nil), // 162: openshell.v1.ReportMainProcessExitRequest - (*ReportMainProcessExitResponse)(nil), // 163: openshell.v1.ReportMainProcessExitResponse - (*FinalizeMainProcessExitRequest)(nil), // 164: openshell.v1.FinalizeMainProcessExitRequest - (*FinalizeMainProcessExitResponse)(nil), // 165: openshell.v1.FinalizeMainProcessExitResponse - (*RelayOpen)(nil), // 166: openshell.v1.RelayOpen - (*SshRelayTarget)(nil), // 167: openshell.v1.SshRelayTarget - (*TcpRelayTarget)(nil), // 168: openshell.v1.TcpRelayTarget - (*RelayInit)(nil), // 169: openshell.v1.RelayInit - (*RelayFrame)(nil), // 170: openshell.v1.RelayFrame - (*RelayOpenResult)(nil), // 171: openshell.v1.RelayOpenResult - (*RelayClose)(nil), // 172: openshell.v1.RelayClose - (*L7RequestSample)(nil), // 173: openshell.v1.L7RequestSample - (*DenialSummary)(nil), // 174: openshell.v1.DenialSummary - (*DenialGroupCount)(nil), // 175: openshell.v1.DenialGroupCount - (*NetworkActivitySummary)(nil), // 176: openshell.v1.NetworkActivitySummary - (*PolicyChunk)(nil), // 177: openshell.v1.PolicyChunk - (*DraftPolicyUpdate)(nil), // 178: openshell.v1.DraftPolicyUpdate - (*SubmitPolicyAnalysisRequest)(nil), // 179: openshell.v1.SubmitPolicyAnalysisRequest - (*SubmitPolicyAnalysisResponse)(nil), // 180: openshell.v1.SubmitPolicyAnalysisResponse - (*GetDraftPolicyRequest)(nil), // 181: openshell.v1.GetDraftPolicyRequest - (*GetDraftPolicyResponse)(nil), // 182: openshell.v1.GetDraftPolicyResponse - (*ApproveDraftChunkRequest)(nil), // 183: openshell.v1.ApproveDraftChunkRequest - (*ApproveDraftChunkResponse)(nil), // 184: openshell.v1.ApproveDraftChunkResponse - (*RejectDraftChunkRequest)(nil), // 185: openshell.v1.RejectDraftChunkRequest - (*RejectDraftChunkResponse)(nil), // 186: openshell.v1.RejectDraftChunkResponse - (*DraftChunkApproval)(nil), // 187: openshell.v1.DraftChunkApproval - (*ApproveAllDraftChunksRequest)(nil), // 188: openshell.v1.ApproveAllDraftChunksRequest - (*ApproveAllDraftChunksResponse)(nil), // 189: openshell.v1.ApproveAllDraftChunksResponse - (*EditDraftChunkRequest)(nil), // 190: openshell.v1.EditDraftChunkRequest - (*EditDraftChunkResponse)(nil), // 191: openshell.v1.EditDraftChunkResponse - (*UndoDraftChunkRequest)(nil), // 192: openshell.v1.UndoDraftChunkRequest - (*UndoDraftChunkResponse)(nil), // 193: openshell.v1.UndoDraftChunkResponse - (*ClearDraftChunksRequest)(nil), // 194: openshell.v1.ClearDraftChunksRequest - (*ClearDraftChunksResponse)(nil), // 195: openshell.v1.ClearDraftChunksResponse - (*GetDraftHistoryRequest)(nil), // 196: openshell.v1.GetDraftHistoryRequest - (*DraftHistoryEntry)(nil), // 197: openshell.v1.DraftHistoryEntry - (*GetDraftHistoryResponse)(nil), // 198: openshell.v1.GetDraftHistoryResponse - (*CreateWorkspaceRequest)(nil), // 199: openshell.v1.CreateWorkspaceRequest - (*CreateWorkspaceResponse)(nil), // 200: openshell.v1.CreateWorkspaceResponse - (*GetWorkspaceRequest)(nil), // 201: openshell.v1.GetWorkspaceRequest - (*GetWorkspaceResponse)(nil), // 202: openshell.v1.GetWorkspaceResponse - (*ListWorkspacesRequest)(nil), // 203: openshell.v1.ListWorkspacesRequest - (*ListWorkspacesResponse)(nil), // 204: openshell.v1.ListWorkspacesResponse - (*DeleteWorkspaceRequest)(nil), // 205: openshell.v1.DeleteWorkspaceRequest - (*DeleteWorkspaceResponse)(nil), // 206: openshell.v1.DeleteWorkspaceResponse - (*WorkspaceMember)(nil), // 207: openshell.v1.WorkspaceMember - (*AddWorkspaceMemberRequest)(nil), // 208: openshell.v1.AddWorkspaceMemberRequest - (*AddWorkspaceMemberResponse)(nil), // 209: openshell.v1.AddWorkspaceMemberResponse - (*RemoveWorkspaceMemberRequest)(nil), // 210: openshell.v1.RemoveWorkspaceMemberRequest - (*RemoveWorkspaceMemberResponse)(nil), // 211: openshell.v1.RemoveWorkspaceMemberResponse - (*ListWorkspaceMembersRequest)(nil), // 212: openshell.v1.ListWorkspaceMembersRequest - (*ListWorkspaceMembersResponse)(nil), // 213: openshell.v1.ListWorkspaceMembersResponse - (*ExtensionServiceCredential)(nil), // 214: openshell.v1.ExtensionServiceCredential - nil, // 215: openshell.v1.SandboxSpec.EnvironmentEntry - nil, // 216: openshell.v1.SandboxTemplate.LabelsEntry - nil, // 217: openshell.v1.SandboxTemplate.AnnotationsEntry - nil, // 218: openshell.v1.SandboxTemplate.EnvironmentEntry - nil, // 219: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - nil, // 220: openshell.v1.PlatformEvent.MetadataEntry - nil, // 221: openshell.v1.CreateSandboxRequest.LabelsEntry - nil, // 222: openshell.v1.CreateSandboxRequest.AnnotationsEntry - nil, // 223: openshell.v1.ExecSandboxRequest.EnvironmentEntry - nil, // 224: openshell.v1.SandboxLogLine.FieldsEntry - nil, // 225: openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry - nil, // 226: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - nil, // 227: openshell.v1.ProviderProfile.AnnotationsEntry - nil, // 228: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - nil, // 229: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry - nil, // 230: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - nil, // 231: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - nil, // 232: openshell.v1.UpdateConfigRequest.AnnotationsEntry - nil, // 233: openshell.v1.UpdateConfigResponse.AnnotationsEntry - nil, // 234: openshell.v1.SandboxPolicyRevision.ProvenanceEntry - nil, // 235: openshell.v1.CreateWorkspaceRequest.LabelsEntry - (*datamodelv1.ObjectMeta)(nil), // 236: openshell.datamodel.v1.ObjectMeta - (*sandboxv1.SandboxPolicy)(nil), // 237: openshell.sandbox.v1.SandboxPolicy - (*structpb.Struct)(nil), // 238: google.protobuf.Struct - (*durationpb.Duration)(nil), // 239: google.protobuf.Duration - (*datamodelv1.Provider)(nil), // 240: openshell.datamodel.v1.Provider - (*sandboxv1.NetworkEndpoint)(nil), // 241: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 242: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 243: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 244: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 245: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 246: openshell.sandbox.v1.L7Rule - (*datamodelv1.Workspace)(nil), // 247: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 248: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 249: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 250: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 251: openshell.sandbox.v1.GetGatewayConfigResponse + (ConfigurationAdmissionState)(0), // 4: openshell.v1.ConfigurationAdmissionState + (PolicyStatus)(0), // 5: openshell.v1.PolicyStatus + (ServiceStatus)(0), // 6: openshell.v1.ServiceStatus + (WorkspaceRole)(0), // 7: openshell.v1.WorkspaceRole + (ProviderCredentialRefreshRecoveryAction)(0), // 8: openshell.v1.ProviderCredentialRefreshRecoveryAction + (*IssueSandboxTokenRequest)(nil), // 9: openshell.v1.IssueSandboxTokenRequest + (*IssueSandboxTokenResponse)(nil), // 10: openshell.v1.IssueSandboxTokenResponse + (*RefreshSandboxTokenRequest)(nil), // 11: openshell.v1.RefreshSandboxTokenRequest + (*RefreshSandboxTokenResponse)(nil), // 12: openshell.v1.RefreshSandboxTokenResponse + (*HealthRequest)(nil), // 13: openshell.v1.HealthRequest + (*HealthResponse)(nil), // 14: openshell.v1.HealthResponse + (*GetCurrentUserRequest)(nil), // 15: openshell.v1.GetCurrentUserRequest + (*GetCurrentUserResponse)(nil), // 16: openshell.v1.GetCurrentUserResponse + (*GetGatewayInfoRequest)(nil), // 17: openshell.v1.GetGatewayInfoRequest + (*GetGatewayInfoResponse)(nil), // 18: openshell.v1.GetGatewayInfoResponse + (*ComputeDriverInfo)(nil), // 19: openshell.v1.ComputeDriverInfo + (*ComputeDriverCapabilities)(nil), // 20: openshell.v1.ComputeDriverCapabilities + (*ResourceCapabilities)(nil), // 21: openshell.v1.ResourceCapabilities + (*CpuResourceCapabilities)(nil), // 22: openshell.v1.CpuResourceCapabilities + (*MemoryResourceCapabilities)(nil), // 23: openshell.v1.MemoryResourceCapabilities + (*GpuResourceCapabilities)(nil), // 24: openshell.v1.GpuResourceCapabilities + (*Sandbox)(nil), // 25: openshell.v1.Sandbox + (*SandboxSpec)(nil), // 26: openshell.v1.SandboxSpec + (*ResourceRequirements)(nil), // 27: openshell.v1.ResourceRequirements + (*GpuResourceRequirements)(nil), // 28: openshell.v1.GpuResourceRequirements + (*SandboxTemplate)(nil), // 29: openshell.v1.SandboxTemplate + (*SandboxWorkloadTemplate)(nil), // 30: openshell.v1.SandboxWorkloadTemplate + (*SandboxWorkloadTemplateSpec)(nil), // 31: openshell.v1.SandboxWorkloadTemplateSpec + (*SandboxWorkloadConfig)(nil), // 32: openshell.v1.SandboxWorkloadConfig + (*SandboxResources)(nil), // 33: openshell.v1.SandboxResources + (*SandboxServiceLevel)(nil), // 34: openshell.v1.SandboxServiceLevel + (*SandboxStartup)(nil), // 35: openshell.v1.SandboxStartup + (*SandboxWorkloadTemplateProvenance)(nil), // 36: openshell.v1.SandboxWorkloadTemplateProvenance + (*SandboxStatus)(nil), // 37: openshell.v1.SandboxStatus + (*SandboxCondition)(nil), // 38: openshell.v1.SandboxCondition + (*PlatformEvent)(nil), // 39: openshell.v1.PlatformEvent + (*CreateSandboxRequest)(nil), // 40: openshell.v1.CreateSandboxRequest + (*CreateSandboxTemplateRequest)(nil), // 41: openshell.v1.CreateSandboxTemplateRequest + (*GetSandboxTemplateRequest)(nil), // 42: openshell.v1.GetSandboxTemplateRequest + (*ListSandboxTemplatesRequest)(nil), // 43: openshell.v1.ListSandboxTemplatesRequest + (*DeleteSandboxTemplateRequest)(nil), // 44: openshell.v1.DeleteSandboxTemplateRequest + (*SandboxTemplateResponse)(nil), // 45: openshell.v1.SandboxTemplateResponse + (*ListSandboxTemplatesResponse)(nil), // 46: openshell.v1.ListSandboxTemplatesResponse + (*DeleteSandboxTemplateResponse)(nil), // 47: openshell.v1.DeleteSandboxTemplateResponse + (*BeginRootfsTarStagingRequest)(nil), // 48: openshell.v1.BeginRootfsTarStagingRequest + (*BeginRootfsTarStagingResponse)(nil), // 49: openshell.v1.BeginRootfsTarStagingResponse + (*GetSandboxRequest)(nil), // 50: openshell.v1.GetSandboxRequest + (*ListSandboxesRequest)(nil), // 51: openshell.v1.ListSandboxesRequest + (*ListSandboxProvidersRequest)(nil), // 52: openshell.v1.ListSandboxProvidersRequest + (*AttachSandboxProviderRequest)(nil), // 53: openshell.v1.AttachSandboxProviderRequest + (*DetachSandboxProviderRequest)(nil), // 54: openshell.v1.DetachSandboxProviderRequest + (*DeleteSandboxRequest)(nil), // 55: openshell.v1.DeleteSandboxRequest + (*StopSandboxRequest)(nil), // 56: openshell.v1.StopSandboxRequest + (*StartSandboxRequest)(nil), // 57: openshell.v1.StartSandboxRequest + (*SandboxResponse)(nil), // 58: openshell.v1.SandboxResponse + (*ListSandboxesResponse)(nil), // 59: openshell.v1.ListSandboxesResponse + (*ListSandboxProvidersResponse)(nil), // 60: openshell.v1.ListSandboxProvidersResponse + (*AttachSandboxProviderResponse)(nil), // 61: openshell.v1.AttachSandboxProviderResponse + (*DetachSandboxProviderResponse)(nil), // 62: openshell.v1.DetachSandboxProviderResponse + (*DeleteSandboxResponse)(nil), // 63: openshell.v1.DeleteSandboxResponse + (*CreateSshSessionRequest)(nil), // 64: openshell.v1.CreateSshSessionRequest + (*CreateSshSessionResponse)(nil), // 65: openshell.v1.CreateSshSessionResponse + (*ExposeServiceRequest)(nil), // 66: openshell.v1.ExposeServiceRequest + (*GetServiceRequest)(nil), // 67: openshell.v1.GetServiceRequest + (*ListServicesRequest)(nil), // 68: openshell.v1.ListServicesRequest + (*ListServicesResponse)(nil), // 69: openshell.v1.ListServicesResponse + (*DeleteServiceRequest)(nil), // 70: openshell.v1.DeleteServiceRequest + (*DeleteServiceResponse)(nil), // 71: openshell.v1.DeleteServiceResponse + (*ServiceEndpoint)(nil), // 72: openshell.v1.ServiceEndpoint + (*ServiceEndpointResponse)(nil), // 73: openshell.v1.ServiceEndpointResponse + (*RevokeSshSessionRequest)(nil), // 74: openshell.v1.RevokeSshSessionRequest + (*RevokeSshSessionResponse)(nil), // 75: openshell.v1.RevokeSshSessionResponse + (*ExecSandboxRequest)(nil), // 76: openshell.v1.ExecSandboxRequest + (*ExecSandboxStdout)(nil), // 77: openshell.v1.ExecSandboxStdout + (*ExecSandboxStderr)(nil), // 78: openshell.v1.ExecSandboxStderr + (*ExecSandboxExit)(nil), // 79: openshell.v1.ExecSandboxExit + (*ExecSandboxEvent)(nil), // 80: openshell.v1.ExecSandboxEvent + (*TcpForwardInit)(nil), // 81: openshell.v1.TcpForwardInit + (*TcpForwardFrame)(nil), // 82: openshell.v1.TcpForwardFrame + (*ExecSandboxInput)(nil), // 83: openshell.v1.ExecSandboxInput + (*ExecSandboxWindowResize)(nil), // 84: openshell.v1.ExecSandboxWindowResize + (*SshSession)(nil), // 85: openshell.v1.SshSession + (*WatchSandboxRequest)(nil), // 86: openshell.v1.WatchSandboxRequest + (*SandboxStreamEvent)(nil), // 87: openshell.v1.SandboxStreamEvent + (*SandboxLogLine)(nil), // 88: openshell.v1.SandboxLogLine + (*SandboxStreamWarning)(nil), // 89: openshell.v1.SandboxStreamWarning + (*CreateProviderRequest)(nil), // 90: openshell.v1.CreateProviderRequest + (*GetProviderRequest)(nil), // 91: openshell.v1.GetProviderRequest + (*ListProvidersRequest)(nil), // 92: openshell.v1.ListProvidersRequest + (*UpdateProviderRequest)(nil), // 93: openshell.v1.UpdateProviderRequest + (*DeleteProviderRequest)(nil), // 94: openshell.v1.DeleteProviderRequest + (*ProviderResponse)(nil), // 95: openshell.v1.ProviderResponse + (*ListProvidersResponse)(nil), // 96: openshell.v1.ListProvidersResponse + (*ListProviderProfilesRequest)(nil), // 97: openshell.v1.ListProviderProfilesRequest + (*GetProviderProfileRequest)(nil), // 98: openshell.v1.GetProviderProfileRequest + (*ProviderProfileImportItem)(nil), // 99: openshell.v1.ProviderProfileImportItem + (*ProviderProfileDiagnostic)(nil), // 100: openshell.v1.ProviderProfileDiagnostic + (*ProviderCredentialTokenGrantAudienceOverride)(nil), // 101: openshell.v1.ProviderCredentialTokenGrantAudienceOverride + (*ProviderCredentialTokenGrantSubjectToken)(nil), // 102: openshell.v1.ProviderCredentialTokenGrantSubjectToken + (*ProviderCredentialTokenGrant)(nil), // 103: openshell.v1.ProviderCredentialTokenGrant + (*ProviderProfileCredential)(nil), // 104: openshell.v1.ProviderProfileCredential + (*ProviderCredentialRefreshMaterial)(nil), // 105: openshell.v1.ProviderCredentialRefreshMaterial + (*ProviderCredentialRefreshOutput)(nil), // 106: openshell.v1.ProviderCredentialRefreshOutput + (*ProviderCredentialRefresh)(nil), // 107: openshell.v1.ProviderCredentialRefresh + (*ProviderCredentialRefreshStatus)(nil), // 108: openshell.v1.ProviderCredentialRefreshStatus + (*ProviderProfileDiscovery)(nil), // 109: openshell.v1.ProviderProfileDiscovery + (*GetProviderRefreshStatusRequest)(nil), // 110: openshell.v1.GetProviderRefreshStatusRequest + (*GetProviderRefreshStatusResponse)(nil), // 111: openshell.v1.GetProviderRefreshStatusResponse + (*ConfigureProviderRefreshRequest)(nil), // 112: openshell.v1.ConfigureProviderRefreshRequest + (*ConfigureProviderRefreshResponse)(nil), // 113: openshell.v1.ConfigureProviderRefreshResponse + (*RotateProviderCredentialRequest)(nil), // 114: openshell.v1.RotateProviderCredentialRequest + (*RotateProviderCredentialResponse)(nil), // 115: openshell.v1.RotateProviderCredentialResponse + (*DeleteProviderRefreshRequest)(nil), // 116: openshell.v1.DeleteProviderRefreshRequest + (*DeleteProviderRefreshResponse)(nil), // 117: openshell.v1.DeleteProviderRefreshResponse + (*ProviderProfile)(nil), // 118: openshell.v1.ProviderProfile + (*ProviderProfileResponse)(nil), // 119: openshell.v1.ProviderProfileResponse + (*ListProviderProfilesResponse)(nil), // 120: openshell.v1.ListProviderProfilesResponse + (*ImportProviderProfilesRequest)(nil), // 121: openshell.v1.ImportProviderProfilesRequest + (*ImportProviderProfilesResponse)(nil), // 122: openshell.v1.ImportProviderProfilesResponse + (*UpdateProviderProfilesRequest)(nil), // 123: openshell.v1.UpdateProviderProfilesRequest + (*UpdateProviderProfilesResponse)(nil), // 124: openshell.v1.UpdateProviderProfilesResponse + (*LintProviderProfilesRequest)(nil), // 125: openshell.v1.LintProviderProfilesRequest + (*LintProviderProfilesResponse)(nil), // 126: openshell.v1.LintProviderProfilesResponse + (*DeleteProviderResponse)(nil), // 127: openshell.v1.DeleteProviderResponse + (*DeleteProviderProfileRequest)(nil), // 128: openshell.v1.DeleteProviderProfileRequest + (*DeleteProviderProfileResponse)(nil), // 129: openshell.v1.DeleteProviderProfileResponse + (*GetSandboxProviderEnvironmentRequest)(nil), // 130: openshell.v1.GetSandboxProviderEnvironmentRequest + (*StaticCredentialEndpointBinding)(nil), // 131: openshell.v1.StaticCredentialEndpointBinding + (*StaticCredentialBinding)(nil), // 132: openshell.v1.StaticCredentialBinding + (*GetSandboxProviderEnvironmentResponse)(nil), // 133: openshell.v1.GetSandboxProviderEnvironmentResponse + (*ExchangeProviderSubjectTokenRequest)(nil), // 134: openshell.v1.ExchangeProviderSubjectTokenRequest + (*ExchangeProviderSubjectTokenResponse)(nil), // 135: openshell.v1.ExchangeProviderSubjectTokenResponse + (*UpdateConfigRequest)(nil), // 136: openshell.v1.UpdateConfigRequest + (*PolicyMergeOperation)(nil), // 137: openshell.v1.PolicyMergeOperation + (*AddNetworkRule)(nil), // 138: openshell.v1.AddNetworkRule + (*RemoveNetworkEndpoint)(nil), // 139: openshell.v1.RemoveNetworkEndpoint + (*RemoveNetworkRule)(nil), // 140: openshell.v1.RemoveNetworkRule + (*AddDenyRules)(nil), // 141: openshell.v1.AddDenyRules + (*AddAllowRules)(nil), // 142: openshell.v1.AddAllowRules + (*RemoveNetworkBinary)(nil), // 143: openshell.v1.RemoveNetworkBinary + (*UpdateConfigResponse)(nil), // 144: openshell.v1.UpdateConfigResponse + (*GetSandboxPolicyStatusRequest)(nil), // 145: openshell.v1.GetSandboxPolicyStatusRequest + (*GetSandboxPolicyStatusResponse)(nil), // 146: openshell.v1.GetSandboxPolicyStatusResponse + (*ListSandboxPoliciesRequest)(nil), // 147: openshell.v1.ListSandboxPoliciesRequest + (*ListSandboxPoliciesResponse)(nil), // 148: openshell.v1.ListSandboxPoliciesResponse + (*ReportPolicyStatusRequest)(nil), // 149: openshell.v1.ReportPolicyStatusRequest + (*ReportPolicyStatusResponse)(nil), // 150: openshell.v1.ReportPolicyStatusResponse + (*SandboxConfigurationAdmission)(nil), // 151: openshell.v1.SandboxConfigurationAdmission + (*ReportSandboxConfigurationRequest)(nil), // 152: openshell.v1.ReportSandboxConfigurationRequest + (*ReportSandboxConfigurationResponse)(nil), // 153: openshell.v1.ReportSandboxConfigurationResponse + (*SandboxPolicyRevision)(nil), // 154: openshell.v1.SandboxPolicyRevision + (*GetSandboxLogsRequest)(nil), // 155: openshell.v1.GetSandboxLogsRequest + (*PushSandboxLogsRequest)(nil), // 156: openshell.v1.PushSandboxLogsRequest + (*PushSandboxLogsResponse)(nil), // 157: openshell.v1.PushSandboxLogsResponse + (*GetSandboxLogsResponse)(nil), // 158: openshell.v1.GetSandboxLogsResponse + (*SupervisorMessage)(nil), // 159: openshell.v1.SupervisorMessage + (*GatewayMessage)(nil), // 160: openshell.v1.GatewayMessage + (*SupervisorHello)(nil), // 161: openshell.v1.SupervisorHello + (*SessionAccepted)(nil), // 162: openshell.v1.SessionAccepted + (*SessionRejected)(nil), // 163: openshell.v1.SessionRejected + (*SupervisorHeartbeat)(nil), // 164: openshell.v1.SupervisorHeartbeat + (*GatewayHeartbeat)(nil), // 165: openshell.v1.GatewayHeartbeat + (*ReportMainProcessExitRequest)(nil), // 166: openshell.v1.ReportMainProcessExitRequest + (*ReportMainProcessExitResponse)(nil), // 167: openshell.v1.ReportMainProcessExitResponse + (*FinalizeMainProcessExitRequest)(nil), // 168: openshell.v1.FinalizeMainProcessExitRequest + (*FinalizeMainProcessExitResponse)(nil), // 169: openshell.v1.FinalizeMainProcessExitResponse + (*RelayOpen)(nil), // 170: openshell.v1.RelayOpen + (*SshRelayTarget)(nil), // 171: openshell.v1.SshRelayTarget + (*TcpRelayTarget)(nil), // 172: openshell.v1.TcpRelayTarget + (*RelayInit)(nil), // 173: openshell.v1.RelayInit + (*RelayFrame)(nil), // 174: openshell.v1.RelayFrame + (*RelayOpenResult)(nil), // 175: openshell.v1.RelayOpenResult + (*RelayClose)(nil), // 176: openshell.v1.RelayClose + (*L7RequestSample)(nil), // 177: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 178: openshell.v1.DenialSummary + (*DenialGroupCount)(nil), // 179: openshell.v1.DenialGroupCount + (*NetworkActivitySummary)(nil), // 180: openshell.v1.NetworkActivitySummary + (*PolicyChunk)(nil), // 181: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 182: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 183: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 184: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 185: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 186: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 187: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 188: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 189: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 190: openshell.v1.RejectDraftChunkResponse + (*DraftChunkApproval)(nil), // 191: openshell.v1.DraftChunkApproval + (*ApproveAllDraftChunksRequest)(nil), // 192: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 193: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 194: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 195: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 196: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 197: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 198: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 199: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 200: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 201: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 202: openshell.v1.GetDraftHistoryResponse + (*CreateWorkspaceRequest)(nil), // 203: openshell.v1.CreateWorkspaceRequest + (*CreateWorkspaceResponse)(nil), // 204: openshell.v1.CreateWorkspaceResponse + (*GetWorkspaceRequest)(nil), // 205: openshell.v1.GetWorkspaceRequest + (*GetWorkspaceResponse)(nil), // 206: openshell.v1.GetWorkspaceResponse + (*ListWorkspacesRequest)(nil), // 207: openshell.v1.ListWorkspacesRequest + (*ListWorkspacesResponse)(nil), // 208: openshell.v1.ListWorkspacesResponse + (*DeleteWorkspaceRequest)(nil), // 209: openshell.v1.DeleteWorkspaceRequest + (*DeleteWorkspaceResponse)(nil), // 210: openshell.v1.DeleteWorkspaceResponse + (*WorkspaceMember)(nil), // 211: openshell.v1.WorkspaceMember + (*AddWorkspaceMemberRequest)(nil), // 212: openshell.v1.AddWorkspaceMemberRequest + (*AddWorkspaceMemberResponse)(nil), // 213: openshell.v1.AddWorkspaceMemberResponse + (*RemoveWorkspaceMemberRequest)(nil), // 214: openshell.v1.RemoveWorkspaceMemberRequest + (*RemoveWorkspaceMemberResponse)(nil), // 215: openshell.v1.RemoveWorkspaceMemberResponse + (*ListWorkspaceMembersRequest)(nil), // 216: openshell.v1.ListWorkspaceMembersRequest + (*ListWorkspaceMembersResponse)(nil), // 217: openshell.v1.ListWorkspaceMembersResponse + (*ExtensionServiceCredential)(nil), // 218: openshell.v1.ExtensionServiceCredential + nil, // 219: openshell.v1.SandboxSpec.EnvironmentEntry + nil, // 220: openshell.v1.SandboxTemplate.LabelsEntry + nil, // 221: openshell.v1.SandboxTemplate.AnnotationsEntry + nil, // 222: openshell.v1.SandboxTemplate.EnvironmentEntry + nil, // 223: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + nil, // 224: openshell.v1.PlatformEvent.MetadataEntry + nil, // 225: openshell.v1.CreateSandboxRequest.LabelsEntry + nil, // 226: openshell.v1.CreateSandboxRequest.AnnotationsEntry + nil, // 227: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 228: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 229: openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry + nil, // 230: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + nil, // 231: openshell.v1.ProviderProfile.AnnotationsEntry + nil, // 232: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + nil, // 233: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry + nil, // 234: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + nil, // 235: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + nil, // 236: openshell.v1.UpdateConfigRequest.AnnotationsEntry + nil, // 237: openshell.v1.UpdateConfigResponse.AnnotationsEntry + nil, // 238: openshell.v1.SandboxPolicyRevision.ProvenanceEntry + nil, // 239: openshell.v1.CreateWorkspaceRequest.LabelsEntry + (*datamodelv1.ObjectMeta)(nil), // 240: openshell.datamodel.v1.ObjectMeta + (*sandboxv1.SandboxPolicy)(nil), // 241: openshell.sandbox.v1.SandboxPolicy + (*structpb.Struct)(nil), // 242: google.protobuf.Struct + (*durationpb.Duration)(nil), // 243: google.protobuf.Duration + (*datamodelv1.Provider)(nil), // 244: openshell.datamodel.v1.Provider + (*sandboxv1.NetworkEndpoint)(nil), // 245: openshell.sandbox.v1.NetworkEndpoint + (*sandboxv1.NetworkBinary)(nil), // 246: openshell.sandbox.v1.NetworkBinary + (*sandboxv1.SettingValue)(nil), // 247: openshell.sandbox.v1.SettingValue + (*sandboxv1.NetworkPolicyRule)(nil), // 248: openshell.sandbox.v1.NetworkPolicyRule + (*sandboxv1.L7DenyRule)(nil), // 249: openshell.sandbox.v1.L7DenyRule + (*sandboxv1.L7Rule)(nil), // 250: openshell.sandbox.v1.L7Rule + (*datamodelv1.Workspace)(nil), // 251: openshell.datamodel.v1.Workspace + (*sandboxv1.GetSandboxConfigRequest)(nil), // 252: openshell.sandbox.v1.GetSandboxConfigRequest + (*sandboxv1.GetGatewayConfigRequest)(nil), // 253: openshell.sandbox.v1.GetGatewayConfigRequest + (*sandboxv1.GetSandboxConfigResponse)(nil), // 254: openshell.sandbox.v1.GetSandboxConfigResponse + (*sandboxv1.GetGatewayConfigResponse)(nil), // 255: openshell.sandbox.v1.GetGatewayConfigResponse } var file_openshell_proto_depIdxs = []int32{ - 214, // 0: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential - 5, // 1: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus - 5, // 2: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus - 18, // 3: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo - 19, // 4: openshell.v1.ComputeDriverInfo.capabilities:type_name -> openshell.v1.ComputeDriverCapabilities - 20, // 5: openshell.v1.ComputeDriverCapabilities.resource_capabilities:type_name -> openshell.v1.ResourceCapabilities - 21, // 6: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities - 22, // 7: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities - 23, // 8: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities - 236, // 9: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 25, // 10: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec - 36, // 11: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus - 35, // 12: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance - 215, // 13: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry - 28, // 14: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate - 237, // 15: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 26, // 16: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements - 27, // 17: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements - 216, // 18: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry - 217, // 19: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry - 218, // 20: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry - 238, // 21: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct - 238, // 22: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct - 236, // 23: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 30, // 24: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec - 31, // 25: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig - 238, // 26: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct - 33, // 27: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel - 219, // 28: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - 32, // 29: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources - 27, // 30: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements - 34, // 31: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup - 239, // 32: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration - 37, // 33: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition + 218, // 0: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential + 6, // 1: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus + 6, // 2: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus + 19, // 3: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo + 20, // 4: openshell.v1.ComputeDriverInfo.capabilities:type_name -> openshell.v1.ComputeDriverCapabilities + 21, // 5: openshell.v1.ComputeDriverCapabilities.resource_capabilities:type_name -> openshell.v1.ResourceCapabilities + 22, // 6: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities + 23, // 7: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities + 24, // 8: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities + 240, // 9: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 26, // 10: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec + 37, // 11: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus + 36, // 12: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance + 219, // 13: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry + 29, // 14: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate + 241, // 15: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 27, // 16: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements + 28, // 17: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements + 220, // 18: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry + 221, // 19: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry + 222, // 20: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry + 242, // 21: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 242, // 22: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct + 240, // 23: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 31, // 24: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec + 32, // 25: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig + 242, // 26: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct + 34, // 27: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel + 223, // 28: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + 33, // 29: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources + 28, // 30: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements + 35, // 31: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup + 243, // 32: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 38, // 33: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition 0, // 34: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 220, // 35: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 25, // 36: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 221, // 37: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 222, // 38: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 29, // 39: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 29, // 40: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 29, // 41: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate - 24, // 42: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 24, // 43: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 240, // 44: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 24, // 45: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 24, // 46: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox - 72, // 47: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 236, // 48: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 71, // 49: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint - 223, // 50: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 76, // 51: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout - 77, // 52: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr - 78, // 53: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 167, // 54: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 168, // 55: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget - 80, // 56: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit - 75, // 57: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest - 83, // 58: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 236, // 59: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 24, // 60: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox - 87, // 61: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine - 38, // 62: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent - 88, // 63: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 178, // 64: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 224, // 65: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 240, // 66: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 240, // 67: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 225, // 68: openshell.v1.UpdateProviderRequest.credential_expires_at_ms:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry - 240, // 69: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider - 240, // 70: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 117, // 71: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 100, // 72: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride - 1, // 73: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType - 101, // 74: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken - 106, // 75: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh - 102, // 76: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant - 2, // 77: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 104, // 78: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial - 105, // 79: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput - 2, // 80: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 7, // 81: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 107, // 82: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 2, // 83: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 226, // 84: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 107, // 85: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 107, // 86: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 3, // 87: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory - 103, // 88: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 241, // 89: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 242, // 90: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 108, // 91: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 227, // 92: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 117, // 93: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 117, // 94: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 98, // 95: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 99, // 96: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 117, // 97: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 98, // 98: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 99, // 99: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 117, // 100: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 98, // 101: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 99, // 102: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 130, // 103: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 228, // 104: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 229, // 105: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expires_at_ms:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry - 230, // 106: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 231, // 107: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 237, // 108: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 243, // 109: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 136, // 110: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 232, // 111: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 137, // 112: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 138, // 113: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 139, // 114: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 140, // 115: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 141, // 116: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 142, // 117: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 244, // 118: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 245, // 119: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 246, // 120: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 233, // 121: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 150, // 122: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 150, // 123: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 4, // 124: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 4, // 125: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 237, // 126: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 234, // 127: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 87, // 128: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 87, // 129: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 157, // 130: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 160, // 131: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 171, // 132: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 172, // 133: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 158, // 134: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 159, // 135: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 161, // 136: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 166, // 137: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 172, // 138: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 167, // 139: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 168, // 140: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 169, // 141: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 173, // 142: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 175, // 143: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 244, // 144: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 237, // 145: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 237, // 146: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 174, // 147: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 177, // 148: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 176, // 149: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 177, // 150: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 187, // 151: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval - 244, // 152: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 197, // 153: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 235, // 154: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 247, // 155: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 247, // 156: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 247, // 157: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 236, // 158: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 6, // 159: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 6, // 160: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 207, // 161: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 207, // 162: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 103, // 163: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 131, // 164: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 12, // 165: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 14, // 166: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 16, // 167: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 39, // 168: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 47, // 169: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest - 49, // 170: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 50, // 171: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 40, // 172: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 41, // 173: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 42, // 174: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 43, // 175: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 51, // 176: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 52, // 177: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 53, // 178: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 54, // 179: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 55, // 180: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 56, // 181: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 63, // 182: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 65, // 183: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 66, // 184: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 67, // 185: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 69, // 186: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 73, // 187: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 75, // 188: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 81, // 189: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 82, // 190: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 89, // 191: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 90, // 192: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 91, // 193: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 96, // 194: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 97, // 195: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 120, // 196: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 122, // 197: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 124, // 198: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 92, // 199: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 109, // 200: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 111, // 201: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 113, // 202: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 115, // 203: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 93, // 204: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 127, // 205: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 248, // 206: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 249, // 207: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 135, // 208: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 144, // 209: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 146, // 210: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 148, // 211: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 129, // 212: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 133, // 213: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest - 151, // 214: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 152, // 215: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 155, // 216: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 162, // 217: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest - 164, // 218: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest - 170, // 219: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 85, // 220: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 179, // 221: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 181, // 222: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 183, // 223: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 185, // 224: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 188, // 225: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 190, // 226: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 192, // 227: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 194, // 228: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 196, // 229: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 8, // 230: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 10, // 231: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 199, // 232: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 201, // 233: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 203, // 234: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 205, // 235: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 208, // 236: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 210, // 237: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 212, // 238: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 13, // 239: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 15, // 240: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 17, // 241: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 57, // 242: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 48, // 243: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse - 57, // 244: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 58, // 245: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 44, // 246: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 44, // 247: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 45, // 248: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 46, // 249: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 59, // 250: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 60, // 251: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 61, // 252: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 62, // 253: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 57, // 254: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 57, // 255: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 64, // 256: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 72, // 257: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 72, // 258: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 68, // 259: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 70, // 260: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 74, // 261: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 79, // 262: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 81, // 263: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 79, // 264: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 94, // 265: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 94, // 266: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 95, // 267: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 119, // 268: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 118, // 269: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 121, // 270: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 123, // 271: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 125, // 272: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 94, // 273: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 110, // 274: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 112, // 275: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 114, // 276: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 116, // 277: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 126, // 278: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 128, // 279: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 250, // 280: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 251, // 281: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 143, // 282: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 145, // 283: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 147, // 284: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 149, // 285: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 132, // 286: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 134, // 287: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse - 154, // 288: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 153, // 289: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 156, // 290: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 163, // 291: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse - 165, // 292: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse - 170, // 293: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 86, // 294: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 180, // 295: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 182, // 296: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 184, // 297: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 186, // 298: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 189, // 299: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 191, // 300: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 193, // 301: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 195, // 302: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 198, // 303: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 9, // 304: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 11, // 305: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 200, // 306: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 202, // 307: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 204, // 308: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 206, // 309: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 209, // 310: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 211, // 311: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 213, // 312: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 239, // [239:313] is the sub-list for method output_type - 165, // [165:239] is the sub-list for method input_type - 165, // [165:165] is the sub-list for extension type_name - 165, // [165:165] is the sub-list for extension extendee - 0, // [0:165] is the sub-list for field type_name + 151, // 35: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 224, // 36: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 26, // 37: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec + 225, // 38: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 226, // 39: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 30, // 40: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 30, // 41: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate + 30, // 42: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate + 25, // 43: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox + 25, // 44: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox + 244, // 45: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 25, // 46: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 25, // 47: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox + 73, // 48: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse + 240, // 49: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 72, // 50: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint + 227, // 51: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 77, // 52: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout + 78, // 53: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr + 79, // 54: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit + 171, // 55: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget + 172, // 56: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget + 81, // 57: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit + 76, // 58: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest + 84, // 59: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize + 240, // 60: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 25, // 61: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox + 88, // 62: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine + 39, // 63: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent + 89, // 64: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning + 182, // 65: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 228, // 66: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 244, // 67: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 244, // 68: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 229, // 69: openshell.v1.UpdateProviderRequest.credential_expires_at_ms:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpiresAtMsEntry + 244, // 70: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 244, // 71: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 118, // 72: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile + 101, // 73: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride + 1, // 74: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType + 102, // 75: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken + 107, // 76: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh + 103, // 77: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant + 2, // 78: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 105, // 79: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial + 106, // 80: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput + 2, // 81: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 8, // 82: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction + 108, // 83: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 2, // 84: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy + 230, // 85: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 108, // 86: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 108, // 87: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus + 3, // 88: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory + 104, // 89: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential + 245, // 90: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 246, // 91: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 109, // 92: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery + 231, // 93: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 118, // 94: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile + 118, // 95: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 99, // 96: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 100, // 97: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 118, // 98: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 99, // 99: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem + 100, // 100: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 118, // 101: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile + 99, // 102: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 100, // 103: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 131, // 104: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding + 232, // 105: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 233, // 106: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expires_at_ms:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpiresAtMsEntry + 234, // 107: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 235, // 108: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 241, // 109: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 247, // 110: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 137, // 111: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation + 236, // 112: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 138, // 113: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule + 139, // 114: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint + 140, // 115: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule + 141, // 116: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules + 142, // 117: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules + 143, // 118: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary + 248, // 119: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 249, // 120: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 250, // 121: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 237, // 122: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 154, // 123: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 154, // 124: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 5, // 125: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 4, // 126: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState + 151, // 127: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 5, // 128: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 241, // 129: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 238, // 130: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 88, // 131: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 88, // 132: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 161, // 133: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello + 164, // 134: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat + 175, // 135: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 176, // 136: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 162, // 137: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted + 163, // 138: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected + 165, // 139: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat + 170, // 140: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen + 176, // 141: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 171, // 142: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget + 172, // 143: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget + 173, // 144: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit + 177, // 145: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 179, // 146: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 248, // 147: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 241, // 148: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 241, // 149: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 178, // 150: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 181, // 151: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 180, // 152: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 181, // 153: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 191, // 154: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval + 248, // 155: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 201, // 156: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 239, // 157: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 251, // 158: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 251, // 159: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 251, // 160: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 240, // 161: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 7, // 162: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 7, // 163: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 211, // 164: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 211, // 165: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 104, // 166: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 132, // 167: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 13, // 168: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 15, // 169: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 17, // 170: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 40, // 171: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 48, // 172: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest + 50, // 173: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 51, // 174: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 41, // 175: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 42, // 176: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 43, // 177: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 44, // 178: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 52, // 179: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 53, // 180: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 54, // 181: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 55, // 182: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 56, // 183: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 57, // 184: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 64, // 185: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 66, // 186: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 67, // 187: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 68, // 188: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 70, // 189: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 74, // 190: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 76, // 191: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 82, // 192: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 83, // 193: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 90, // 194: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 91, // 195: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 92, // 196: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 97, // 197: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 98, // 198: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 121, // 199: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 123, // 200: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 125, // 201: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 93, // 202: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 110, // 203: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 112, // 204: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 114, // 205: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 116, // 206: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 94, // 207: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 128, // 208: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 252, // 209: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 253, // 210: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 136, // 211: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 145, // 212: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 147, // 213: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 149, // 214: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 152, // 215: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest + 130, // 216: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 134, // 217: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest + 155, // 218: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 156, // 219: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 159, // 220: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 166, // 221: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest + 168, // 222: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest + 174, // 223: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 86, // 224: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 183, // 225: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 185, // 226: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 187, // 227: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 189, // 228: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 192, // 229: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 194, // 230: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 196, // 231: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 198, // 232: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 200, // 233: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 9, // 234: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 11, // 235: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 203, // 236: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 205, // 237: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 207, // 238: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 209, // 239: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 212, // 240: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 214, // 241: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 216, // 242: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 14, // 243: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 16, // 244: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 18, // 245: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 58, // 246: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 49, // 247: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse + 58, // 248: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 59, // 249: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 45, // 250: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 45, // 251: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 46, // 252: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 47, // 253: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 60, // 254: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 61, // 255: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 62, // 256: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 63, // 257: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 58, // 258: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 58, // 259: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 65, // 260: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 73, // 261: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 73, // 262: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 69, // 263: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 71, // 264: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 75, // 265: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 80, // 266: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 82, // 267: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 80, // 268: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 95, // 269: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 95, // 270: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 96, // 271: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 120, // 272: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 119, // 273: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 122, // 274: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 124, // 275: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 126, // 276: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 95, // 277: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 111, // 278: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 113, // 279: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 115, // 280: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 117, // 281: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 127, // 282: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 129, // 283: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 254, // 284: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 255, // 285: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 144, // 286: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 146, // 287: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 148, // 288: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 150, // 289: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 153, // 290: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse + 133, // 291: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 135, // 292: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse + 158, // 293: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 157, // 294: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 160, // 295: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 167, // 296: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse + 169, // 297: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse + 174, // 298: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 87, // 299: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 184, // 300: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 186, // 301: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 188, // 302: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 190, // 303: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 193, // 304: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 195, // 305: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 197, // 306: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 199, // 307: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 202, // 308: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 10, // 309: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 12, // 310: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 204, // 311: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 206, // 312: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 208, // 313: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 210, // 314: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 213, // 315: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 215, // 316: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 217, // 317: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 243, // [243:318] is the sub-list for method output_type + 168, // [168:243] is the sub-list for method input_type + 168, // [168:168] is the sub-list for extension type_name + 168, // [168:168] is the sub-list for extension extendee + 0, // [0:168] is the sub-list for field type_name } func init() { file_openshell_proto_init() } @@ -16104,24 +16388,24 @@ func file_openshell_proto_init() { (*PolicyMergeOperation_AddAllowRules)(nil), (*PolicyMergeOperation_RemoveBinary)(nil), } - file_openshell_proto_msgTypes[147].OneofWrappers = []any{ + file_openshell_proto_msgTypes[150].OneofWrappers = []any{ (*SupervisorMessage_Hello)(nil), (*SupervisorMessage_Heartbeat)(nil), (*SupervisorMessage_RelayOpenResult)(nil), (*SupervisorMessage_RelayClose)(nil), } - file_openshell_proto_msgTypes[148].OneofWrappers = []any{ + file_openshell_proto_msgTypes[151].OneofWrappers = []any{ (*GatewayMessage_SessionAccepted)(nil), (*GatewayMessage_SessionRejected)(nil), (*GatewayMessage_Heartbeat)(nil), (*GatewayMessage_RelayOpen)(nil), (*GatewayMessage_RelayClose)(nil), } - file_openshell_proto_msgTypes[158].OneofWrappers = []any{ + file_openshell_proto_msgTypes[161].OneofWrappers = []any{ (*RelayOpen_Ssh)(nil), (*RelayOpen_Tcp)(nil), } - file_openshell_proto_msgTypes[162].OneofWrappers = []any{ + file_openshell_proto_msgTypes[165].OneofWrappers = []any{ (*RelayFrame_Init)(nil), (*RelayFrame_Data)(nil), } @@ -16130,8 +16414,8 @@ func file_openshell_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_openshell_proto_rawDesc), len(file_openshell_proto_rawDesc)), - NumEnums: 8, - NumMessages: 228, + NumEnums: 9, + NumMessages: 231, NumExtensions: 0, NumServices: 1, }, diff --git a/sdk/go/proto/openshellv1/openshell_grpc.pb.go b/sdk/go/proto/openshellv1/openshell_grpc.pb.go index d8f3c91008..446c67a41d 100644 --- a/sdk/go/proto/openshellv1/openshell_grpc.pb.go +++ b/sdk/go/proto/openshellv1/openshell_grpc.pb.go @@ -70,6 +70,7 @@ const ( OpenShell_GetSandboxPolicyStatus_FullMethodName = "/openshell.v1.OpenShell/GetSandboxPolicyStatus" OpenShell_ListSandboxPolicies_FullMethodName = "/openshell.v1.OpenShell/ListSandboxPolicies" OpenShell_ReportPolicyStatus_FullMethodName = "/openshell.v1.OpenShell/ReportPolicyStatus" + OpenShell_ReportSandboxConfiguration_FullMethodName = "/openshell.v1.OpenShell/ReportSandboxConfiguration" OpenShell_GetSandboxProviderEnvironment_FullMethodName = "/openshell.v1.OpenShell/GetSandboxProviderEnvironment" OpenShell_ExchangeProviderSubjectToken_FullMethodName = "/openshell.v1.OpenShell/ExchangeProviderSubjectToken" OpenShell_GetSandboxLogs_FullMethodName = "/openshell.v1.OpenShell/GetSandboxLogs" @@ -221,6 +222,8 @@ type OpenShellClient interface { ListSandboxPolicies(ctx context.Context, in *ListSandboxPoliciesRequest, opts ...grpc.CallOption) (*ListSandboxPoliciesResponse, error) // Report policy load result (called by sandbox after reload attempt). ReportPolicyStatus(ctx context.Context, in *ReportPolicyStatusRequest, opts ...grpc.CallOption) (*ReportPolicyStatusResponse, error) + // Register startup and acknowledge an exact validated runtime configuration. + ReportSandboxConfiguration(ctx context.Context, in *ReportSandboxConfigurationRequest, opts ...grpc.CallOption) (*ReportSandboxConfigurationResponse, error) // Get provider environment for a sandbox (called by sandbox supervisor at startup). GetSandboxProviderEnvironment(ctx context.Context, in *GetSandboxProviderEnvironmentRequest, opts ...grpc.CallOption) (*GetSandboxProviderEnvironmentResponse, error) // Exchange a stored provider subject token for an intermediate token scoped @@ -801,6 +804,16 @@ func (c *openShellClient) ReportPolicyStatus(ctx context.Context, in *ReportPoli return out, nil } +func (c *openShellClient) ReportSandboxConfiguration(ctx context.Context, in *ReportSandboxConfigurationRequest, opts ...grpc.CallOption) (*ReportSandboxConfigurationResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReportSandboxConfigurationResponse) + err := c.cc.Invoke(ctx, OpenShell_ReportSandboxConfiguration_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *openShellClient) GetSandboxProviderEnvironment(ctx context.Context, in *GetSandboxProviderEnvironmentRequest, opts ...grpc.CallOption) (*GetSandboxProviderEnvironmentResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetSandboxProviderEnvironmentResponse) @@ -1211,6 +1224,8 @@ type OpenShellServer interface { ListSandboxPolicies(context.Context, *ListSandboxPoliciesRequest) (*ListSandboxPoliciesResponse, error) // Report policy load result (called by sandbox after reload attempt). ReportPolicyStatus(context.Context, *ReportPolicyStatusRequest) (*ReportPolicyStatusResponse, error) + // Register startup and acknowledge an exact validated runtime configuration. + ReportSandboxConfiguration(context.Context, *ReportSandboxConfigurationRequest) (*ReportSandboxConfigurationResponse, error) // Get provider environment for a sandbox (called by sandbox supervisor at startup). GetSandboxProviderEnvironment(context.Context, *GetSandboxProviderEnvironmentRequest) (*GetSandboxProviderEnvironmentResponse, error) // Exchange a stored provider subject token for an intermediate token scoped @@ -1447,6 +1462,9 @@ func (UnimplementedOpenShellServer) ListSandboxPolicies(context.Context, *ListSa func (UnimplementedOpenShellServer) ReportPolicyStatus(context.Context, *ReportPolicyStatusRequest) (*ReportPolicyStatusResponse, error) { return nil, status.Error(codes.Unimplemented, "method ReportPolicyStatus not implemented") } +func (UnimplementedOpenShellServer) ReportSandboxConfiguration(context.Context, *ReportSandboxConfigurationRequest) (*ReportSandboxConfigurationResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ReportSandboxConfiguration not implemented") +} func (UnimplementedOpenShellServer) GetSandboxProviderEnvironment(context.Context, *GetSandboxProviderEnvironmentRequest) (*GetSandboxProviderEnvironmentResponse, error) { return nil, status.Error(codes.Unimplemented, "method GetSandboxProviderEnvironment not implemented") } @@ -2366,6 +2384,24 @@ func _OpenShell_ReportPolicyStatus_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _OpenShell_ReportSandboxConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReportSandboxConfigurationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OpenShellServer).ReportSandboxConfiguration(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OpenShell_ReportSandboxConfiguration_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OpenShellServer).ReportSandboxConfiguration(ctx, req.(*ReportSandboxConfigurationRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _OpenShell_GetSandboxProviderEnvironment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetSandboxProviderEnvironmentRequest) if err := dec(in); err != nil { @@ -2995,6 +3031,10 @@ var OpenShell_ServiceDesc = grpc.ServiceDesc{ MethodName: "ReportPolicyStatus", Handler: _OpenShell_ReportPolicyStatus_Handler, }, + { + MethodName: "ReportSandboxConfiguration", + Handler: _OpenShell_ReportSandboxConfiguration_Handler, + }, { MethodName: "GetSandboxProviderEnvironment", Handler: _OpenShell_GetSandboxProviderEnvironment_Handler, diff --git a/sdk/go/proto/sandboxv1/sandbox.pb.go b/sdk/go/proto/sandboxv1/sandbox.pb.go index 989589002b..7b75a9d2dc 100644 --- a/sdk/go/proto/sandboxv1/sandbox.pb.go +++ b/sdk/go/proto/sandboxv1/sandbox.pb.go @@ -1837,8 +1837,15 @@ type GetSandboxConfigResponse struct { // False also covers older gateways that do not advertise this capability; // supervisors preserve their legacy unauthenticated connection behavior. ExtensionAuthenticationEnabled bool `protobuf:"varint,12,opt,name=extension_authentication_enabled,json=extensionAuthenticationEnabled,proto3" json:"extension_authentication_enabled,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // True only after validating this complete policy/provider composition. + // Missing (older gateway) is deliberately not admission. + ConfigurationAdmitted bool `protobuf:"varint,13,opt,name=configuration_admitted,json=configurationAdmitted,proto3" json:"configuration_admitted,omitempty"` + // Bounded, credential-free admission diagnostic. Empty for admitted policy. + ConfigurationError string `protobuf:"bytes,14,opt,name=configuration_error,json=configurationError,proto3" json:"configuration_error,omitempty"` + // Registration fence for a new supervisor; capture once and retain on retry. + ConfigurationInstanceId string `protobuf:"bytes,15,opt,name=configuration_instance_id,json=configurationInstanceId,proto3" json:"configuration_instance_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetSandboxConfigResponse) Reset() { @@ -1955,6 +1962,27 @@ func (x *GetSandboxConfigResponse) GetExtensionAuthenticationEnabled() bool { return false } +func (x *GetSandboxConfigResponse) GetConfigurationAdmitted() bool { + if x != nil { + return x.ConfigurationAdmitted + } + return false +} + +func (x *GetSandboxConfigResponse) GetConfigurationError() string { + if x != nil { + return x.ConfigurationError + } + return "" +} + +func (x *GetSandboxConfigResponse) GetConfigurationInstanceId() string { + if x != nil { + return x.ConfigurationInstanceId + } + return "" +} + // Connection details for one operator-registered supervisor middleware service. // V1 supports plaintext and server-authenticated TLS gRPC. type SupervisorMiddlewareService struct { @@ -2220,7 +2248,7 @@ const file_sandbox_proto_rawDesc = "" + "\x05value\"\x86\x01\n" + "\x10EffectiveSetting\x128\n" + "\x05value\x18\x01 \x01(\v2\".openshell.sandbox.v1.SettingValueR\x05value\x128\n" + - "\x05scope\x18\x02 \x01(\x0e2\".openshell.sandbox.v1.SettingScopeR\x05scope\"\xd1\x06\n" + + "\x05scope\x18\x02 \x01(\x0e2\".openshell.sandbox.v1.SettingScopeR\x05scope\"\xf5\a\n" + "\x18GetSandboxConfigResponse\x12;\n" + "\x06policy\x18\x01 \x01(\v2#.openshell.sandbox.v1.SandboxPolicyR\x06policy\x12\x18\n" + "\aversion\x18\x02 \x01(\rR\aversion\x12\x1f\n" + @@ -2235,7 +2263,10 @@ const file_sandbox_proto_rawDesc = "" + "\tworkspace\x18\n" + " \x01(\tR\tworkspace\x12C\n" + "\x1epolicy_validation_failure_mode\x18\v \x01(\tR\x1bpolicyValidationFailureMode\x12H\n" + - " extension_authentication_enabled\x18\f \x01(\bR\x1eextensionAuthenticationEnabled\x1ac\n" + + " extension_authentication_enabled\x18\f \x01(\bR\x1eextensionAuthenticationEnabled\x125\n" + + "\x16configuration_admitted\x18\r \x01(\bR\x15configurationAdmitted\x12/\n" + + "\x13configuration_error\x18\x0e \x01(\tR\x12configurationError\x12:\n" + + "\x19configuration_instance_id\x18\x0f \x01(\tR\x17configurationInstanceId\x1ac\n" + "\rSettingsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12<\n" + "\x05value\x18\x02 \x01(\v2&.openshell.sandbox.v1.EffectiveSettingR\x05value:\x028\x01\"\x99\x02\n" + diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index 7d47b18065..cf5318a309 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -141,6 +141,16 @@ Inspect sandbox OCSF configuration and finding events for the validation rationale, configured and effective modes, active generation, and the explicit `previous_policy_active` state. +A `ConfigurationInvalid` readiness condition means startup admission rejected +the image/effective policy or provider configuration. The supervisor remains +alive while the workload stays unstarted. Inspect `openshell sandbox get` and +repair the desired configuration with a complete policy replacement or provider +change; do not treat a healthy container as proof that the workload is ready. +See [policy validation and repair](https://docs.nvidia.com/openshell/latest/sandboxes/policies.md). +In sidecar topology, the process supervisor sends image-policy discovery over +the authenticated control socket and waits for an accepted bootstrap. A process +container waiting there can be expected during repair, rather than a crash loop. + ### Step 4: Check Docker-Backed Gateways ```bash diff --git a/skills/generate-sandbox-policy/SKILL.md b/skills/generate-sandbox-policy/SKILL.md index 73c0863df7..02d91b4dcf 100644 --- a/skills/generate-sandbox-policy/SKILL.md +++ b/skills/generate-sandbox-policy/SKILL.md @@ -173,6 +173,12 @@ When middleware is requested, also read the published [supervisor middleware gui For enforcement concepts and the shipped baseline, read [sandbox policies](https://docs.nvidia.com/openshell/latest/sandboxes/policies.md) and the [default policy reference](https://docs.nvidia.com/openshell/latest/reference/default-policy.md). The default policy is baked into the community base image (`ghcr.io/nvidia/openshell-community/sandboxes/base:latest`). +Validate the intended provider combination as well as the authored policy. +An image endpoint can become credentialed after provider composition and block +startup with `ConfigurationInvalid`. Repair the complete policy or provider +selection using the published policy workflow; do not add +`allow_uninspected_credentials` merely to bypass a startup error. + ## Step 4: Choose Policy Shape Follow this decision tree based on the detail tier and user intent: diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index ed64496190..484a3f5f85 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -430,7 +430,14 @@ the operation that removes retained state. This is the most important multi-step workflow. It enables a tight feedback cycle where sandbox policy is refined based on observed activity. -**Key concept**: Policies have static fields (immutable after creation: `filesystem_policy`, `landlock`, `process`) and two dynamic fields: `network_policies` and `network_middlewares`. Both dynamic fields can be updated without recreating the sandbox when the selected compute driver supports live policy updates. Drivers without the standard supervisor fetch revisions through the sandbox configuration API and report whether they loaded them. +**Key concept**: Policies have static fields (immutable after activation: `filesystem_policy`, `landlock`, `process`) and two dynamic fields: `network_policies` and `network_middlewares`. Both dynamic fields can be updated without recreating the sandbox when the selected compute driver supports live policy updates. Drivers without the standard supervisor fetch revisions through the sandbox configuration API and report whether they loaded them. + +If startup reports `ConfigurationInvalid`, inspect `openshell sandbox get` and +repair the complete policy or provider set through the gateway. The workload +has not started, so static fields can also be replaced during this repair. +After validation succeeds, the supervisor completes startup. Follow the +published [policy repair guidance](https://docs.nvidia.com/openshell/latest/sandboxes/policies.md) +and confirm current replacement/detach syntax with installed CLI help. An endpoint with omitted `protocol` retains explicit-proxy behavior. Explicit `protocol: tcp` requests policy DNS and transparent TCP and currently requires