diff --git a/crates/openshell-cli/src/commands/provider.rs b/crates/openshell-cli/src/commands/provider.rs index fca1d16f3f..05ec158e42 100644 --- a/crates/openshell-cli/src/commands/provider.rs +++ b/crates/openshell-cli/src/commands/provider.rs @@ -2566,7 +2566,8 @@ fn format_provider_profile_details(profile: &ProviderProfile) -> String { let access = match network_access_preset_to_str(endpoint.access) { Some("") if !endpoint.rules.is_empty() => "custom rules".to_string(), Some("") if is_mcp && allow_all_known_mcp_methods == Some(true) => { - "all known MCP methods (subject to tool and deny rules)".to_string() + "core MCP methods for the selected revision (subject to tool and deny rules)" + .to_string() } Some("") => "not specified".to_string(), Some(access) => access.to_string(), @@ -2601,9 +2602,26 @@ fn format_provider_profile_details(profile: &ProviderProfile) -> String { || "not specified".to_string(), |options| options.versions.join(", "), ); - let _ = writeln!(rendered, " Allow all known MCP methods: {methods}"); + let _ = writeln!( + rendered, + " Allow core MCP methods for the selected revision: {methods}" + ); + if allow_all_known_mcp_methods == Some(true) { + rendered + .push_str(" Tool restrictions still apply; deny rules take precedence.\n"); + rendered.push_str( + " Without tool-specific allow rules, all tool names are allowed.\n", + ); + } + rendered.push_str(" Extension methods: require an exact allow rule\n"); let _ = writeln!(rendered, " Strict MCP tool names: {strict_names}"); let _ = writeln!(rendered, " MCP versions (declared): {versions}"); + rendered.push_str( + " Revision selection: MCP-Protocol-Version header; 2025-03-26 when absent\n", + ); + rendered.push_str( + " Legacy initialize requests negotiate their revision in the body.\n", + ); } if !endpoint.allowed_ips.is_empty() { let _ = writeln!( @@ -3143,11 +3161,39 @@ binaries: [/usr/bin/curl] let rendered = format_provider_profile_details(&proto); assert!( rendered - .contains("Access: all known MCP methods (subject to tool and deny rules)\n") + .contains("Access: core MCP methods for the selected revision (subject to tool and deny rules)\n") ); - assert!(rendered.contains("Allow all known MCP methods: true\n")); + assert!(rendered.contains("Allow core MCP methods for the selected revision: true\n")); + assert!( + rendered.contains("Tool restrictions still apply; deny rules take precedence.") + ); + assert!( + rendered.contains("Without tool-specific allow rules, all tool names are allowed.") + ); + assert!(rendered.contains("Extension methods: require an exact allow rule\n")); assert!(rendered.contains("Strict MCP tool names: true (default)\n")); assert!(rendered.contains("MCP versions (declared): 2025-11-25\n")); + assert!(rendered.contains( + "Revision selection: MCP-Protocol-Version header; 2025-03-26 when absent\n" + )); + assert!( + rendered + .contains("Legacy initialize requests negotiate their revision in the body.\n") + ); + + for output in ["json", "yaml"] { + let structured = format_provider_profile_description(&proto, output) + .expect("structured description renders"); + let roundtrip = if output == "json" { + parse_profile_json(&structured) + } else { + parse_profile_yaml(&structured) + } + .expect("structured description is a full profile document"); + assert_eq!(roundtrip, ProviderTypeProfile::from_proto(&proto)); + assert!(structured.contains("allow_all_known_mcp_methods")); + assert!(!structured.contains("Allow core MCP methods")); + } // Explicit rules remain relevant when the method default is enabled, // and independent tool-name validation must not disappear from view. @@ -3163,7 +3209,13 @@ binaries: [/usr/bin/curl] options.strict_tool_names = Some(false); let rendered = format_provider_profile_details(&proto); assert!(rendered.contains("Access: custom rules\n Rules: 1 allow, 0 deny\n")); - assert!(rendered.contains(&format!("Allow all known MCP methods: {allow_all}\n"))); + assert!(rendered.contains(&format!( + "Allow core MCP methods for the selected revision: {allow_all}\n" + ))); + assert_eq!( + rendered.contains("Tool restrictions still apply"), + allow_all + ); assert!(rendered.contains("Strict MCP tool names: false\n")); } } diff --git a/crates/openshell-core/src/grpc_client.rs b/crates/openshell-core/src/grpc_client.rs index f49466b0e2..9808bd16e0 100644 --- a/crates/openshell-core/src/grpc_client.rs +++ b/crates/openshell-core/src/grpc_client.rs @@ -1116,6 +1116,7 @@ fn provider_environment_result( .collect::>>()?; Ok(ProviderEnvironmentResult { environment: inner.environment, + files: inner.files, provider_env_revision: inner.provider_env_revision, provider_attachment_epoch: inner.provider_attachment_epoch, policy_hash: inner.policy_hash, @@ -1380,6 +1381,7 @@ mod settings_poll_tests { /// Credential material and the authority snapshot that produced its bindings. pub struct ProviderEnvironmentResult { pub environment: HashMap, + pub files: HashMap, pub provider_env_revision: u64, /// Attachment identity captured with the delivered credential records. pub provider_attachment_epoch: String, diff --git a/crates/openshell-core/src/provider_credentials.rs b/crates/openshell-core/src/provider_credentials.rs index fee82e0d3f..6988d1f4be 100644 --- a/crates/openshell-core/src/provider_credentials.rs +++ b/crates/openshell-core/src/provider_credentials.rs @@ -36,11 +36,14 @@ pub struct ChildEnvironmentSnapshot { pub revision: u64, /// Prepared environment used by future workload processes. pub environment: HashMap, + /// Complete desired set of non-secret files for this installation. + pub files: HashMap, } #[derive(Debug)] struct ProviderCredentialStateInner { current: Arc, + files: HashMap, generations: VecDeque>, current_resolver: Option>, combined_resolver: Option>, @@ -117,6 +120,7 @@ impl ProviderCredentialState { Self { inner: Arc::new(RwLock::new(ProviderCredentialStateInner { current: snapshot.clone(), + files: HashMap::new(), generations, current_resolver, combined_resolver, @@ -172,6 +176,7 @@ impl ProviderCredentialState { Ok(Self { inner: Arc::new(RwLock::new(ProviderCredentialStateInner { current: snapshot.clone(), + files: HashMap::new(), generations, current_resolver, combined_resolver, @@ -205,6 +210,7 @@ impl ProviderCredentialState { Self { inner: Arc::new(RwLock::new(ProviderCredentialStateInner { current: snapshot.clone(), + files: HashMap::new(), generations: VecDeque::new(), current_resolver: None, combined_resolver: None, @@ -410,22 +416,19 @@ impl ProviderCredentialState { inner.current = Arc::new(env); } - /// Return `child_env` with GCP static config vars resolved to real values. + /// Return `child_env` with explicitly non-secret config vars resolved. /// - /// The credential pipeline placeholderizes ALL env values, but GCP SDKs - /// and coding agents read certain vars (project ID, region, metadata host) - /// at process startup before any HTTP request flows through the proxy. - /// This method overrides those vars with resolved real values while - /// keeping secret credentials (like `GCP_ACCESS_TOKEN`) as placeholders. + /// The credential pipeline placeholderizes all env values. Workloads need + /// non-secret configuration, including provider file paths, at process + /// startup before any HTTP request flows through the proxy. Credential + /// values remain placeholders. /// /// Three layers of env var injection: /// 1. **Synthetic vars** (`GCE_METADATA_IP`, `METADATA_SERVER_DETECTION`) /// — sandbox-internal config not from user /// input, inserted directly here with real values. - /// 2. **`google_cloud::STATIC_CONFIG_KEYS`** — user-provided non-secret config - /// (project ID, region, SA email) that was placeholderized by - /// `ProviderPlugin::inject_env` → `SecretResolver`; un-placeholderized - /// here so SDKs can read them at startup. + /// 2. **Classified non-secret keys** — user-provided config and provider + /// file paths un-placeholderized so workloads can read them at startup. /// 3. Everything else stays as placeholders for proxy-time resolution. pub fn child_env_with_gcp_resolved(&self) -> HashMap { let inner = self @@ -463,9 +466,18 @@ impl ProviderCredentialState { installation_id: inner.current.installation_id.clone(), revision, environment, + files: inner.files.clone(), }) } + /// Attach the complete file set to a prepared provider snapshot. + pub fn set_managed_files(&self, files: HashMap) { + self.inner + .write() + .expect("provider credential state poisoned") + .files = files; + } + fn resolve_child_env_snapshot( inner: &ProviderCredentialStateInner, ) -> (u64, HashMap) { @@ -477,11 +489,7 @@ impl ProviderCredentialState { && inner .non_secret_environment_keys .contains("GCE_METADATA_HOST"); - let has_gcp_config = google_cloud::STATIC_CONFIG_KEYS - .iter() - .any(|key| env.contains_key(*key) && inner.non_secret_environment_keys.contains(*key)); - - if !has_gcp_metadata && !has_gcp_config { + if !has_gcp_metadata && inner.non_secret_environment_keys.is_empty() { return (inner.current.revision, env); } @@ -506,16 +514,15 @@ impl ProviderCredentialState { ); } - // Un-placeholderize non-secret config vars so SDKs can read them - // at process startup before any HTTP flows through the proxy. + // Only explicitly classified non-secret values may be unwrapped. if let Some(ref resolver) = inner.combined_resolver { - for key in google_cloud::STATIC_CONFIG_KEYS - .iter() - .filter(|key| inner.non_secret_environment_keys.contains(**key)) - { + for key in &inner.non_secret_environment_keys { + if !env.contains_key(key) || (has_gcp_metadata && key == "GCE_METADATA_HOST") { + continue; + } let placeholder = crate::secrets::placeholder_for_env_key(key); if let Some(value) = resolver.resolve_placeholder(&placeholder) { - env.insert(key.to_string(), value.to_string()); + env.insert(key.clone(), value.to_string()); } } } @@ -738,7 +745,7 @@ impl ProviderCredentialState { 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 (snapshot, generations, current_resolver, bindings, non_secret_keys, files) = { let candidate = prepared .inner .read() @@ -749,6 +756,7 @@ impl ProviderCredentialState { candidate.current_resolver.clone(), candidate.static_credential_bindings.clone(), candidate.non_secret_environment_keys.clone(), + candidate.files.clone(), ) }; let mut inner = self @@ -781,6 +789,7 @@ impl ProviderCredentialState { ); inner.static_credential_bindings = bindings; inner.non_secret_environment_keys = non_secret_keys; + inner.files = files; inner.body_inventory_available = true; inner .known_body_keys @@ -2138,6 +2147,33 @@ mod tests { assert!(!env.contains_key("CLAUDE_CODE_USE_VERTEX")); } + #[test] + fn child_env_resolves_provider_file_path_but_keeps_credentials_placeholderized() { + let path = "/run/openshell/providers/acme/client.toml"; + let state = ProviderCredentialState::from_bound_environment( + 1, + HashMap::from([ + ("ACME_CONFIG_FILE".to_string(), path.to_string()), + ("ACME_TOKEN".to_string(), "secret-token".to_string()), + ]), + HashMap::new(), + HashMap::new(), + HashMap::from([( + "ACME_TOKEN".to_string(), + binding("api.acme.example", 443, "/**"), + )]), + vec!["ACME_CONFIG_FILE".to_string()], + ) + .expect("classified provider environment"); + + let env = state.child_env_with_gcp_resolved(); + assert_eq!(env.get("ACME_CONFIG_FILE").map(String::as_str), Some(path)); + assert_eq!( + env.get("ACME_TOKEN").map(String::as_str), + Some("openshell:resolve:env:v1_ACME_TOKEN") + ); + } + #[test] fn child_env_with_gcp_resolved_overrides_gcp_static_vars() { let state = ProviderCredentialState::from_bound_environment( diff --git a/crates/openshell-isolation-interface/src/linux/seccomp_notify.rs b/crates/openshell-isolation-interface/src/linux/seccomp_notify.rs index c9bbb0fafa..a87dc080d5 100644 --- a/crates/openshell-isolation-interface/src/linux/seccomp_notify.rs +++ b/crates/openshell-isolation-interface/src/linux/seccomp_notify.rs @@ -432,7 +432,8 @@ pub fn install_listener(syscalls: &[i64]) -> io::Result { /// reconfigure an INET endpoint. Connected `send()`/null-destination /// `sendto()` retains the audited cBPF fast path. pub fn install_workload_listener() -> io::Result { - install_listener(&[ + #[allow(unused_mut)] // SYS_open is unavailable on some architectures. + let mut syscalls = vec![ libc::SYS_socket, libc::SYS_connect, libc::SYS_bind, @@ -447,7 +448,12 @@ pub fn install_workload_listener() -> io::Result { libc::SYS_kill, libc::SYS_tkill, libc::SYS_rt_sigqueueinfo, - ]) + libc::SYS_openat, + libc::SYS_openat2, + ]; + #[cfg(target_arch = "x86_64")] + syscalls.push(libc::SYS_open); + install_listener(&syscalls) } /// Run a no-capability conformance probe. diff --git a/crates/openshell-isolation-interface/src/linux/workload_launcher.rs b/crates/openshell-isolation-interface/src/linux/workload_launcher.rs index 8602d9df80..71fc7f336e 100644 --- a/crates/openshell-isolation-interface/src/linux/workload_launcher.rs +++ b/crates/openshell-isolation-interface/src/linux/workload_launcher.rs @@ -137,7 +137,27 @@ mod tests { }) .expect("launcher result") .expect("spawn child"); - let notification = listener.receive().expect("receive child socket"); + let notification = loop { + let notification = listener.receive().expect("receive child syscall"); + let syscall = i64::from(notification.syscall); + if syscall == libc::SYS_socket { + break notification; + } + if syscall == libc::SYS_openat || syscall == libc::SYS_openat2 { + listener + .respond_continue(notification.id) + .expect("continue ordinary file open"); + continue; + } + #[cfg(target_arch = "x86_64")] + if syscall == libc::SYS_open { + listener + .respond_continue(notification.id) + .expect("continue ordinary file open"); + continue; + } + panic!("unexpected child syscall: {syscall}"); + }; assert_eq!(i64::from(notification.syscall), libc::SYS_socket); assert!( std::path::Path::new(&format!("/proc/{}/task/{}", child.id(), notification.tid)) diff --git a/crates/openshell-providers/src/discovery.rs b/crates/openshell-providers/src/discovery.rs index 00e8da1890..2249adaf4a 100644 --- a/crates/openshell-providers/src/discovery.rs +++ b/crates/openshell-providers/src/discovery.rs @@ -92,6 +92,7 @@ mod tests { fn profile() -> ProviderTypeProfile { ProviderTypeProfile { + files: Vec::new(), id: "custom".to_string(), resource_version: 0, annotations: std::collections::HashMap::new(), diff --git a/crates/openshell-providers/src/profiles.rs b/crates/openshell-providers/src/profiles.rs index 36cf9a5844..74d7e44234 100644 --- a/crates/openshell-providers/src/profiles.rs +++ b/crates/openshell-providers/src/profiles.rs @@ -13,7 +13,7 @@ use openshell_core::proto::{ ProviderCredentialRefreshMaterial, ProviderCredentialRefreshOutput, ProviderCredentialRefreshStrategy, ProviderCredentialTokenGrantSubjectToken, ProviderCredentialTokenGrantType, ProviderProfile, ProviderProfileCategory, - ProviderProfileCredential, ProviderProfileDiscovery, + ProviderProfileCredential, ProviderProfileDiscovery, ProviderProfileFile, }; use openshell_core::secrets::uses_reserved_revision_namespace; use openshell_policy::{ @@ -697,6 +697,10 @@ pub struct ProviderTypeProfile { pub category: ProviderProfileCategory, #[serde(default)] pub credentials: Vec, + /// EXPERIMENTAL: Non-secret files served to sandbox workloads on demand. + /// This API and its behavior may change or be removed. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub files: Vec, #[serde(default)] pub endpoints: Vec, #[serde(default)] @@ -711,6 +715,81 @@ pub struct ProviderTypeProfile { pub scope: String, } +/// EXPERIMENTAL: A non-secret provider file template. This API may change or be removed. +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +pub struct ProviderFileProfile { + pub path: String, + pub content: String, + #[serde(default, skip_serializing_if = "String::is_empty")] + pub env_var: String, +} + +impl ProviderFileProfile { + fn validate_template(&self) -> Result<(), String> { + let mut remaining = self.content.as_str(); + while let Some(start) = remaining.find("{{") { + if remaining[..start].contains("}}") { + return Err("unexpected provider file placeholder close".to_string()); + } + let after = &remaining[start + 2..]; + let end = after + .find("}}") + .ok_or("unclosed provider file placeholder")?; + let key = after[..end] + .strip_prefix("config.") + .ok_or("provider files may reference only config.KEY")?; + if !valid_file_config_key(key) { + return Err("invalid provider file config key".to_string()); + } + remaining = &after[end + 2..]; + } + if remaining.contains("}}") { + return Err("unexpected provider file placeholder close".to_string()); + } + Ok(()) + } + + /// Render only explicitly referenced non-secret provider config values. + pub fn render(&self, config: &HashMap) -> Result { + self.validate_template()?; + let mut remaining = self.content.as_str(); + let mut rendered = String::new(); + while let Some(start) = remaining.find("{{") { + rendered.push_str(&remaining[..start]); + let after = &remaining[start + 2..]; + let end = after + .find("}}") + .ok_or("unclosed provider file placeholder")?; + let key = after[..end] + .strip_prefix("config.") + .ok_or("provider files may reference only config.KEY")?; + if !valid_file_config_key(key) { + return Err("invalid provider file config key".to_string()); + } + let value = config + .get(key) + .ok_or_else(|| format!("missing provider config key '{key}'"))?; + rendered.push_str(value); + remaining = &after[end + 2..]; + if rendered.len() > 65_536 { + return Err("rendered provider file exceeds 64 KiB".to_string()); + } + } + rendered.push_str(remaining); + if rendered.len() > 65_536 { + return Err("rendered provider file exceeds 64 KiB".to_string()); + } + Ok(rendered) + } +} + +fn valid_file_config_key(key: &str) -> bool { + !key.is_empty() + && key + .bytes() + .all(|c| c.is_ascii_alphanumeric() || c == b'_' || c == b'-') +} + // Provider profile import/export is expected to be lossless for the network // policy fields exposed by the protobuf API. Do not collapse these DTOs into a // narrower shape; direct gRPC imports and CLI YAML imports must preserve the @@ -745,6 +824,15 @@ impl ProviderTypeProfile { token_grant: credential.token_grant.as_ref().map(token_grant_from_proto), }) .collect(), + files: profile + .files + .iter() + .map(|file| ProviderFileProfile { + path: file.path.clone(), + content: file.content.clone(), + env_var: file.env_var.clone(), + }) + .collect(), endpoints: profile.endpoints.iter().map(endpoint_from_proto).collect(), binaries: profile.binaries.iter().map(binary_from_proto).collect(), inference_capable: profile.inference_capable, @@ -911,6 +999,15 @@ impl ProviderTypeProfile { token_grant: credential.token_grant.as_ref().map(token_grant_to_proto), }) .collect(), + files: self + .files + .iter() + .map(|file| ProviderProfileFile { + path: file.path.clone(), + content: file.content.clone(), + env_var: file.env_var.clone(), + }) + .collect(), endpoints: self.endpoints.iter().map(endpoint_to_proto).collect(), binaries: self.binaries.iter().map(binary_to_proto).collect(), inference_capable: self.inference_capable, @@ -2037,8 +2134,80 @@ pub fn validate_profile_set( )); } + if profile.files.len() > 16 { + diagnostics.push(ProfileValidationDiagnostic::error( + source, + profile_id, + "files", + "at most 16 provider files are allowed", + )); + } + let mut file_paths = HashSet::new(); + let mut file_env_vars = HashSet::new(); + for file in &profile.files { + if file.path.is_empty() + || file.path == "." + || file.path == ".." + || !file + .path + .bytes() + .all(|c| c.is_ascii_alphanumeric() || matches!(c, b'.' | b'_' | b'-')) + || !file_paths.insert(file.path.as_str()) + { + diagnostics.push(ProfileValidationDiagnostic::error( + source, + profile_id, + "files.path", + "file path must be a unique, safe file name", + )); + } + if file.content.len() > 65_536 { + diagnostics.push(ProfileValidationDiagnostic::error( + source, + profile_id, + "files.content", + "file template exceeds 64 KiB", + )); + } + if let Err(error) = file.validate_template() { + diagnostics.push(ProfileValidationDiagnostic::error( + source, + profile_id, + "files.content", + error, + )); + } + if !file.env_var.is_empty() + && (!file + .env_var + .starts_with(|c: char| c.is_ascii_alphabetic() || c == '_') + || !file + .env_var + .bytes() + .all(|c| c.is_ascii_alphanumeric() || c == b'_') + || !file_env_vars.insert(file.env_var.as_str())) + { + diagnostics.push(ProfileValidationDiagnostic::error( + source, + profile_id, + "files.env_var", + "file environment key must be unique and use letters, digits, or underscores", + )); + } + } + let mut credential_names = HashSet::new(); for credential in &profile.credentials { + for env_var in &credential.env_vars { + if file_env_vars.contains(env_var.as_str()) { + diagnostics.push(ProfileValidationDiagnostic::error( + source, + profile_id, + "files.env_var", + format!("file environment key '{env_var}' conflicts with a credential"), + )); + } + } let credential_name = credential.name.trim(); if credential_name.is_empty() { diagnostics.push(ProfileValidationDiagnostic::error( @@ -5738,6 +5907,7 @@ binaries: ["", /usr/bin/broken] ( "space.yaml".to_string(), ProviderTypeProfile { + files: Vec::new(), id: " alex-api ".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -5756,6 +5926,7 @@ binaries: ["", /usr/bin/broken] ( "underscore.yaml".to_string(), ProviderTypeProfile { + files: Vec::new(), id: "alex_api".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -5774,6 +5945,7 @@ binaries: ["", /usr/bin/broken] ( "case.yaml".to_string(), ProviderTypeProfile { + files: Vec::new(), id: "Alex-API".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -7795,4 +7967,29 @@ binaries: "expected mcp-options-on-non-mcp rejection: {diagnostics:?}" ); } + + #[test] + fn managed_file_example_validates_and_renders_only_config_fields() { + let yaml = include_str!("../../../examples/provider-managed-files/acme-config.yaml"); + let profile = parse_profile_yaml(yaml).expect("example profile parses"); + let diagnostics = + validate_profile_set(&[("acme-config.yaml".to_string(), profile.clone())]); + assert!(diagnostics.is_empty(), "{diagnostics:?}"); + let rendered = profile.files[0] + .render(&HashMap::from([ + ( + "endpoint".to_string(), + "https://api.acme.example".to_string(), + ), + ("project".to_string(), "production".to_string()), + ])) + .expect("render provider config"); + assert!(rendered.contains("project = \"production\"")); + assert!(!rendered.contains("{{")); + + let mut invalid = profile; + invalid.files[0].content = "token = \"{{credential.API_KEY}}\"".to_string(); + let diagnostics = validate_profile_set(&[("invalid.yaml".to_string(), invalid)]); + assert!(diagnostics.iter().any(|d| d.field == "files.content")); + } } diff --git a/crates/openshell-sandbox-backend/src/boundary_protocol.rs b/crates/openshell-sandbox-backend/src/boundary_protocol.rs index 4ba77f1adb..6c6c66e76c 100644 --- a/crates/openshell-sandbox-backend/src/boundary_protocol.rs +++ b/crates/openshell-sandbox-backend/src/boundary_protocol.rs @@ -684,6 +684,8 @@ pub enum Request { resource_claims: std::collections::BTreeMap, }, Confirm, + /// Verify file-open mediation before sending a file-bearing snapshot. + ProbeProviderFiles, StartAgent { sandbox_id: String, spec: AgentSpecWire, @@ -692,12 +694,16 @@ pub enum Request { ca_bundle: Option, provider_env_revision: u64, provider_env: std::collections::HashMap, + #[serde(default)] + provider_files: std::collections::HashMap, }, UpdateProviderEnvironment { /// Ordered publication within this authenticated boundary session. generation: u64, revision: u64, provider_env: std::collections::HashMap, + #[serde(default)] + provider_files: std::collections::HashMap, }, AttachProcess { process_id: String, @@ -772,6 +778,7 @@ impl fmt::Debug for Request { .field("resource_claims", resource_claims) .finish(), Self::Confirm => formatter.write_str("Confirm"), + Self::ProbeProviderFiles => formatter.write_str("ProbeProviderFiles"), Self::StartAgent { sandbox_id, spec, @@ -780,6 +787,7 @@ impl fmt::Debug for Request { ca_bundle, provider_env_revision, provider_env, + provider_files, } => formatter .debug_struct("StartAgent") .field("sandbox_id", sandbox_id) @@ -788,6 +796,7 @@ impl fmt::Debug for Request { .field("ca_cert_present", &ca_cert.is_some()) .field("ca_bundle_present", &ca_bundle.is_some()) .field("provider_env_revision", provider_env_revision) + .field("provider_file_count", &provider_files.len()) .field( "provider_env_keys", &provider_env.keys().collect::>(), @@ -797,10 +806,12 @@ impl fmt::Debug for Request { generation, revision, provider_env, + provider_files, } => formatter .debug_struct("UpdateProviderEnvironment") .field("generation", generation) .field("revision", revision) + .field("provider_file_count", &provider_files.len()) .field( "provider_env_keys", &provider_env.keys().collect::>(), @@ -872,6 +883,7 @@ pub enum Response { /// before workload launch. confirmation: Box, }, + ProviderFilesSupported, Started { process_id: String, provider_env_revision: u64, @@ -1563,6 +1575,7 @@ mod tests { request_id: "4e94636d-54f8-4d85-8e4e-58954fb5af0a".to_string(), payload_digest: String::new(), request: Request::StartAgent { + provider_files: std::collections::HashMap::new(), sandbox_id: "sandbox-1".to_string(), spec: AgentSpecWire { program: "/bin/true".to_string(), @@ -1612,6 +1625,7 @@ mod tests { second.insert("A".to_string(), "1".to_string()); second.insert("B".to_string(), "2".to_string()); let build = |provider_env| Request::UpdateProviderEnvironment { + provider_files: std::collections::HashMap::new(), generation: 1, revision: 2, provider_env, @@ -1622,7 +1636,7 @@ mod tests { let expected = format!( "{:x}", Sha256::digest( - br#"{"generation":1,"operation":"update_provider_environment","provider_env":{"A":"1","B":"2"},"revision":2}"# + br#"{"generation":1,"operation":"update_provider_environment","provider_env":{"A":"1","B":"2"},"provider_files":{},"revision":2}"# ) ); for provider_env in [first, second] { @@ -1659,11 +1673,34 @@ mod tests { envelope.validate_payload_digest(), Err(FrameError::PayloadDigestMismatch) )); + + let mut request = build(std::collections::HashMap::new()); + let Request::UpdateProviderEnvironment { provider_files, .. } = &mut request else { + unreachable!(); + }; + provider_files.insert( + "/run/openshell/providers/acme/client.toml".to_string(), + "version = 1".to_string(), + ); + let mut envelope = RequestEnvelope::new(request).expect("file-bearing request envelope"); + let Request::UpdateProviderEnvironment { provider_files, .. } = &mut envelope.request + else { + unreachable!(); + }; + provider_files.insert( + "/run/openshell/providers/acme/client.toml".to_string(), + "version = 2".to_string(), + ); + assert!(matches!( + envelope.validate_payload_digest(), + Err(FrameError::PayloadDigestMismatch) + )); } #[test] fn start_agent_with_large_ca_bundle_fits_in_frame_limit() { let request = RequestEnvelope::new(Request::StartAgent { + provider_files: std::collections::HashMap::new(), sandbox_id: "sandbox-1".to_string(), spec: AgentSpecWire { program: "/bin/true".to_string(), diff --git a/crates/openshell-sandbox-backend/src/runtime.rs b/crates/openshell-sandbox-backend/src/runtime.rs index f073c6d7ce..641d50cd24 100644 --- a/crates/openshell-sandbox-backend/src/runtime.rs +++ b/crates/openshell-sandbox-backend/src/runtime.rs @@ -396,12 +396,26 @@ impl ReadyBoundary for RemoteReady { } else { (None, None) }; - let (provider_env_revision, provider_env) = self + let provider_snapshot = self .provider_credentials - .child_env_snapshot_with_gcp_resolved() + .child_environment_snapshot() .map_err(|error| { BackendError::Process(format!("snapshot provider environment: {error}")) })?; + if !provider_snapshot.files.is_empty() { + let response = self + .client + .call_idempotent(Request::ProbeProviderFiles) + .await + .map_err(|error| { + BackendError::Process(format!("provider file capability probe failed: {error}")) + })?; + if !matches!(response, Response::ProviderFilesSupported) { + return Err(BackendError::Process( + "sandbox boundary does not support provider files".to_string(), + )); + } + } let response = self .client .call_idempotent(Request::StartAgent { @@ -410,8 +424,9 @@ impl ReadyBoundary for RemoteReady { policy: Box::new(SandboxPolicyWire::from(self.policy)), ca_cert, ca_bundle, - provider_env_revision, - provider_env, + provider_env_revision: provider_snapshot.revision, + provider_env: provider_snapshot.environment, + provider_files: provider_snapshot.files, }) .await?; let Response::Started { @@ -621,6 +636,22 @@ impl RemoteExec { .map_err(|error| { BackendError::Process(format!("snapshot provider environment: {error}")) })?; + if !snapshot.files.is_empty() { + let response = self + .client + .call_idempotent(Request::ProbeProviderFiles) + .await + .map_err(|error| { + BackendError::Process(format!( + "provider file capability probe failed: {error}" + )) + })?; + if !matches!(response, Response::ProviderFilesSupported) { + return Err(BackendError::Process( + "sandbox boundary does not support provider files".to_string(), + )); + } + } *generation = generation.checked_add(1).ok_or_else(|| { BackendError::Process("provider environment publication exhausted".to_string()) })?; @@ -631,6 +662,7 @@ impl RemoteExec { generation: requested_generation, revision: snapshot.revision, provider_env: snapshot.environment, + provider_files: snapshot.files, }) .await?; let Response::ProviderEnvironmentUpdated { @@ -2286,6 +2318,7 @@ mod tests { Request::Confirm => Response::Confirmed { confirmation: Box::new(confirmation), }, + Request::ProbeProviderFiles => Response::ProviderFilesSupported, Request::OpenMediation if mediation_ready => Response::MediationReady, Request::OpenMediation => Response::Error { kind: crate::boundary_protocol::BoundaryErrorKind::Denied, @@ -3452,6 +3485,7 @@ mod tests { assert!(matches!( client .exchange(Request::StartAgent { + provider_files: HashMap::new(), sandbox_id: context.sandbox_id, spec: AgentSpecWire::from(context.agent), policy: Box::new(SandboxPolicyWire::from(context.policy)), @@ -3511,6 +3545,7 @@ mod tests { tokio::time::timeout( Duration::from_secs(2), client.exchange(Request::StartAgent { + provider_files: HashMap::new(), sandbox_id: context.sandbox_id, spec: AgentSpecWire::from(context.agent), policy: Box::new(SandboxPolicyWire::from(context.policy)), diff --git a/crates/openshell-sandbox/src/boundary_exec.rs b/crates/openshell-sandbox/src/boundary_exec.rs index 8d0a3326ed..da35294c06 100644 --- a/crates/openshell-sandbox/src/boundary_exec.rs +++ b/crates/openshell-sandbox/src/boundary_exec.rs @@ -688,7 +688,17 @@ mod tests { .expect("start test workload launcher"); std::thread::spawn(move || { while let Ok(notification) = listener.receive() { - let _ = listener.respond_errno(notification.id, libc::EPERM); + let syscall = i64::from(notification.syscall); + if syscall == libc::SYS_openat || syscall == libc::SYS_openat2 { + let _ = listener.respond_continue(notification.id); + } else { + #[cfg(target_arch = "x86_64")] + if syscall == libc::SYS_open { + let _ = listener.respond_continue(notification.id); + continue; + } + let _ = listener.respond_errno(notification.id, libc::EPERM); + } } }); LocalBoundaryExec::new( diff --git a/crates/openshell-sandbox/src/boundary_server.rs b/crates/openshell-sandbox/src/boundary_server.rs index 7a2a73f731..6e7dd23ca3 100644 --- a/crates/openshell-sandbox/src/boundary_server.rs +++ b/crates/openshell-sandbox/src/boundary_server.rs @@ -1420,6 +1420,7 @@ mod linux { ca_bundle: Option, provider_env_revision: u64, provider_env: std::collections::HashMap, + provider_files: std::collections::HashMap, } impl StartedAgent { @@ -1945,6 +1946,10 @@ mod linux { } } Request::Confirm => self.confirm(), + Request::ProbeProviderFiles => self.network_broker.confirm_healthy().map_or_else( + |error| guest_error(BoundaryErrorKind::Unavailable, error.to_string()), + |()| Response::ProviderFilesSupported, + ), Request::StartAgent { sandbox_id, spec, @@ -1953,6 +1958,7 @@ mod linux { ca_bundle, provider_env_revision, provider_env, + provider_files, } => self.start_agent( sandbox_id, spec, @@ -1961,12 +1967,19 @@ mod linux { ca_bundle, provider_env_revision, provider_env, + provider_files, ), Request::UpdateProviderEnvironment { generation, revision, provider_env, - } => self.update_provider_environment(generation, revision, provider_env), + provider_files, + } => self.update_provider_environment( + generation, + revision, + provider_env, + provider_files, + ), Request::Wait { process_id } => self.wait(&process_id), Request::Signal { process_id, signal } => self.signal(&process_id, signal), Request::Terminate { process_id } => self.terminate(&process_id), @@ -2425,6 +2438,7 @@ mod linux { ca_bundle: Option, provider_env_revision: u64, provider_env: std::collections::HashMap, + provider_files: std::collections::HashMap, ) -> Response { let spec = match resolve_agent_spec(spec) { Ok(spec) => spec, @@ -2439,6 +2453,7 @@ mod linux { ca_bundle: ca_bundle.clone(), provider_env_revision, provider_env: provider_env.clone(), + provider_files: provider_files.clone(), }; if let RuntimeState::Running(process) = &*state { return if lock(&self.started_agent) @@ -2498,6 +2513,13 @@ mod linux { provider_env, ca_file_paths, }; + let provider_file_count = provider_files.len(); + if let Err(error) = self.network_broker.provider_files().replace(provider_files) { + return guest_error( + BoundaryErrorKind::Process, + format!("install provider files: {error}"), + ); + } let process = match ManagedProcess::spawn( &self.process_runtime, &self.workload_launcher, @@ -2510,6 +2532,15 @@ mod linux { let process_id = process.process_id(); *lock(&self.started_agent) = Some(requested); *state = RuntimeState::Running(process); + openshell_ocsf::ocsf_emit!( + openshell_ocsf::ConfigStateChangeBuilder::new(openshell_ocsf::ctx::ctx()) + .severity(openshell_ocsf::SeverityId::Informational) + .status(openshell_ocsf::StatusId::Success) + .message(format!( + "Provider file snapshot loaded [file_count:{provider_file_count}]" + )) + .build() + ); Response::Started { process_id, provider_env_revision, @@ -2522,6 +2553,7 @@ mod linux { generation: u64, revision: u64, provider_env: std::collections::HashMap, + provider_files: std::collections::HashMap, ) -> Response { let process = { let state = lock(&self.state); @@ -2548,6 +2580,13 @@ mod linux { applied: false, }; } + if let Err(error) = crate::provider_files::ProviderFiles::validate(&provider_files) { + return guest_error( + BoundaryErrorKind::Invalid, + format!("invalid provider files: {error}"), + ); + } + let requested_revision = revision; let revision = match process .provider_credentials .compare_and_install_child_env_snapshot(current.revision, revision, provider_env) @@ -2555,7 +2594,29 @@ mod linux { Ok(revision) => revision, Err(error) => return guest_error(BoundaryErrorKind::Process, error.to_string()), }; + if revision != requested_revision { + return guest_error( + BoundaryErrorKind::Invalid, + "provider environment changed during update", + ); + } + let provider_file_count = provider_files.len(); + if let Err(error) = self.network_broker.provider_files().replace(provider_files) { + return guest_error( + BoundaryErrorKind::Process, + format!("install provider files: {error}"), + ); + } *installed_generation = generation; + openshell_ocsf::ocsf_emit!( + openshell_ocsf::ConfigStateChangeBuilder::new(openshell_ocsf::ctx::ctx()) + .severity(openshell_ocsf::SeverityId::Informational) + .status(openshell_ocsf::StatusId::Success) + .message(format!( + "Provider file snapshot updated [file_count:{provider_file_count}]" + )) + .build() + ); Response::ProviderEnvironmentUpdated { revision, generation, @@ -4871,6 +4932,7 @@ mod linux { None, 0, std::collections::HashMap::new(), + std::collections::HashMap::new(), ) }; let Response::Started { @@ -4883,6 +4945,7 @@ mod linux { }; let update = RequestEnvelope::new(Request::UpdateProviderEnvironment { + provider_files: std::collections::HashMap::new(), generation: 1, revision: 7, provider_env: std::collections::HashMap::from([( @@ -4968,6 +5031,7 @@ mod linux { None, 0, std::collections::HashMap::new(), + std::collections::HashMap::new(), ), Response::Error { kind, .. } if kind == BoundaryErrorKind::Denied )); @@ -4976,7 +5040,12 @@ mod linux { // fingerprint. Distinct publications must still replace the map, // while a delayed older clear must never undo the repair. assert_eq!( - boundary.update_provider_environment(2, 7, std::collections::HashMap::default()), + boundary.update_provider_environment( + 2, + 7, + std::collections::HashMap::default(), + std::collections::HashMap::new() + ), Response::ProviderEnvironmentUpdated { revision: 7, generation: 2, @@ -4990,7 +5059,8 @@ mod linux { std::collections::HashMap::from([( "REPLAY_TEST".to_string(), "reconnected".to_string() - ),]) + ),]), + std::collections::HashMap::new(), ), Response::ProviderEnvironmentUpdated { revision: 7, @@ -4999,7 +5069,12 @@ mod linux { } ); assert_eq!( - boundary.update_provider_environment(2, 7, std::collections::HashMap::default()), + boundary.update_provider_environment( + 2, + 7, + std::collections::HashMap::default(), + std::collections::HashMap::new() + ), Response::ProviderEnvironmentUpdated { revision: 7, generation: 3, @@ -5165,6 +5240,7 @@ mod linux { *lock(&boundary.state) = RuntimeState::Running(process.clone()); *lock(&boundary.attached_policy) = Some(wire_policy.clone()); *lock(&boundary.started_agent) = Some(StartedAgent { + provider_files: std::collections::HashMap::new(), sandbox_id: "sandbox-retained".to_string(), spec: agent_spec.clone(), policy: wire_policy.clone(), @@ -5190,6 +5266,7 @@ mod linux { None, 0, std::collections::HashMap::new(), + std::collections::HashMap::new(), ), Response::Started { process_id: process.process_id(), @@ -5206,6 +5283,7 @@ mod linux { "ROTATED_TOKEN".to_string(), "refreshed".to_string(), )]), + std::collections::HashMap::new(), ), Response::ProviderEnvironmentUpdated { revision: 2, @@ -5221,6 +5299,7 @@ mod linux { "ROTATED_TOKEN".to_string(), "stale".to_string(), )]), + std::collections::HashMap::new(), ), Response::ProviderEnvironmentUpdated { revision: 2, @@ -5229,7 +5308,12 @@ mod linux { } ); assert_eq!( - boundary.update_provider_environment(2, 1, std::collections::HashMap::new()), + boundary.update_provider_environment( + 2, + 1, + std::collections::HashMap::new(), + std::collections::HashMap::new() + ), Response::ProviderEnvironmentUpdated { revision: 1, generation: 2, @@ -5245,6 +5329,7 @@ mod linux { "ROTATED_TOKEN".to_string(), "out-of-order".to_string(), )]), + std::collections::HashMap::new(), ), Response::ProviderEnvironmentUpdated { revision: 1, @@ -5254,7 +5339,12 @@ mod linux { "a stale publication must not overwrite current state" ); assert_eq!( - boundary.update_provider_environment(1, 1, std::collections::HashMap::new()), + boundary.update_provider_environment( + 1, + 1, + std::collections::HashMap::new(), + std::collections::HashMap::new() + ), Response::ProviderEnvironmentUpdated { revision: 1, generation: 2, @@ -5280,6 +5370,7 @@ mod linux { "ROTATED_TOKEN".to_string(), "replacement-control-snapshot".to_string(), )]), + std::collections::HashMap::new(), ), Response::Started { process_id: process.process_id(), diff --git a/crates/openshell-sandbox/src/lib.rs b/crates/openshell-sandbox/src/lib.rs index 957b55c664..5ba996181a 100644 --- a/crates/openshell-sandbox/src/lib.rs +++ b/crates/openshell-sandbox/src/lib.rs @@ -22,6 +22,8 @@ mod network_broker; pub mod perf; #[cfg(unix)] pub mod process; +#[cfg(target_os = "linux")] +mod provider_files; mod pty; pub mod sandbox; #[cfg(target_os = "linux")] diff --git a/crates/openshell-sandbox/src/network_broker.rs b/crates/openshell-sandbox/src/network_broker.rs index 5fda6d1c99..56c857ce9c 100644 --- a/crates/openshell-sandbox/src/network_broker.rs +++ b/crates/openshell-sandbox/src/network_broker.rs @@ -190,6 +190,7 @@ fn register_dns_socket( #[derive(Clone)] struct NotificationQueues { + provider_files: crate::provider_files::ProviderFiles, protected_control_port: Option, accept_registrar: crate::accept_interrupt::AcceptRegistrar, identity_resolver: ProcfsIdentityResolver, @@ -204,6 +205,7 @@ struct NotificationQueues { /// Live broker handle retained by the sandbox boundary. #[derive(Clone)] pub struct NetworkBroker { + provider_files: crate::provider_files::ProviderFiles, _accept_monitor: Arc, pending: Arc>>, pending_dns: Arc>>, @@ -260,7 +262,9 @@ impl NetworkBroker { let dns_address = dns_relay.address; let retained_socket_capacity = retained_socket_capacity()?; let registry = Arc::new(Mutex::new(SocketRegistry::new(1, SOCKET_CAPACITY)?)); + let provider_files = crate::provider_files::ProviderFiles::default(); let queues = NotificationQueues { + provider_files: provider_files.clone(), protected_control_port, accept_registrar: accept_monitor.registrar(), identity_resolver: ProcfsIdentityResolver::for_pid_namespace(), @@ -311,6 +315,7 @@ impl NetworkBroker { }) .map_err(|error| io::Error::other(format!("start network broker: {error}")))?; Ok(Self { + provider_files, _accept_monitor: accept_monitor, pending: Arc::new(tokio::sync::Mutex::new(pending_rx)), pending_dns: Arc::new(tokio::sync::Mutex::new(pending_dns_rx)), @@ -352,6 +357,10 @@ impl NetworkBroker { )) } } + + pub(crate) fn provider_files(&self) -> &crate::provider_files::ProviderFiles { + &self.provider_files + } } fn start_dns_relay( @@ -528,6 +537,13 @@ fn dispatch_notification( queues: NotificationQueues, ) -> io::Result<()> { let syscall = i64::from(notification.syscall); + if syscall == libc::SYS_openat || syscall == libc::SYS_openat2 { + return queues.provider_files.handle_open(&listener, notification); + } + #[cfg(target_arch = "x86_64")] + if syscall == libc::SYS_open { + return queues.provider_files.handle_open(&listener, notification); + } if matches!(syscall, libc::SYS_kill | libc::SYS_rt_sigqueueinfo) { return openshell_isolation_interface::linux::process_signal::mediate_process_signal( &listener, @@ -1827,6 +1843,87 @@ fn error_to_errno(error: &io::Error) -> i32 { mod tests { use super::*; use openshell_isolation_interface::linux::seccomp_notify::ListenerMode; + + #[test] + fn provider_files_are_opened_on_demand_and_replaced() { + let (launcher, listener) = openshell_isolation_interface::linux::workload_launcher::start() + .expect("start workload launcher"); + let broker = NetworkBroker::start_for_test(listener).expect("start broker"); + let path = "/run/openshell/providers/acme/client.toml".to_string(); + broker + .provider_files() + .replace(HashMap::from([(path.clone(), "version = 1\n".into())])) + .unwrap(); + let first = launcher + .execute({ + let path = path.clone(); + move || std::fs::read_to_string(path) + }) + .unwrap() + .expect("first open"); + assert_eq!(first, "version = 1\n"); + let mut old_descriptor = launcher + .execute({ + let path = path.clone(); + move || std::fs::File::open(path) + }) + .unwrap() + .expect("open old version"); + let denied_write = launcher + .execute({ + let path = path.clone(); + move || std::fs::OpenOptions::new().write(true).open(path) + }) + .unwrap() + .expect_err("provider file is read only"); + assert_eq!(denied_write.raw_os_error(), Some(libc::EACCES)); + broker + .provider_files() + .replace(HashMap::from([(path.clone(), "version = 2\n".into())])) + .unwrap(); + let mut old_content = String::new(); + io::Read::read_to_string(&mut old_descriptor, &mut old_content).unwrap(); + assert_eq!(old_content, "version = 1\n"); + let second = launcher + .execute({ + let path = path.clone(); + move || std::fs::read_to_string(path) + }) + .unwrap() + .expect("second open"); + assert_eq!(second, "version = 2\n"); + let via_openat2 = launcher + .execute({ + let path = path.clone(); + move || -> io::Result { + let path = std::ffi::CString::new(path).unwrap(); + let how = [libc::O_CLOEXEC as u64, 0, 0]; + let fd = unsafe { + libc::syscall( + libc::SYS_openat2, + libc::AT_FDCWD, + path.as_ptr(), + how.as_ptr(), + 24_usize, + ) + }; + if fd < 0 { + return Err(io::Error::last_os_error()); + } + let mut file = unsafe { + std::fs::File::from_raw_fd(i32::try_from(fd).expect("open fd fits")) + }; + let mut content = String::new(); + io::Read::read_to_string(&mut file, &mut content)?; + Ok(content) + } + }) + .unwrap(); + assert_eq!(via_openat2.unwrap(), "version = 2\n"); + broker.provider_files().replace(HashMap::new()).unwrap(); + let detached = launcher.execute(move || std::fs::read(path)).unwrap(); + assert_eq!(detached.unwrap_err().raw_os_error(), Some(libc::ENOENT)); + } use std::io::{Read as _, Write as _}; use std::os::unix::net::{UnixListener, UnixStream}; diff --git a/crates/openshell-sandbox/src/provider_files.rs b/crates/openshell-sandbox/src/provider_files.rs new file mode 100644 index 0000000000..5efd4270f2 --- /dev/null +++ b/crates/openshell-sandbox/src/provider_files.rs @@ -0,0 +1,259 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Read-only provider files served on demand through seccomp FD injection. + +#![allow(unsafe_code)] + +use std::collections::HashMap; +use std::ffi::CString; +use std::fs::File; +use std::io::{self, Seek as _, SeekFrom, Write as _}; +use std::os::fd::{AsRawFd as _, FromRawFd as _}; +use std::sync::{Arc, RwLock}; + +use openshell_isolation_interface::linux::seccomp_notify::{Notification, NotificationListener}; +use openshell_isolation_interface::linux::task_memory; + +const PREFIX: &str = "/run/openshell/providers/"; +const MAX_FILE_BYTES: usize = 65_536; +const MAX_TOTAL_BYTES: usize = 262_144; +const MAX_PATH_BYTES: usize = 4_096; + +type Snapshot = HashMap>; + +/// A complete provider-file generation. Open handlers clone the selected +/// content before dropping the lock, so updates never block on a child open. +#[derive(Clone, Default)] +pub struct ProviderFiles { + current: Arc>>, +} + +impl ProviderFiles { + pub(crate) fn validate(desired: &HashMap) -> io::Result<()> { + if desired.len() > 64 || desired.values().map(String::len).sum::() > MAX_TOTAL_BYTES + { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "provider file set is too large", + )); + } + for (path, content) in desired { + validate_path(path)?; + if content.len() > MAX_FILE_BYTES { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "provider file exceeds 64 KiB", + )); + } + } + Ok(()) + } + + pub(crate) fn replace(&self, desired: HashMap) -> io::Result<()> { + Self::validate(&desired)?; + let next = desired + .into_iter() + .map(|(path, content)| (path, Arc::<[u8]>::from(content.into_bytes()))) + .collect(); + *self + .current + .write() + .unwrap_or_else(std::sync::PoisonError::into_inner) = Arc::new(next); + Ok(()) + } + + pub(crate) fn handle_open( + &self, + listener: &NotificationListener, + notification: Notification, + ) -> io::Result<()> { + let syscall = i64::from(notification.syscall); + let path_address = if syscall == libc::SYS_openat || syscall == libc::SYS_openat2 { + notification.args[1] + } else { + notification.args[0] + }; + // Every workload open reaches the listener. Copy only the reserved + // prefix for ordinary paths; full path reads are rare. + let mut prefix = [0_u8; PREFIX.len()]; + if task_memory::read_exact(notification.tid, path_address, &mut prefix).is_err() + || prefix != PREFIX.as_bytes() + { + return listener.respond_continue(notification.id); + } + // A failed or non-absolute lookup is left to the kernel. In particular, + // this preserves its normal EFAULT result for an invalid path pointer. + let Ok(path) = read_path(notification.tid, path_address) else { + return listener.respond_continue(notification.id); + }; + if !path.starts_with(PREFIX) { + return listener.respond_continue(notification.id); + } + let content = self + .current + .read() + .unwrap_or_else(std::sync::PoisonError::into_inner) + .get(&path) + .cloned(); + let Some(content) = content else { + return listener.respond_errno(notification.id, libc::ENOENT); + }; + let flags = match open_flags(¬ification) { + Ok(flags) => flags, + Err(error) => { + return listener.respond_errno( + notification.id, + error.raw_os_error().unwrap_or(libc::EINVAL), + ); + } + }; + if flags & libc::O_ACCMODE != libc::O_RDONLY + || flags + & (libc::O_CREAT | libc::O_EXCL | libc::O_TRUNC | libc::O_TMPFILE | libc::O_APPEND) + != 0 + { + return listener.respond_errno(notification.id, libc::EACCES); + } + if flags & (libc::O_DIRECTORY | libc::O_PATH | libc::O_DIRECT) != 0 { + return listener.respond_errno(notification.id, libc::EINVAL); + } + let file = sealed_memfd(&content)?; + listener.add_fd_and_send( + notification.id, + file.as_raw_fd(), + flags & libc::O_CLOEXEC != 0, + )?; + Ok(()) + } +} + +fn safe_component(value: &str) -> bool { + !value.is_empty() + && value != "." + && value != ".." + && value + .bytes() + .all(|c| c.is_ascii_alphanumeric() || matches!(c, b'.' | b'_' | b'-')) +} + +fn validate_path(path: &str) -> io::Result<()> { + let suffix = path.strip_prefix(PREFIX).ok_or_else(|| { + io::Error::new( + io::ErrorKind::InvalidInput, + "provider file escapes managed root", + ) + })?; + let (provider, name) = suffix.split_once('/').ok_or_else(|| { + io::Error::new( + io::ErrorKind::InvalidInput, + "provider file must name a provider and file", + ) + })?; + if !safe_component(provider) || !safe_component(name) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "invalid provider file path", + )); + } + Ok(()) +} + +fn read_path(tid: u32, mut address: u64) -> io::Result { + if address == 0 { + return Err(io::Error::from_raw_os_error(libc::EFAULT)); + } + let mut path = Vec::with_capacity(128); + while path.len() < MAX_PATH_BYTES { + // VMAs are page aligned. Never read across a page boundary before + // finding NUL, because the following page may be unmapped. + let page_remaining = 4096 - usize::try_from(address & 4095).expect("page offset fits"); + let length = page_remaining.min(MAX_PATH_BYTES - path.len()); + let mut chunk = vec![0; length]; + task_memory::read_exact(tid, address, &mut chunk)?; + if let Some(end) = chunk.iter().position(|byte| *byte == 0) { + path.extend_from_slice(&chunk[..end]); + return String::from_utf8(path).map_err(|_| io::Error::from_raw_os_error(libc::EINVAL)); + } + path.extend_from_slice(&chunk); + address += length as u64; + } + Err(io::Error::from_raw_os_error(libc::ENAMETOOLONG)) +} + +fn open_flags(notification: &Notification) -> io::Result { + let syscall = i64::from(notification.syscall); + if syscall == libc::SYS_openat2 { + if notification.args[3] < 24 { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + } + let mut how = [0_u8; 24]; + task_memory::read_exact(notification.tid, notification.args[2], &mut how)?; + let flags = u64::from_ne_bytes(how[0..8].try_into().expect("eight bytes")); + let mode = u64::from_ne_bytes(how[8..16].try_into().expect("eight bytes")); + let resolve = u64::from_ne_bytes(how[16..24].try_into().expect("eight bytes")); + if mode != 0 || resolve != 0 { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + } + i32::try_from(flags).map_err(|_| io::Error::from_raw_os_error(libc::EINVAL)) + } else if syscall == libc::SYS_openat { + i32::try_from(notification.args[2]).map_err(|_| io::Error::from_raw_os_error(libc::EINVAL)) + } else { + i32::try_from(notification.args[1]).map_err(|_| io::Error::from_raw_os_error(libc::EINVAL)) + } +} + +fn sealed_memfd(content: &[u8]) -> io::Result { + let name = CString::new("openshell-provider").expect("static name"); + let fd = + unsafe { libc::memfd_create(name.as_ptr(), libc::MFD_CLOEXEC | libc::MFD_ALLOW_SEALING) }; + if fd < 0 { + return Err(io::Error::last_os_error()); + } + let mut file = unsafe { File::from_raw_fd(fd) }; + file.write_all(content)?; + file.seek(SeekFrom::Start(0))?; + let seals = libc::F_SEAL_SEAL | libc::F_SEAL_WRITE | libc::F_SEAL_GROW | libc::F_SEAL_SHRINK; + if unsafe { libc::fcntl(file.as_raw_fd(), libc::F_ADD_SEALS, seals) } < 0 { + return Err(io::Error::last_os_error()); + } + // memfd_create returns O_RDWR. Reopen the sealed object through our own + // procfs descriptor so the child receives an actual O_RDONLY description. + File::open(format!("/proc/self/fd/{}", file.as_raw_fd())) +} + +#[cfg(test)] +mod tests { + use super::{ProviderFiles, sealed_memfd}; + use std::collections::HashMap; + use std::io::Read as _; + use std::os::fd::AsRawFd as _; + + #[test] + fn paths_cannot_escape_the_managed_tree() { + let valid = "/run/openshell/providers/acme/client.toml"; + assert!(ProviderFiles::validate(&HashMap::from([(valid.into(), "ok".into())])).is_ok()); + for path in [ + "/etc/passwd", + "/run/openshell/providers/acme/../passwd", + "/run/openshell/providers/acme/sub/file", + "/run/openshell/providers/../client.toml", + ] { + assert!( + ProviderFiles::validate(&HashMap::from([(path.into(), "ok".into())])).is_err(), + "{path}" + ); + } + } + + #[test] + fn memfd_is_read_only_and_positioned_at_start() { + let mut file = sealed_memfd(b"version = 1\n").unwrap(); + let flags = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_GETFL) }; + assert_eq!(flags & libc::O_ACCMODE, libc::O_RDONLY); + let mut read = String::new(); + file.read_to_string(&mut read).unwrap(); + assert_eq!(read, "version = 1\n"); + assert!(std::io::Write::write_all(&mut file, b"changed").is_err()); + } +} diff --git a/crates/openshell-server/src/grpc/policy.rs b/crates/openshell-server/src/grpc/policy.rs index 9bb1ea5860..2d92a64ddc 100644 --- a/crates/openshell-server/src/grpc/policy.rs +++ b/crates/openshell-server/src/grpc/policy.rs @@ -3346,10 +3346,10 @@ pub(super) async fn handle_get_sandbox_provider_environment( .await .map_err(|e| Status::internal(format!("fetch sandbox failed: {e}")))? .ok_or_else(|| Status::not_found("sandbox not found"))?; - Ok(Response::new( + let environment = load_sandbox_provider_environment(state, &sandbox, supports_static_credential_bindings) - .await?, - )) + .await?; + Ok(Response::new(environment)) } /// Materialize a privileged provider snapshot after the caller has authorized @@ -3476,6 +3476,7 @@ pub(super) async fn load_sandbox_provider_environment( .collect(); Ok(GetSandboxProviderEnvironmentResponse { environment: provider_environment.environment, + files: provider_environment.files, provider_env_revision, credential_expiration_times, dynamic_credentials: provider_environment.dynamic_credentials, @@ -11271,6 +11272,7 @@ mod tests { deletion_time: None, }), profile: Some(openshell_core::proto::ProviderProfile { + files: Vec::new(), id: "generic".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -11364,6 +11366,7 @@ mod tests { deletion_time: None, }), profile: Some(openshell_core::proto::ProviderProfile { + files: Vec::new(), id: "custom-api".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -11435,6 +11438,7 @@ mod tests { deletion_time: None, }), profile: Some(openshell_core::proto::ProviderProfile { + files: Vec::new(), id: "custom-api".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -12592,6 +12596,7 @@ mod tests { deletion_time: None, }), profile: Some(ProviderProfile { + files: Vec::new(), id: "custom-policy".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -12815,6 +12820,89 @@ mod tests { assert_eq!(v2_env.get("GITHUB_TOKEN"), Some(&"ghp-test".to_string())); } + #[tokio::test] + async fn provider_files_do_not_block_legacy_provider_environment_requests() { + use openshell_core::proto::{ + GetSandboxProviderEnvironmentRequest, ProviderProfile, ProviderProfileCategory, + ProviderProfileFile, + }; + + let state = test_server_state().await; + state + .store + .put_message(&StoredProviderProfile { + metadata: Some(openshell_core::proto::datamodel::v1::ObjectMeta { + id: "profile-config-only".to_string(), + name: "config-only".to_string(), + workspace: "default".to_string(), + ..Default::default() + }), + profile: Some(ProviderProfile { + id: "config-only".to_string(), + display_name: "Config only".to_string(), + category: ProviderProfileCategory::Other as i32, + files: vec![ProviderProfileFile { + path: "client.toml".to_string(), + content: "endpoint = '{{config.endpoint}}'".to_string(), + env_var: "CLIENT_CONFIG_FILE".to_string(), + }], + ..Default::default() + }), + }) + .await + .unwrap(); + + let mut file_provider = test_provider("work-config", "config-only"); + file_provider.credentials.clear(); + file_provider + .config + .insert("endpoint".to_string(), "https://config.example".to_string()); + state.store.put_message(&file_provider).await.unwrap(); + state + .store + .put_message(&test_provider("work-github", "github")) + .await + .unwrap(); + state + .store + .put_message(&test_sandbox( + "sb-files-and-credentials", + "files-and-credentials", + test_policy_with_rule("sandbox_only", "sandbox.example.com"), + vec!["work-config".to_string(), "work-github".to_string()], + )) + .await + .unwrap(); + + // An older supervisor sends this request without a provider-file + // capability field and ignores the additive files response field. + let response = handle_get_sandbox_provider_environment( + &state, + with_user(Request::new(GetSandboxProviderEnvironmentRequest { + sandbox_id: "sb-files-and-credentials".to_string(), + supports_static_credential_bindings: true, + })), + ) + .await + .unwrap() + .into_inner(); + + assert_eq!( + response.environment.get("GITHUB_TOKEN"), + Some(&"ghp-test".to_string()) + ); + assert_eq!( + response.environment.get("CLIENT_CONFIG_FILE"), + Some(&"/run/openshell/providers/work-config/client.toml".to_string()) + ); + assert_eq!( + response + .files + .get("/run/openshell/providers/work-config/client.toml"), + Some(&"endpoint = 'https://config.example'".to_string()) + ); + } + #[tokio::test] async fn provider_readiness_snapshot_uses_baseline_static_binding_contract() { let state = test_server_state().await; @@ -13712,6 +13800,7 @@ mod tests { deletion_time: None, }), profile: Some(ProviderProfile { + files: Vec::new(), id: "custom-token".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -14042,6 +14131,7 @@ mod tests { profiles: vec![ProviderProfileImportItem { source: "custom-api.yaml".to_string(), profile: Some(ProviderProfile { + files: Vec::new(), id: "custom-api".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -17715,6 +17805,7 @@ mod tests { deletion_time: None, }), profile: Some(ProviderProfile { + files: Vec::new(), id: "custom-api".to_string(), resource_version: 0, annotations: HashMap::new(), diff --git a/crates/openshell-server/src/grpc/provider.rs b/crates/openshell-server/src/grpc/provider.rs index 2141ecb4c2..cc2395fe7d 100644 --- a/crates/openshell-server/src/grpc/provider.rs +++ b/crates/openshell-server/src/grpc/provider.rs @@ -74,6 +74,7 @@ pub(super) struct ProviderEnvironment { pub dynamic_credentials: HashMap, pub static_credential_bindings: HashMap, pub static_credential_keys: HashSet, + pub files: HashMap, } /// Immutable provider records used to build one provider-environment response. @@ -1127,6 +1128,8 @@ pub(super) async fn resolve_provider_environment_from_records_with_policy_bindin let mut expires = HashMap::new(); let mut static_credential_bindings = HashMap::new(); let mut static_credential_keys = HashSet::new(); + let mut files = HashMap::new(); + let mut file_env_keys = HashSet::new(); let mut readiness_reason = openshell_core::proto::ProviderReadinessReason::Unspecified; let now_ms = crate::persistence::current_time_ms(); validate_provider_environment_records_unique_at(store, catalog, records, now_ms).await?; @@ -1369,11 +1372,59 @@ pub(super) async fn resolve_provider_environment_from_records_with_policy_bindin // or populates its own keys. Cross-provider credential/config // collisions have already been rejected by the validation above. inject_provider_plugin_environment(catalog, provider, ®istry, &mut provider_env); + if let Some(profile) = profile.as_ref() { + if !profile.files.is_empty() + && (name.is_empty() + || !name + .bytes() + .all(|c| c.is_ascii_alphanumeric() || c == b'-' || c == b'_')) + { + return Err(Status::failed_precondition( + "provider name cannot be used in a managed file path", + )); + } + for file in &profile.files { + let path = format!("/run/openshell/providers/{name}/{}", file.path); + let content = file.render(&provider.config).map_err(|error| { + Status::failed_precondition(format!( + "provider '{name}' file '{}': {error}", + file.path + )) + })?; + if files.insert(path.clone(), content).is_some() { + return Err(Status::failed_precondition( + "duplicate provider file destination", + )); + } + if !file.env_var.is_empty() { + if provider_env.insert(file.env_var.clone(), path).is_some() + || env.contains_key(&file.env_var) + { + return Err(Status::failed_precondition(format!( + "provider file environment key '{}' conflicts with another provider output", + file.env_var + ))); + } + file_env_keys.insert(file.env_var.clone()); + } + } + } for (key, value) in provider_env { + if env.contains_key(&key) && file_env_keys.contains(&key) { + return Err(Status::failed_precondition(format!( + "provider file environment key '{key}' conflicts with another provider output" + ))); + } env.entry(key).or_insert(value); } } + if files.len() > 64 || files.values().map(String::len).sum::() > 262_144 { + return Err(Status::failed_precondition( + "provider file set exceeds sandbox limits", + )); + } + Ok(ProviderEnvironment { readiness_reason, environment: env, @@ -1381,6 +1432,7 @@ pub(super) async fn resolve_provider_environment_from_records_with_policy_bindin dynamic_credentials: resolve_dynamic_credentials_from_records(catalog, records), static_credential_bindings, static_credential_keys, + files, }) } @@ -3334,6 +3386,26 @@ fn validate_provider_credentials( provider: &Provider, pending_credentials: &HashMap, ) -> Result<(), Status> { + if !profile.files.is_empty() { + let name = provider.object_name(); + if name.is_empty() + || !name + .bytes() + .all(|c| c.is_ascii_alphanumeric() || c == b'-' || c == b'_') + { + return Err(Status::invalid_argument( + "provider name cannot be used in a managed file path", + )); + } + for file in &profile.files { + file.render(&provider.config).map_err(|error| { + Status::invalid_argument(format!( + "provider file '{}' cannot be rendered: {error}", + file.path + )) + })?; + } + } let declared_keys = profile .credentials .iter() @@ -5342,6 +5414,7 @@ mod tests { }), }; let profile = ProviderProfile { + files: Vec::new(), id: "keycloak-sso".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -6123,6 +6196,7 @@ mod tests { fn custom_profile(id: &str) -> ProviderProfile { ProviderProfile { + files: Vec::new(), id: id.to_string(), resource_version: 0, annotations: HashMap::new(), @@ -6301,6 +6375,7 @@ mod tests { "google-cloud", "google-vertex-ai", "nvidia", + "oci-genai", "openai", "openrouter", "pypi" @@ -6950,6 +7025,7 @@ mod tests { request_id: String::new(), profiles: vec![ProviderProfileImportItem { profile: Some(ProviderProfile { + files: Vec::new(), id: "advanced-api".to_string(), resource_version: 0, annotations: HashMap::new(), @@ -10335,6 +10411,7 @@ mod tests { request_id: String::new(), profiles: vec![ProviderProfileImportItem { profile: Some(ProviderProfile { + files: Vec::new(), id: "delegated-refresh-api".to_string(), resource_version: 0, annotations: HashMap::new(), diff --git a/crates/openshell-server/src/storage_proto.rs b/crates/openshell-server/src/storage_proto.rs index f9283b8cca..918ba14d9f 100644 --- a/crates/openshell-server/src/storage_proto.rs +++ b/crates/openshell-server/src/storage_proto.rs @@ -121,12 +121,17 @@ mod tests { // Restart policy is stored in SandboxSpec, and the count and well-known // timestamps are stored in SandboxStatus. Legacy payloads decode with // Unspecified (treated as Never), zero count, and absent timestamps. + // ProviderProfileFile is reachable from stored provider profiles. Its + // additive declaration changes the durable and public/durable overlap + // inventories; the provider-environment file map is public-only. The + // request has no provider-file capability field: older supervisors ignore + // the additive file map while retaining the rest of the response. const PUBLIC_RPC_SCHEMA_SHA256: &str = - "b1f9b34f035234e1032685eb4fc829950acad63a971b3abd37a2ccbbec783531"; + "2ed66dbc38c60eb96c7461c76d02813c177facfad93753b180534477270ad240"; const DURABLE_SCHEMA_SHA256: &str = - "517561b578c88d28ffd74d128faf668e65aef03c784dd794aeb5208e1dbf6de3"; + "399737f2a367d2e3a9d78cf84e2a97eef041835554599790788e4bbf318116c3"; const PUBLIC_DURABLE_OVERLAP_SHA256: &str = - "d60c0a91163bcdd6c29e24c64e0f00555f914240465f94295d800e9063171bef"; + "d3c444ecdb42306af8a81791481fdfc147ddc54bf344e1c8e69bd06745c6cc3c"; // A persisted Sandbox without endpoint status retains its lifecycle fields; // the absent repeated field decodes empty and needs no database rewrite. const SANDBOX_WITHOUT_ENDPOINT_STATUS: &str = "0a1e0a0a73616e64626f782d6964120773616e64626f783a0764656661756c741a2b0a0773616e64626f782a0d0a05526561647912045472756530023807420d73757065727669736f722d6964"; @@ -589,9 +594,9 @@ mod tests { overlap_hash.as_str(), ), ( - (304, 26), - (92, 20), - (80, 20), + (306, 26), + (93, 20), + (81, 20), PUBLIC_RPC_SCHEMA_SHA256, DURABLE_SCHEMA_SHA256, PUBLIC_DURABLE_OVERLAP_SHA256 diff --git a/crates/openshell-supervisor-network/data/sandbox-policy.rego b/crates/openshell-supervisor-network/data/sandbox-policy.rego index 61f7188b46..a477e1253f 100644 --- a/crates/openshell-supervisor-network/data/sandbox-policy.rego +++ b/crates/openshell-supervisor-network/data/sandbox-policy.rego @@ -424,11 +424,66 @@ request_deny_reason := reason if { reason := "JSON-RPC response frames are not permitted from client to server" } +# Explain only parsed MCP calls on an endpoint that matches this request path. +# The relay evaluates batch members separately. Response frames and protocol +# errors keep their own diagnostics, and a sibling endpoint must not select +# the explanation merely because it shares the connection's host and port. +mcp_policy_request if { + input.request.method == "POST" + not is_object(object.get(input.request, "graphql", null)) + not jsonrpc_response_frame_present(input.request) + jsonrpc := object.get(input.request, "jsonrpc", null) + is_object(jsonrpc) + jsonrpc_no_parse_error(jsonrpc) + method := object.get(jsonrpc, "method", "") + is_string(method) + method != "" + object.get(jsonrpc, "mcp_method_classification", "") in {"available", "extension"} + endpoint := _matching_endpoint_configs[_] + endpoint.protocol == "mcp" + endpoint_path_matches_request(endpoint, input.request) +} + +# These reasons use fixed text because method names and tool parameters can +# contain caller data. Deny rules take precedence over missing allow rules. +request_deny_reason := reason if { + mcp_policy_request + deny_request + reason := "MCP request blocked by a deny rule; ask the policy owner to review deny_rules and tool selectors" +} + +request_deny_reason := reason if { + mcp_policy_request + not deny_request + not allow_request + input.request.jsonrpc.mcp_method_classification == "extension" + reason := "MCP extension method has no matching exact allow rule; ask the policy owner to review rules with an exact method name and any parameter restrictions; allow_all_known_mcp_methods does not allow extensions" +} + +request_deny_reason := reason if { + mcp_policy_request + not deny_request + not allow_request + input.request.jsonrpc.mcp_method_classification == "available" + input.request.jsonrpc.method == "tools/call" + reason := "MCP tool call has no matching allow rule; ask the policy owner to review rules and tool selectors" +} + +request_deny_reason := reason if { + mcp_policy_request + not deny_request + not allow_request + input.request.jsonrpc.mcp_method_classification == "available" + input.request.jsonrpc.method != "tools/call" + reason := "MCP core method is not permitted by policy; ask the policy owner to review rules for this method in the selected MCP revision" +} + request_deny_reason := reason if { input.request deny_request not graphql_request_has_operations(input.request) not jsonrpc_response_frame_present(input.request) + not mcp_policy_request reason := sprintf("%s %s blocked by deny rule", [input.request.method, input.request.path]) } @@ -438,6 +493,7 @@ request_deny_reason := reason if { not allow_request not graphql_request_has_operations(input.request) not jsonrpc_response_frame_present(input.request) + not mcp_policy_request reason := sprintf("%s %s not permitted by policy", [input.request.method, input.request.path]) } diff --git a/crates/openshell-supervisor-network/src/l7/jsonrpc.rs b/crates/openshell-supervisor-network/src/l7/jsonrpc.rs index f3ddb0527d..6d767191fd 100644 --- a/crates/openshell-supervisor-network/src/l7/jsonrpc.rs +++ b/crates/openshell-supervisor-network/src/l7/jsonrpc.rs @@ -814,10 +814,7 @@ fn parse_mcp_payload( TowerMcpMethodClassification::Unavailable => { return JsonRpcRequestInfo::rejected( inspection.payload().is_batch(), - JsonRpcInspectionError::mcp_profile_violation(format!( - "MCP {revision} does not make `{}` available", - method.method() - )), + unavailable_mcp_method_error(revision, method.method()), ); } _ => { @@ -944,10 +941,7 @@ pub(crate) fn inspect_mcp_payload_for_revision( for method in inspection.methods() { match method.classification() { TowerMcpMethodClassification::Unavailable => { - return Err(JsonRpcInspectionError::mcp_profile_violation(format!( - "MCP {revision} does not make `{}` available", - method.method() - ))); + return Err(unavailable_mcp_method_error(revision, method.method())); } TowerMcpMethodClassification::Available | TowerMcpMethodClassification::Extension => {} _ => { @@ -962,6 +956,17 @@ pub(crate) fn inspect_mcp_payload_for_revision( Ok(inspection) } +// Only a method recognized by Tower's closed core-method registry reaches +// this diagnostic. Policy permission cannot make it valid in another revision. +fn unavailable_mcp_method_error( + revision: McpProtocolVersion, + method: &str, +) -> JsonRpcInspectionError { + JsonRpcInspectionError::mcp_profile_violation(format!( + "MCP method `{method}` is unavailable in revision {revision}; use a method defined by this core revision, or check client/server support and mcp.versions before selecting another revision; allow rules and allow_all_known_mcp_methods cannot enable an unavailable method" + )) +} + fn parse_mcp_initialize(payload: JsonRpcPayload) -> JsonRpcRequestInfo { if payload.is_batch() { return JsonRpcRequestInfo::rejected( @@ -1080,10 +1085,18 @@ fn mcp_named_request_for_inspected_method( fn map_mcp_inspection_error(error: McpInspectionError) -> JsonRpcInspectionError { match error.kind() { - McpInspectionErrorKind::BatchUnavailable - | McpInspectionErrorKind::DirectionMismatch - | McpInspectionErrorKind::UnsupportedProfile => { - JsonRpcInspectionError::mcp_profile_violation(error.to_string()) + McpInspectionErrorKind::BatchUnavailable => JsonRpcInspectionError::mcp_profile_violation( + format!("{error}; send each JSON-RPC message in a separate request for this revision"), + ), + McpInspectionErrorKind::DirectionMismatch => { + JsonRpcInspectionError::mcp_profile_violation(format!( + "{error}; send the method from the peer role defined by this revision; an allow rule cannot change its direction" + )) + } + McpInspectionErrorKind::UnsupportedProfile => { + JsonRpcInspectionError::mcp_profile_violation(format!( + "{error}; use an MCP revision supported by this OpenShell build" + )) } McpInspectionErrorKind::InitializeInBatch => { JsonRpcInspectionError::mcp_lifecycle_violation(error.to_string()) @@ -1889,12 +1902,18 @@ mod tests { info.error.as_ref().map(JsonRpcInspectionError::kind), Some(JsonRpcInspectionErrorKind::McpProfileViolation) ); + let detail = info.error.as_ref().expect("unavailable method").detail(); + assert!(detail.contains("`tasks/get` is unavailable in revision 2025-06-18")); + assert!(detail.contains("check client/server support and mcp.versions")); + assert!(detail.contains("allow_all_known_mcp_methods cannot enable")); assert!( - info.error - .as_ref() - .is_some_and(|error| error.detail().contains("tasks/get")), - "expected unavailable-method evidence, got {info:?}" + !detail.contains("task-1"), + "task params must not be reflected" ); + + let november = + parse_jsonrpc_body_with_options(body, mcp_options(McpProtocolVersion::V2025_11_25)); + assert!(november.error.is_none(), "November task remains valid"); } #[test] @@ -1919,6 +1938,11 @@ mod tests { .is_some_and(|error| error.detail().contains("client-to-server")), "expected direction mismatch evidence, got {info:?}" ); + assert!(info.error.as_ref().is_some_and(|error| { + error + .detail() + .contains("an allow rule cannot change its direction") + })); } #[test] diff --git a/crates/openshell-supervisor-network/src/l7/mcp.rs b/crates/openshell-supervisor-network/src/l7/mcp.rs index 4c46ad8830..26538c9467 100644 --- a/crates/openshell-supervisor-network/src/l7/mcp.rs +++ b/crates/openshell-supervisor-network/src/l7/mcp.rs @@ -39,6 +39,20 @@ pub(super) enum McpProtocolVersionError { } impl McpProtocolVersionError { + /// Explain a rejected revision using validated header metadata. + /// + /// Missing headers select the 2025-03-26 fallback. Only the validated parser + /// may identify that case; duplicate or hop-by-hop headers must keep their + /// own rejection reason without being described as absent. + pub(super) fn rejection_detail(self, request: &L7Request) -> String { + match self { + Self::NotAllowed(version) => { + format!("{self}; {}", selected_revision_context(request, version)) + } + _ => self.to_string(), + } + } + /// Return the HTTP status for this transport or policy rejection. #[must_use] pub(super) const fn http_status(self) -> &'static str { @@ -68,20 +82,20 @@ impl std::fmt::Display for McpProtocolVersionError { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::InvalidHeader => formatter.write_str( - "MCP-Protocol-Version must contain one non-empty end-to-end header value", + "MCP-Protocol-Version must contain one non-empty end-to-end header value; send exactly one revision, without duplicates, comma-separated values, or Connection nomination", ), Self::UnsupportedHeaderValue => { - formatter.write_str("MCP-Protocol-Version names an unsupported protocol version") + formatter.write_str("MCP-Protocol-Version names a revision unsupported by this OpenShell build; use a supported client/server revision permitted by mcp.versions") } Self::InvalidRequestMetadata => { - formatter.write_str("MCP request headers must match the inspected request metadata") + formatter.write_str("MCP request headers must match the inspected request metadata; send MCP-Protocol-Version, Mcp-Method, and any required Mcp-Name consistently with the 2026-07-28 message") } Self::MethodNotAllowed => { - formatter.write_str("MCP protocol version 2026-07-28 requires HTTP POST") + formatter.write_str("MCP protocol version 2026-07-28 requires HTTP POST; send a POST message instead of a legacy GET stream or DELETE session request") } Self::NotAllowed(version) => write!( formatter, - "MCP protocol version {version} is not allowed by endpoint policy" + "MCP protocol version {version} is not allowed by endpoint policy; use a client/server revision permitted by mcp.versions" ), } } @@ -89,6 +103,23 @@ impl std::fmt::Display for McpProtocolVersionError { impl std::error::Error for McpProtocolVersionError {} +/// Describe how the request selected its MCP revision. +/// +/// Initial and post-middleware inspection supply their current request so the +/// explanation describes the headers used for that selection. +pub(super) fn selected_revision_context( + request: &L7Request, + version: McpProtocolVersion, +) -> String { + match request_protocol_version_header(&request.raw_header) { + Ok(None) => format!( + "selected MCP revision {version} from the missing MCP-Protocol-Version header fallback; send the client/server revision explicitly in that header" + ), + Ok(Some(_)) => format!("selected MCP revision {version} from MCP-Protocol-Version"), + Err(_) => format!("selected MCP revision {version}"), + } +} + /// Select and authorize the protocol revision for one MCP HTTP request. /// /// Legacy initialization negotiates its revision in the body. It cannot exempt diff --git a/crates/openshell-supervisor-network/src/l7/relay.rs b/crates/openshell-supervisor-network/src/l7/relay.rs index cad8f668e9..0aa453258f 100644 --- a/crates/openshell-supervisor-network/src/l7/relay.rs +++ b/crates/openshell-supervisor-network/src/l7/relay.rs @@ -224,7 +224,10 @@ where // even when the caller disconnects before receiving it. observer.observe(EndpointResult::PolicyDenied); } - let reason = error.to_string(); + let reason = format!( + "{error}; {}", + crate::l7::mcp::selected_revision_context(request, version) + ); let summary = l7_protocol_log_summary(None, Some(&info)); ocsf_emit!(build_l7_request_event( ctx, @@ -305,7 +308,7 @@ where // Record the denial before client delivery can fail. observer.observe(EndpointResult::PolicyDenied); } - let reason = error.to_string(); + let reason = error.rejection_detail(request); let summary = l7_protocol_log_summary(None, Some(info)); ocsf_emit!(build_l7_request_event( ctx, @@ -10992,23 +10995,31 @@ network_policies: #[tokio::test] async fn mcp_relay_rejects_invalid_disallowed_and_missing_versions_without_forwarding() { - for (headers, status, code) in [ + for (headers, status, code, remedy) in [ ( "MCP-Protocol-Version: 2026-07-29\r\n", "400 Bad Request", "unsupported_mcp_protocol_version", + "use a supported client/server revision permitted by mcp.versions", ), ( "MCP-Protocol-Version: 2025-11-25\r\nMCP-Protocol-Version: 2025-11-25\r\n", "400 Bad Request", "invalid_mcp_protocol_version_header", + "send exactly one revision", ), ( "MCP-Protocol-Version: 2025-06-18\r\n", "403 Forbidden", "mcp_protocol_version_not_allowed", + "selected MCP revision 2025-06-18 from MCP-Protocol-Version", + ), + ( + "", + "403 Forbidden", + "mcp_protocol_version_not_allowed", + "missing MCP-Protocol-Version header fallback; send the client/server revision explicitly", ), - ("", "403 Forbidden", "mcp_protocol_version_not_allowed"), ] { let (response, forwarded) = run_rejected_mcp_request( false, @@ -11021,6 +11032,7 @@ network_policies: "{response}" ); assert!(response.contains(code), "{response}"); + assert!(response.contains(remedy), "{response}"); assert!(forwarded.is_empty(), "rejected request reached upstream"); } } @@ -11506,12 +11518,40 @@ network_policies: response.contains("does not permit top-level JSON-RPC batches"), "{response}" ); + assert!(response.contains("send each JSON-RPC message in a separate request")); + assert!(response.contains("selected MCP revision 2025-11-25 from MCP-Protocol-Version")); assert!( forwarded.is_empty(), "profile-invalid request reached upstream" ); } + #[tokio::test] + async fn mcp_relay_explains_unavailable_method_without_reflecting_params() { + // tasks/update is known to the parser but absent from the selected + // core revision. The diagnostic must not suggest adding an allow rule. + let body = br#"{"jsonrpc":"2.0","id":1,"method":"tasks/update","params":{"taskId":"private-task-marker","inputResponses":{"secret":"private-argument-marker"}}}"#; + for route_selected in [false, true] { + let (response, forwarded) = run_rejected_mcp_request( + route_selected, + "MCP-Protocol-Version: 2025-11-25\r\n", + body, + ) + .await; + assert!( + response.starts_with("HTTP/1.1 400 Bad Request"), + "{response}" + ); + assert!(response.contains("invalid_mcp_request"), "{response}"); + assert!(response.contains("`tasks/update` is unavailable in revision 2025-11-25")); + assert!(response.contains("allow_all_known_mcp_methods cannot enable")); + assert!(response.contains("from MCP-Protocol-Version")); + assert!(!response.contains("private-task-marker")); + assert!(!response.contains("private-argument-marker")); + assert!(forwarded.is_empty(), "unavailable method reached upstream"); + } + } + #[tokio::test] async fn final_mcp_version_check_reclassifies_a_rewritten_initialize_body() { let (config, _, ctx) = mcp_test_relay_context(); diff --git a/crates/openshell-supervisor-network/src/opa.rs b/crates/openshell-supervisor-network/src/opa.rs index 002972efbf..851125c415 100644 --- a/crates/openshell-supervisor-network/src/opa.rs +++ b/crates/openshell-supervisor-network/src/opa.rs @@ -4925,6 +4925,31 @@ process: val == regorus::Value::from(true) } + fn assert_l7_denial( + engine: &OpaEngine, + input: &serde_json::Value, + deny_rule_matches: bool, + expected_reason: &str, + ) { + let mut eng = engine.engine.lock().unwrap(); + set_regorus_input(&mut eng, input.clone()).unwrap(); + assert_eq!( + eng.eval_rule("data.openshell.sandbox.allow_request".into()) + .expect("evaluate allow_request"), + regorus::Value::from(false), + ); + assert_eq!( + eng.eval_rule("data.openshell.sandbox.deny_request".into()) + .expect("evaluate deny_request"), + regorus::Value::from(deny_rule_matches), + ); + assert_eq!( + eng.eval_rule("data.openshell.sandbox.request_deny_reason".into()) + .expect("evaluate one unambiguous denial reason"), + regorus::Value::from(expected_reason), + ); + } + fn eval_l7_raw_data(data: serde_json::Value, input: serde_json::Value) -> bool { let mut engine = regorus::Engine::new(); engine @@ -6271,10 +6296,34 @@ network_policies: "tools/call", serde_json::json!({"name": "blocked_action"}), ); - assert!(!eval_l7(&engine, &blocked)); + assert_l7_denial( + &engine, + &blocked, + true, + "MCP request blocked by a deny rule; ask the policy owner to review deny_rules and tool selectors", + ); + + let unmatched_tool = l7_jsonrpc_input_with_params( + "mcp.params.test", + 8000, + "/mcp", + "tools/call", + serde_json::json!({"name": "private_tool_name", "arguments.secret": "private-value"}), + ); + assert_l7_denial( + &engine, + &unmatched_tool, + false, + "MCP tool call has no matching allow rule; ask the policy owner to review rules and tool selectors", + ); let list_tools = l7_jsonrpc_input("mcp.params.test", 8000, "/mcp", "tools/list"); - assert!(!eval_l7(&engine, &list_tools)); + assert_l7_denial( + &engine, + &list_tools, + false, + "MCP core method is not permitted by policy; ask the policy owner to review rules for this method in the selected MCP revision", + ); } #[test] @@ -6311,12 +6360,19 @@ network_policies: let list_tools = l7_jsonrpc_input("mcp.default.test", 8000, "/mcp", "tools/list"); assert!(eval_l7(&engine, &list_tools)); - let mut extension = l7_jsonrpc_input("mcp.default.test", 8000, "/mcp", "vendor/extension"); + let mut extension = l7_jsonrpc_input( + "mcp.default.test", + 8000, + "/mcp", + "vendor/private_method_name", + ); extension["request"]["jsonrpc"]["mcp_method_classification"] = serde_json::json!("extension"); - assert!( - !eval_l7(&engine, &extension), - "allow_all_known_mcp_methods must cover only selected-profile methods" + assert_l7_denial( + &engine, + &extension, + false, + "MCP extension method has no matching exact allow rule; ask the policy owner to review rules with an exact method name and any parameter restrictions; allow_all_known_mcp_methods does not allow extensions", ); } @@ -6382,20 +6438,108 @@ network_policies: l7_jsonrpc_input("mcp.extension-wildcard.test", 8000, "/mcp", "tools/vendor"); wildcard["request"]["jsonrpc"]["mcp_method_classification"] = serde_json::json!("extension"); - assert!( - !eval_l7(&engine, &wildcard), - "wildcards must not authorize unknown extension methods" + assert_l7_denial( + &engine, + &wildcard, + false, + "MCP extension method has no matching exact allow rule; ask the policy owner to review rules with an exact method name and any parameter restrictions; allow_all_known_mcp_methods does not allow extensions", ); let mut denied = l7_jsonrpc_input("mcp.extension-denied.test", 8000, "/mcp", "tools/vendor"); denied["request"]["jsonrpc"]["mcp_method_classification"] = serde_json::json!("extension"); - assert!( - !eval_l7(&engine, &denied), - "deny-rule wildcards must still block explicitly allowed extensions" + assert_l7_denial( + &engine, + &denied, + true, + "MCP request blocked by a deny rule; ask the policy owner to review deny_rules and tool selectors", ); } + #[test] + fn l7_mcp_denial_reason_matches_request_path_and_protocol() { + let data = r#" +network_policies: + mixed: + name: mixed + endpoints: + - host: mcp.reasons.test + port: 8000 + path: /rpc + protocol: json-rpc + enforcement: enforce + rules: [{allow: {method: reports.list}}] + - host: mcp.reasons.test + port: 8000 + path: /rest + protocol: rest + enforcement: enforce + rules: [{allow: {method: GET, path: /rest}}] + - host: mcp.reasons.test + port: 8000 + path: /mcp + protocol: mcp + enforcement: enforce + mcp: + allow_all_known_mcp_methods: true + rules: [{allow: {tool: read_status}}] + binaries: + - {path: /usr/bin/curl} +"#; + let engine = OpaEngine::from_strings(TEST_POLICY, data).expect("engine from yaml"); + + // Select the explanation by the current request path, not the first + // configured endpoint for this host and port. + let unmatched_tool = l7_jsonrpc_input_with_params( + "mcp.reasons.test", + 8000, + "/mcp", + "tools/call", + serde_json::json!({"name": "other_tool"}), + ); + assert_l7_denial( + &engine, + &unmatched_tool, + false, + "MCP tool call has no matching allow rule; ask the policy owner to review rules and tool selectors", + ); + for path in ["/rest", "/rpc", "/other"] { + assert_l7_denial( + &engine, + &l7_jsonrpc_input("mcp.reasons.test", 8000, path, "tools/call"), + false, + &format!("POST {path} not permitted by policy"), + ); + } + + // Batch envelopes have no selected call until the relay evaluates + // each member. Protocol failures also remain outside policy hints. + for field in ["method", "error", "mcp_method_classification"] { + let mut input = unmatched_tool.clone(); + input["request"]["jsonrpc"][field] = match field { + "method" => serde_json::Value::Null, + "error" => serde_json::json!("invalid MCP request"), + _ => serde_json::json!("unavailable"), + }; + assert_l7_denial(&engine, &input, false, "POST /mcp not permitted by policy"); + } + + assert_l7_denial( + &engine, + &l7_jsonrpc_response_input("mcp.reasons.test", 8000, "/rpc"), + true, + "JSON-RPC response frames are not permitted from client to server", + ); + assert!(eval_l7( + &engine, + &l7_jsonrpc_response_input("mcp.reasons.test", 8000, "/mcp") + )); + assert!(eval_l7( + &engine, + &l7_jsonrpc_input("mcp.reasons.test", 8000, "/mcp", "tools/list") + )); + } + #[test] fn l7_jsonrpc_null_metadata_non_matches_without_opa_error() { let data = r#" diff --git a/crates/openshell-supervisor-process/Cargo.toml b/crates/openshell-supervisor-process/Cargo.toml index db56a1fd48..39d48a96e5 100644 --- a/crates/openshell-supervisor-process/Cargo.toml +++ b/crates/openshell-supervisor-process/Cargo.toml @@ -39,6 +39,7 @@ libc = "0.2" [dev-dependencies] openshell-ocsf = { path = "../openshell-ocsf", features = ["test-support"] } tempfile = "3" +tokio = { workspace = true, features = ["test-util"] } [lints] workspace = true diff --git a/crates/openshell-supervisor-process/src/ssh.rs b/crates/openshell-supervisor-process/src/ssh.rs index 25c5cfdbbd..40e0db1668 100644 --- a/crates/openshell-supervisor-process/src/ssh.rs +++ b/crates/openshell-supervisor-process/src/ssh.rs @@ -26,6 +26,14 @@ const NO_LOGIN_SHELL_ENV: (&str, &str) = ("OPENSHELL_NO_LOGIN_SHELL", "1"); const MAIN_DETACH_PREFIX: u8 = 0x10; const MAIN_DETACH_KEY: u8 = 0x11; const MAIN_DETACH_EOF: u8 = 0x04; +const SSH_KEEPALIVE_INTERVAL: Duration = Duration::from_secs(15); +const SSH_PEER_TIMEOUT: Duration = Duration::from_mins(1); + +mod peer_stream; + +#[cfg(test)] +#[path = "ssh/reconnect_tests.rs"] +mod reconnect_tests; fn filter_main_detach_sequence(prefix_pending: &mut bool, data: &[u8]) -> (Vec, bool) { let mut forward = Vec::with_capacity(data.len() + usize::from(*prefix_pending)); @@ -70,6 +78,9 @@ fn ssh_server_init( let mut config = russh::server::Config { server_id: russh::SshId::Standard(Cow::Owned(format!("SSH-2.0-OpenShell_{VERSION}"))), auth_rejection_time: Duration::from_secs(1), + // Peer replies keep idle attachments alive without relying on shell I/O. + keepalive_interval: Some(SSH_KEEPALIVE_INTERVAL), + keepalive_max: 3, ..Default::default() }; config.keys.push(host_key); @@ -159,9 +170,15 @@ pub async fn run_ssh_server( let main_session = main_session.clone(); tokio::spawn(async move { - if let Err(err) = - handle_connection(stream, config, port_forward, boundary_exec, main_session) - .await + if let Err(err) = handle_connection( + stream, + config, + port_forward, + boundary_exec, + main_session, + SSH_PEER_TIMEOUT, + ) + .await { ocsf_emit!( SshActivityBuilder::new(openshell_ocsf::ctx::ctx()) @@ -300,6 +317,7 @@ async fn handle_connection( port_forward: Arc, boundary_exec: Arc, main_session: Option>, + peer_timeout: Duration, ) -> Result<()> { // Access is gated by the Unix-socket filesystem permissions (root-only), // not by an application-level preface. The supervisor bridges the @@ -316,9 +334,12 @@ async fn handle_connection( ); let handler = SshHandler::new(port_forward, boundary_exec, main_session); + let stream = peer_stream::PeerStream::new(stream, peer_timeout); russh::server::run_stream(config, stream, handler) .await - .map_err(|err| miette::miette!("ssh stream error: {err}"))?; + .map_err(|err| miette::miette!("ssh stream error: {err}"))? + .await + .map_err(|err| miette::miette!("ssh session error: {err}"))?; Ok(()) } @@ -339,6 +360,9 @@ struct ChannelState { main_input_owner: Option, main_attached: bool, main_read_only: bool, + /// A writable attachment denied stdin may retry on later input. Explicit + /// viewers and channels that sent EOF must never acquire a new lease. + main_input_pending: bool, main_detach_prefix_pending: bool, main_output_task: Option, } @@ -704,6 +728,7 @@ impl russh::server::Handler for SshHandler { Err(error) => (None, Some(error)), } }; + state.main_input_pending = warning.is_some(); state.input_sender = input; state.main_detach_prefix_pending = false; let mut output = main_session.subscribe(); @@ -715,7 +740,7 @@ impl russh::server::Handler for SshHandler { .extended_data( channel, 1, - format!("openshell: {error}; attached read-only; press Ctrl-C or Ctrl-D to exit{line_ending}").into_bytes(), + format!("openshell: {error}; attached read-only; retry input after the owner disconnects; press Ctrl-C or Ctrl-D to exit{line_ending}").into_bytes(), ) .await; } @@ -831,11 +856,35 @@ impl russh::server::Handler for SshHandler { .await; return Ok(()); } - let (forward, detach) = if state.main_attached { + let denied_prefix = state.main_input_pending && state.main_detach_prefix_pending; + let (mut forward, detach) = if state.main_attached { filter_main_detach_sequence(&mut state.main_detach_prefix_pending, data) } else { (data.to_vec(), false) }; + // Remember a denied viewer's prefix only to recognize split detach + // sequences. It must not become process input when a later frame wins + // the lease: that earlier keystroke was sent without write ownership. + if denied_prefix && forward.first() == Some(&MAIN_DETACH_PREFIX) { + forward.remove(0); + } + // A reconnect can precede detection of the old connection's failure. + // Retry only on new input, using the same exclusive acquisition as a + // fresh attachment. Detach keys retain their read-only behavior. + if state.main_attached + && state.main_input_pending + && !state.main_read_only + && !detach + && !forward.is_empty() + && let Some(main_session) = self.main_session.as_ref() + && !main_session.finished() + && let Ok((owner, input)) = main_session.acquire_input() + { + state.main_input_owner = Some(owner); + state.input_sender = Some(InputSender::Main(input)); + state.main_input_pending = false; + session.extended_data(channel, 1, b"openshell: input enabled\r\n".to_vec())?; + } let error = (!forward.is_empty()) .then(|| state.input_sender.as_ref()?.send(forward).err()) .flatten(); @@ -866,6 +915,7 @@ impl russh::server::Handler for SshHandler { main_session.release_input(owner); } state.input_sender.take(); + state.main_input_pending = false; state.main_detach_prefix_pending = false; } else { warn!("channel_eof on unknown channel {channel:?}"); @@ -1086,6 +1136,7 @@ impl SshHandler { main_session.release_input(owner); } state.input_sender.take(); + state.main_input_pending = false; state.main_detach_prefix_pending = false; if let Some(task) = state.main_output_task.take() { task.abort(); @@ -1221,7 +1272,7 @@ mod tests { use std::io::Write as _; use std::process::{Command, Stdio}; - struct AcceptAnyServerKey; + pub(super) struct AcceptAnyServerKey; impl russh::client::Handler for AcceptAnyServerKey { type Error = russh::Error; @@ -1234,7 +1285,7 @@ mod tests { } } - struct TestLoopbackConnector; + pub(super) struct TestLoopbackConnector; #[async_trait::async_trait] impl openshell_isolation_interface::contract::BoundaryLoopbackConnector for TestLoopbackConnector { @@ -1256,7 +1307,7 @@ mod tests { } } - struct RejectingExec; + pub(super) struct RejectingExec; #[async_trait::async_trait] impl openshell_isolation_interface::contract::BoundaryExec for RejectingExec { @@ -1546,7 +1597,7 @@ mod tests { assert_eq!( String::from_utf8_lossy(&data), format!( - "openshell: canonical main process already has an input owner; attached read-only; press Ctrl-C or Ctrl-D to exit{line_ending}" + "openshell: canonical main process already has an input owner; attached read-only; retry input after the owner disconnects; press Ctrl-C or Ctrl-D to exit{line_ending}" ) ); } diff --git a/crates/openshell-supervisor-process/src/ssh/peer_stream.rs b/crates/openshell-supervisor-process/src/ssh/peer_stream.rs new file mode 100644 index 0000000000..92af3ebfe8 --- /dev/null +++ b/crates/openshell-supervisor-process/src/ssh/peer_stream.rs @@ -0,0 +1,118 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Bound SSH peer silence even while the session is blocked writing to its relay. + +use std::future::Future; +use std::io; +use std::pin::Pin; +use std::task::{Context, Poll}; +use std::time::Duration; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; +use tokio::time::{Instant, Sleep}; + +/// Only inbound bytes extend the deadline. SSH keepalive replies allow healthy +/// idle clients to retain their connections without sending application input. +pub(super) struct PeerStream { + stream: S, + timeout: Duration, + deadline: Pin>, +} + +impl PeerStream { + pub(super) fn new(stream: S, timeout: Duration) -> Self { + Self { + stream, + timeout, + deadline: Box::pin(tokio::time::sleep(timeout)), + } + } + + fn poll_deadline(&mut self, cx: &mut Context<'_>) -> io::Result<()> { + if self.deadline.as_mut().poll(cx).is_ready() { + return Err(io::Error::new( + io::ErrorKind::TimedOut, + "SSH peer did not respond before the receive deadline", + )); + } + Ok(()) + } +} + +impl AsyncRead for PeerStream { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + self.poll_deadline(cx)?; + let before = buf.filled().len(); + match Pin::new(&mut self.stream).poll_read(cx, buf) { + Poll::Ready(Ok(())) => { + if buf.filled().len() > before { + let next = Instant::now() + self.timeout; + self.deadline.as_mut().reset(next); + } + Poll::Ready(Ok(())) + } + other => other, + } + } +} + +impl AsyncWrite for PeerStream { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + // Russh awaits packet writes outside its keepalive select. Polling here + // makes an expired peer close even when the relay stops draining output. + self.poll_deadline(cx)?; + Pin::new(&mut self.stream).poll_write(cx, buf) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.poll_deadline(cx)?; + Pin::new(&mut self.stream).poll_flush(cx) + } + + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.poll_deadline(cx)?; + Pin::new(&mut self.stream).poll_shutdown(cx) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tokio::io::{AsyncReadExt, AsyncWriteExt}; + + #[tokio::test(start_paused = true)] + async fn blocked_write_expires_at_receive_deadline() { + let (stream, _peer) = tokio::io::duplex(1); + let mut stream = PeerStream::new(stream, Duration::from_mins(1)); + let started = Instant::now(); + let error = stream.write_all(b"ab").await.unwrap_err(); + assert_eq!(error.kind(), io::ErrorKind::TimedOut); + assert_eq!(started.elapsed(), Duration::from_mins(1)); + } + + #[tokio::test(start_paused = true)] + async fn only_received_bytes_extend_the_deadline() { + let (stream, mut peer) = tokio::io::duplex(1); + let mut stream = PeerStream::new(stream, Duration::from_mins(1)); + let started = Instant::now(); + tokio::time::advance(Duration::from_secs(40)).await; + peer.write_all(b"r").await.unwrap(); + let mut reply = [0]; + stream.read_exact(&mut reply).await.unwrap(); + assert_eq!(&reply, b"r"); + tokio::time::advance(Duration::from_secs(40)).await; + // A successful write must not renew peer liveness either. + stream.write_all(b"a").await.unwrap(); + let error = stream.write_all(b"b").await.unwrap_err(); + assert_eq!(error.kind(), io::ErrorKind::TimedOut); + assert_eq!(started.elapsed(), Duration::from_secs(100)); + } +} diff --git a/crates/openshell-supervisor-process/src/ssh/reconnect_tests.rs b/crates/openshell-supervisor-process/src/ssh/reconnect_tests.rs new file mode 100644 index 0000000000..f326c63cf2 --- /dev/null +++ b/crates/openshell-supervisor-process/src/ssh/reconnect_tests.rs @@ -0,0 +1,568 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Exercise a half-open gateway path through the production supervisor frame bridge. + +use super::tests::{AcceptAnyServerKey, RejectingExec, TestLoopbackConnector}; +use super::*; +use openshell_core::proto::{RelayFrame, relay_frame}; +use openshell_isolation_interface::contract::{ + BackendError, BoundaryExitStatus, BoundaryProcess, BoundarySignal, ProcessAttachment, +}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::sync::{mpsc, watch}; + +const TEST_INTERVAL: Duration = Duration::from_millis(50); +const WAIT: Duration = Duration::from_secs(3); + +#[derive(Clone, Copy, PartialEq)] +enum RelayMode { + Forward, + Discard, + Stalled, +} + +#[derive(Default)] +struct RetainedProcess(AtomicUsize); + +#[async_trait::async_trait] +impl BoundaryProcess for RetainedProcess { + async fn wait(&self) -> Result { + std::future::pending().await + } + + async fn signal(&self, _: BoundarySignal) -> Result<(), BackendError> { + self.0.fetch_add(1, Ordering::SeqCst); + Ok(()) + } + + async fn terminate(&self) -> Result<(), BackendError> { + self.0.fetch_add(1, Ordering::SeqCst); + Ok(()) + } +} + +struct CanonicalProcess { + session: Arc, + process: Arc, + input: tokio::io::DuplexStream, + output: Option, +} + +impl CanonicalProcess { + fn new() -> Self { + let (stdin, input) = tokio::io::duplex(64 * 1024); + let (stdout, output) = tokio::io::duplex(64 * 1024); + let process = Arc::new(RetainedProcess::default()); + let session = MainSession::from_boundary( + ProcessAttachment { + stdin: Box::new(stdin), + stdout: Box::new(stdout), + stderr: None, + terminal: None, + }, + process.clone(), + ); + Self { + session, + process, + input, + output: Some(output), + } + } + + async fn assert_input(&mut self, channel: &russh::Channel) { + channel.data(&b"typing restored\n"[..]).await.unwrap(); + self.expect_input().await; + } + + async fn expect_input(&mut self) { + let mut received = [0; 16]; + tokio::time::timeout(WAIT, self.input.read_exact(&mut received)) + .await + .expect("attachment must deliver input to the retained process") + .unwrap(); + assert_eq!(&received, b"typing restored\n"); + assert!(!self.session.finished()); + assert_eq!(self.process.0.load(Ordering::SeqCst), 0); + } +} + +struct Connection { + client: russh::client::Handle, + mode: watch::Sender, + tasks: Vec>, +} + +impl Drop for Connection { + fn drop(&mut self) { + for task in &self.tasks { + task.abort(); + } + } +} + +impl Connection { + async fn new(main: Arc) -> Self { + Self::with_window(main, None).await + } + + async fn with_window(main: Arc, window: Option) -> Self { + let dir = tempfile::tempdir().unwrap(); + let socket = dir.path().join("ssh.sock"); + let (listener, mut config, _) = ssh_server_init(&socket, &None, false).unwrap(); + // Preserve whether production enables probes. Only shorten the interval. + let config_mut = Arc::get_mut(&mut config).unwrap(); + config_mut.keepalive_interval = config_mut.keepalive_interval.map(|_| TEST_INTERVAL); + let server_task = tokio::spawn(async move { + let (stream, _) = listener.accept().await.unwrap(); + let _ = handle_connection( + stream, + config, + Arc::new(TestLoopbackConnector), + Arc::new(RejectingExec), + Some(main), + TEST_INTERVAL * 4, + ) + .await; + }); + let target = tokio::net::UnixStream::connect(&socket).await.unwrap(); + let (to_supervisor, inbound) = mpsc::channel(16); + let (outbound, mut from_supervisor) = mpsc::channel::(16); + let relay = tokio::spawn(crate::supervisor_session::test_bridge_ssh_relay( + target, inbound, outbound, + )); + let (client_stream, gateway_stream) = tokio::io::duplex(64 * 1024); + let (mut gateway_read, mut gateway_write) = tokio::io::split(gateway_stream); + let (mode, mut input_mode) = watch::channel(RelayMode::Forward); + let mut output_mode = input_mode.clone(); + let inbound_pump = tokio::spawn(async move { + let mut bytes = [0; 16 * 1024]; + loop { + if *input_mode.borrow() == RelayMode::Stalled { + if input_mode.changed().await.is_err() { + break; + } + continue; + } + tokio::select! { + changed = input_mode.changed() => { + if changed.is_err() { break; } + } + read = gateway_read.read(&mut bytes) => { + let Ok(size) = read else { break; }; + if size == 0 { break; } + if *input_mode.borrow() == RelayMode::Forward { + let frame = RelayFrame { + payload: Some(relay_frame::Payload::Data(bytes[..size].to_vec())), + }; + if to_supervisor.send(Ok(frame)).await.is_err() { break; } + } + } + } + } + }); + let outbound_pump = tokio::spawn(async move { + loop { + if *output_mode.borrow() == RelayMode::Stalled { + if output_mode.changed().await.is_err() { + break; + } + continue; + } + tokio::select! { + changed = output_mode.changed() => { + if changed.is_err() { break; } + } + frame = from_supervisor.recv() => { + let Some(frame) = frame else { break; }; + if let Some(relay_frame::Payload::Data(data)) = frame.payload + && *output_mode.borrow() == RelayMode::Forward + && gateway_write.write_all(&data).await.is_err() + { + break; + } + } + } + } + }); + let mut client_config = russh::client::Config::default(); + if let Some(window) = window { + client_config.window_size = window; + } + let mut client = russh::client::connect_stream( + Arc::new(client_config), + client_stream, + AcceptAnyServerKey, + ) + .await + .unwrap(); + assert!(matches!( + client.authenticate_none("sandbox").await.unwrap(), + russh::client::AuthResult::Success + )); + Self { + client, + mode, + tasks: vec![server_task, relay, inbound_pump, outbound_pump], + } + } + + async fn attach(&self) -> russh::Channel { + let mut channel = self.client.channel_open_session().await.unwrap(); + channel + .request_subsystem(true, "openshell-main") + .await + .unwrap(); + assert!(matches!( + next_event(&mut channel).await, + russh::ChannelMsg::Success + )); + channel + } +} + +async fn next_event(channel: &mut russh::Channel) -> russh::ChannelMsg { + tokio::time::timeout(WAIT, channel.wait()) + .await + .unwrap() + .unwrap() +} + +async fn assert_read_only(channel: &mut russh::Channel) { + loop { + match next_event(channel).await { + russh::ChannelMsg::ExtendedData { data, ext: 1 } => { + assert!(String::from_utf8_lossy(&data).contains("attached read-only")); + break; + } + russh::ChannelMsg::Data { .. } => {} + other => panic!("expected read-only diagnostic, got {other:?}"), + } + } +} + +async fn wait_for_release(main: &MainSession) { + tokio::time::timeout(WAIT, async { + loop { + if let Ok((owner, _)) = main.acquire_input() { + main.release_input(owner); + break; + } + tokio::time::sleep(Duration::from_millis(10)).await; + } + }) + .await + .expect("dead relay must release stdin within the liveness bound"); +} + +async fn reconnect_after_cut(mode: RelayMode, producing: bool) { + let mut main = CanonicalProcess::new(); + let original = Connection::new(main.session.clone()).await; + let original_channel = original.attach().await; + main.assert_input(&original_channel).await; + let mut early = Connection::new(main.session.clone()).await; + let mut early_channel = early.attach().await; + assert_read_only(&mut early_channel).await; + let (mut early_read, early_write) = early_channel.split(); + let (notice_tx, mut notice_rx) = mpsc::channel(1); + early.tasks.push(tokio::spawn(async move { + // The replacement remains a healthy output consumer while the old + // path is cut. Its own SSH receive window must not become the fault. + while let Some(event) = early_read.wait().await { + if let russh::ChannelMsg::ExtendedData { data, ext: 1 } = event { + let _ = notice_tx.send(data).await; + } + } + })); + original.mode.send_replace(mode); + + let output_task = producing.then(|| { + let mut output = main.output.take().unwrap(); + tokio::spawn(async move { + // Faster than the stalled relay can drain, but below the retained + // output budget until the SSH event queue has applied backpressure. + let chunk = [b'x'; 16 * 1024]; + loop { + if output.write_all(&chunk).await.is_err() { + break; + } + tokio::time::sleep(Duration::from_millis(2)).await; + } + }) + }); + wait_for_release(&main.session).await; + if let Some(task) = output_task { + task.abort(); + } + // The already reconnected writer can acquire the freed lease on new input. + // Keystrokes ignored while the previous owner was alive are never replayed. + early_write.data(&b"typing restored\n"[..]).await.unwrap(); + main.expect_input().await; + let notice = tokio::time::timeout(WAIT, notice_rx.recv()) + .await + .unwrap() + .unwrap(); + assert_eq!(¬ice[..], b"openshell: input enabled\r\n"); + early_write.close().await.unwrap(); + wait_for_release(&main.session).await; + // A fresh connection after cleanup can also attach to that same process. + let mut recovered = Connection::new(main.session.clone()).await; + let recovered_channel = recovered.attach().await; + let (mut recovered_read, recovered_write) = recovered_channel.split(); + recovered.tasks.push(tokio::spawn(async move { + while recovered_read.wait().await.is_some() {} + })); + recovered_write + .data(&b"typing restored\n"[..]) + .await + .unwrap(); + main.expect_input().await; + assert!(main.session.acquire_input().is_err()); +} + +#[tokio::test] +async fn silent_half_open_relay_releases_canonical_input() { + reconnect_after_cut(RelayMode::Discard, false).await; +} + +#[tokio::test] +async fn output_does_not_keep_a_half_open_relay_alive() { + reconnect_after_cut(RelayMode::Discard, true).await; +} + +#[tokio::test] +async fn stalled_relay_writes_release_canonical_input() { + reconnect_after_cut(RelayMode::Stalled, true).await; +} + +#[tokio::test] +async fn healthy_idle_owner_survives_probes_and_cannot_be_displaced() { + let mut main = CanonicalProcess::new(); + let owner = Connection::new(main.session.clone()).await; + let channel = owner.attach().await; + main.assert_input(&channel).await; + tokio::time::sleep(TEST_INTERVAL * 12).await; + let viewer = Connection::new(main.session.clone()).await; + let mut viewer_channel = viewer.attach().await; + assert_read_only(&mut viewer_channel).await; + viewer_channel.data(&b"ignored\n"[..]).await.unwrap(); + viewer_channel.eof().await.unwrap(); + viewer_channel.close().await.unwrap(); + main.assert_input(&channel).await; + assert!(main.session.acquire_input().is_err()); +} + +#[tokio::test] +async fn explicit_viewer_does_not_acquire_released_input() { + let mut main = CanonicalProcess::new(); + let owner = Connection::new(main.session.clone()).await; + let owner_channel = owner.attach().await; + let viewer = Connection::new(main.session.clone()).await; + let mut channel = viewer.client.channel_open_session().await.unwrap(); + channel + .set_env(true, "OPENSHELL_MAIN_READ_ONLY", "1") + .await + .unwrap(); + assert!(matches!( + next_event(&mut channel).await, + russh::ChannelMsg::Success + )); + channel + .request_subsystem(true, "openshell-main") + .await + .unwrap(); + assert!(matches!( + next_event(&mut channel).await, + russh::ChannelMsg::Success + )); + owner_channel.close().await.unwrap(); + wait_for_release(&main.session).await; + channel.data(&b"ignored\n"[..]).await.unwrap(); + tokio::time::sleep(Duration::from_millis(30)).await; + let fresh = Connection::new(main.session.clone()).await; + let fresh_channel = fresh.attach().await; + main.assert_input(&fresh_channel).await; +} + +#[tokio::test] +async fn waiting_writer_eof_cancels_acquisition() { + let mut main = CanonicalProcess::new(); + let owner = Connection::new(main.session.clone()).await; + let owner_channel = owner.attach().await; + let waiting = Connection::new(main.session.clone()).await; + let mut channel = waiting.attach().await; + assert_read_only(&mut channel).await; + channel.eof().await.unwrap(); + owner_channel.close().await.unwrap(); + wait_for_release(&main.session).await; + channel.data(&b"ignored\n"[..]).await.unwrap(); + tokio::time::sleep(Duration::from_millis(30)).await; + let fresh = Connection::new(main.session.clone()).await; + let fresh_channel = fresh.attach().await; + main.assert_input(&fresh_channel).await; +} + +#[tokio::test] +async fn production_config_probes_before_the_receive_deadline() { + let dir = tempfile::tempdir().unwrap(); + let (_, config, _) = ssh_server_init(&dir.path().join("ssh.sock"), &None, false).unwrap(); + assert_eq!(config.keepalive_interval, Some(Duration::from_secs(15))); + assert_eq!(config.keepalive_max, 3); + assert_eq!(SSH_PEER_TIMEOUT, Duration::from_mins(1)); +} + +#[tokio::test] +async fn waiting_writer_detach_keys_do_not_acquire_released_input() { + for key in [b"\x03".as_slice(), b"\x04", b"\x10\x11"] { + let main = CanonicalProcess::new(); + let owner = Connection::new(main.session.clone()).await; + let owner_channel = owner.attach().await; + let waiting = Connection::new(main.session.clone()).await; + let mut channel = waiting.attach().await; + assert_read_only(&mut channel).await; + owner_channel.close().await.unwrap(); + wait_for_release(&main.session).await; + channel.data(key).await.unwrap(); + loop { + if matches!(next_event(&mut channel).await, russh::ChannelMsg::Close) { + break; + } + } + wait_for_release(&main.session).await; + assert_eq!(main.process.0.load(Ordering::SeqCst), 0); + } +} + +#[tokio::test] +async fn competing_waiting_writers_preserve_exclusive_ownership() { + let mut main = CanonicalProcess::new(); + let owner = Connection::new(main.session.clone()).await; + let owner_channel = owner.attach().await; + let first = Connection::new(main.session.clone()).await; + let mut first_channel = first.attach().await; + assert_read_only(&mut first_channel).await; + let second = Connection::new(main.session.clone()).await; + let mut second_channel = second.attach().await; + assert_read_only(&mut second_channel).await; + owner_channel.close().await.unwrap(); + wait_for_release(&main.session).await; + let (a, b) = tokio::join!( + first_channel.data(&b"a"[..]), + second_channel.data(&b"b"[..]) + ); + a.unwrap(); + b.unwrap(); + let mut winner = [0]; + tokio::time::timeout(WAIT, main.input.read_exact(&mut winner)) + .await + .unwrap() + .unwrap(); + let mut extra = [0]; + assert!( + tokio::time::timeout(Duration::from_millis(30), main.input.read(&mut extra)) + .await + .is_err() + ); + let winning_channel = match winner[0] { + b'a' => { + second_channel.close().await.unwrap(); + first_channel + } + b'b' => { + first_channel.close().await.unwrap(); + second_channel + } + other => panic!("unexpected input: {other}"), + }; + tokio::time::sleep(Duration::from_millis(30)).await; + assert!(main.session.acquire_input().is_err()); + main.assert_input(&winning_channel).await; +} + +#[tokio::test] +async fn detached_waiting_writer_cannot_reacquire_with_pending_output() { + let mut main = CanonicalProcess::new(); + let owner = Connection::new(main.session.clone()).await; + let owner_channel = owner.attach().await; + // The read-only diagnostic exhausts this channel's output window, so + // russh retains the channel while the detach close waits behind output. + let waiting = Connection::with_window(main.session.clone(), Some(0)).await; + let channel = waiting.attach().await; + owner_channel.close().await.unwrap(); + wait_for_release(&main.session).await; + channel.data(&b"\x04"[..]).await.unwrap(); + channel.data(&b"after detach"[..]).await.unwrap(); + let mut received = [0]; + assert!( + tokio::time::timeout(Duration::from_millis(100), main.input.read(&mut received)) + .await + .is_err(), + "detached channel forwarded input: {received:?}" + ); + let (lease, _) = main + .session + .acquire_input() + .expect("detach must cancel pending ownership"); + main.session.release_input(lease); + channel.close().await.unwrap(); + wait_for_release(&main.session).await; +} + +#[tokio::test] +async fn retry_does_not_forward_prefix_typed_before_owner_release() { + let mut main = CanonicalProcess::new(); + let owner = Connection::new(main.session.clone()).await; + let owner_channel = owner.attach().await; + let waiting = Connection::new(main.session.clone()).await; + let mut channel = waiting.attach().await; + assert_read_only(&mut channel).await; + channel.data(&b"\x10"[..]).await.unwrap(); + // A request response on the same SSH channel proves the prefix was + // processed before the original owner releases its lease. + channel.set_env(true, "REVIEW_BARRIER", "1").await.unwrap(); + assert!(matches!( + next_event(&mut channel).await, + russh::ChannelMsg::Success + )); + owner_channel.close().await.unwrap(); + wait_for_release(&main.session).await; + channel.data(&b"z"[..]).await.unwrap(); + let mut received = [0]; + tokio::time::timeout(WAIT, main.input.read_exact(&mut received)) + .await + .unwrap() + .unwrap(); + assert_eq!( + received, + [b'z'], + "retry replayed a prefix typed while stdin was denied" + ); +} + +#[tokio::test] +async fn waiting_writer_split_detach_survives_owner_release() { + let main = CanonicalProcess::new(); + let owner = Connection::new(main.session.clone()).await; + let owner_channel = owner.attach().await; + let waiting = Connection::new(main.session.clone()).await; + let mut channel = waiting.attach().await; + assert_read_only(&mut channel).await; + channel.data(&b"\x10"[..]).await.unwrap(); + channel.set_env(true, "TEST_BARRIER", "1").await.unwrap(); + assert!(matches!( + next_event(&mut channel).await, + russh::ChannelMsg::Success + )); + owner_channel.close().await.unwrap(); + wait_for_release(&main.session).await; + channel.data(&b"\x11"[..]).await.unwrap(); + loop { + if matches!(next_event(&mut channel).await, russh::ChannelMsg::Close) { + break; + } + } + wait_for_release(&main.session).await; + assert_eq!(main.process.0.load(Ordering::SeqCst), 0); +} diff --git a/crates/openshell-supervisor-process/src/supervisor_session.rs b/crates/openshell-supervisor-process/src/supervisor_session.rs index 38a0880764..5be01017eb 100644 --- a/crates/openshell-supervisor-process/src/supervisor_session.rs +++ b/crates/openshell-supervisor-process/src/supervisor_session.rs @@ -522,6 +522,22 @@ pub async fn report_main_process_exit( Ok(()) } +#[cfg(test)] +pub(crate) async fn test_bridge_ssh_relay( + target: tokio::net::UnixStream, + inbound: mpsc::Receiver>, + out_tx: mpsc::Sender, +) { + let _ = bridge_relay( + Box::new(target), + tokio_stream::wrappers::ReceiverStream::new(inbound), + out_tx, + "half-open-test".into(), + Arc::new(AtomicBool::new(false)), + ) + .await; +} + /// Confirm terminal delivery and permit ephemeral cleanup. pub async fn finalize_main_process_exit( endpoint: &str, @@ -687,8 +703,24 @@ async fn handle_relay_open( } Err(e) => return Err(format!("relay_stream RPC failed: {e}").into()), }; - let mut inbound = response.into_inner(); + bridge_relay( + target, + response.into_inner(), + out_tx, + channel_id, + terminating, + ) + .await +} +/// Forward the relay's data frames without interpreting the target protocol. +async fn bridge_relay( + target: Box, + mut inbound: impl tokio_stream::Stream> + Unpin, + out_tx: mpsc::Sender, + channel_id: String, + terminating: Arc, +) -> Result<(), Box> { // Connect to the local SSH daemon on its Unix socket. let (mut target_r, mut target_w) = tokio::io::split(target); diff --git a/crates/openshell-supervisor/src/lib.rs b/crates/openshell-supervisor/src/lib.rs index 3e5632628b..57fedc31bb 100644 --- a/crates/openshell-supervisor/src/lib.rs +++ b/crates/openshell-supervisor/src/lib.rs @@ -2550,7 +2550,7 @@ fn provider_environment_is_installable(reason: ProviderReadinessReason) -> bool fn prepare_provider_environment( provider: &openshell_core::grpc_client::ProviderEnvironmentResult, ) -> Result { - ProviderCredentialState::from_bound_environment( + let prepared = ProviderCredentialState::from_bound_environment( provider.provider_env_revision, provider.environment.clone(), provider.credential_expires_at_ms.clone(), @@ -2558,7 +2558,9 @@ fn prepare_provider_environment( provider.static_credential_bindings.clone(), provider.non_secret_environment_keys.clone(), ) - .map_err(|_| miette::miette!("Provider credential bindings are invalid")) + .map_err(|_| miette::miette!("Provider credential bindings are invalid"))?; + prepared.set_managed_files(provider.files.clone()); + Ok(prepared) } // Retain only the most recent rejection, so A -> B -> A emits all transitions. @@ -3093,6 +3095,7 @@ fn initial_provider_credentials( result.non_secret_environment_keys, ) { Ok(credentials) => { + credentials.set_managed_files(result.files); readiness.credentials_installed(identity, &credentials, expires_at_ms); credentials } @@ -5532,6 +5535,7 @@ network_policies: fn startup_provider(revision: u64) -> openshell_core::grpc_client::ProviderEnvironmentResult { openshell_core::grpc_client::ProviderEnvironmentResult { + files: std::collections::HashMap::new(), provider_env_revision: revision, provider_attachment_epoch: String::new(), policy_hash: String::new(), @@ -5788,6 +5792,7 @@ network_policies: use std::collections::HashMap; let mut result = openshell_core::grpc_client::ProviderEnvironmentResult { + files: HashMap::new(), environment: HashMap::new(), provider_env_revision: revision, provider_attachment_epoch: String::new(), diff --git a/docs/how-it-works/policies/schema.mdx b/docs/how-it-works/policies/schema.mdx index dceb36fa25..2dea2b0829 100644 --- a/docs/how-it-works/policies/schema.mdx +++ b/docs/how-it-works/policies/schema.mdx @@ -203,7 +203,7 @@ network_policies: | `mcp.versions` | list of strings | `["2025-11-25"]` | Allowed MCP revisions. Refer to [MCP Version Selection](#mcp-version-selection). | | `mcp.max_body_bytes` | integer | `65536` | Maximum MCP request body size for inspection. | | `mcp.strict_tool_names` | bool | `true` | Requires tool names to match `^[A-Za-z0-9_.-]{1,128}$`. | -| `mcp.allow_all_known_mcp_methods` | bool | `false` | When `true`, the endpoint allows every core MCP method available in the request's revision, except those that deny rules match. An extension method still needs an allow rule that names it exactly. If rules name specific tools, `tools/call` is limited to those tools. Rules can omit `method`. Refer to [MCP Rules](#mcp-rules). | +| `mcp.allow_all_known_mcp_methods` | bool | `false` | Allow core MCP methods for the selected request revision. Tool restrictions still apply, and deny rules take precedence. Refer to [Allow Core MCP Methods](#allow-core-mcp-methods) for the behavior and [Core MCP Methods](#core-mcp-methods) for the method list. | | `json_rpc.max_body_bytes` | integer | `65536` | Maximum JSON-RPC request body size for inspection. | #### Endpoint Constraints @@ -351,8 +351,7 @@ matcher fields in one rule. Method globs and `mcp.allow_all_known_mcp_methods` do not. An extension method is one that no supported MCP revision defines. -Under the 2025 revisions, a client sends `initialize` and -`notifications/initialized` before calling tools, so allow both: +Under the 2025 revisions, a client sends `initialize` and `notifications/initialized` before calling tools. When `mcp.allow_all_known_mcp_methods` is omitted or `false`, allow both explicitly: ```yaml showLineNumbers={false} rules: @@ -378,6 +377,51 @@ but the request's revision does not, such as `server/discover` under `invalid_mcp_request`, even on an endpoint that uses `enforcement: audit`. These type checks are not complete JSON Schema validation. +#### Allow Core MCP Methods + +Set `mcp.allow_all_known_mcp_methods: true` to allow the [core methods](#core-mcp-methods) available in each request's [selected MCP revision](#mcp-version-selection). A policy that accepts several revisions still checks each request against its own revision. The option does not combine their method sets. + +Tool-specific allow rules continue to restrict `tools/call` to matching names, and deny rules take precedence over every allow. Without tool-specific allow rules, this option allows calls to every tool name, subject to deny rules and tool-name validation. Extension methods require an allow rule that names the method exactly. An explicit allow rule cannot enable a core method that is unavailable in the selected revision. + +For example, this endpoint allows core methods for `2025-11-25`, while limiting tool calls to `search_web` and `read_document`: + +```yaml showLineNumbers={false} +endpoints: + - host: mcp.example.com + port: 443 + protocol: mcp + enforcement: enforce + mcp: + versions: ["2025-11-25"] + allow_all_known_mcp_methods: true + rules: + - allow: + tool: + any: [search_web, read_document] +``` + +Here, `tools/call` is the JSON-RPC method, and `search_web` is the tool name in `params.name`. Allowing a method does not establish that the server supports it or that a tool is read-only. + +#### Core MCP Methods + +The following list covers client-to-server requests and notifications that OpenShell inspects over HTTP. Server-to-client methods, such as `sampling/createMessage`, `roots/list`, and `elicitation/create`, are outside this inspection. Each row lists the revisions that accept those methods over HTTP in the client-to-server direction. + +| Methods or notifications | MCP revisions | +|---|---| +| `tools/list`, `tools/call` | All supported revisions. | +| `resources/list`, `resources/templates/list`, `resources/read` | All supported revisions. | +| `prompts/list`, `prompts/get`, `completion/complete` | All supported revisions. | +| `notifications/cancelled` | `2025-03-26`, `2025-06-18`, `2025-11-25`. | +| `initialize`, `ping`, `logging/setLevel` | `2025-03-26`, `2025-06-18`, `2025-11-25`. | +| `resources/subscribe`, `resources/unsubscribe` | `2025-03-26`, `2025-06-18`, `2025-11-25`. | +| `notifications/initialized`, `notifications/progress`, `notifications/roots/list_changed` | `2025-03-26`, `2025-06-18`, `2025-11-25`. | +| `tasks/get`, `tasks/result`, `tasks/list`, `tasks/cancel`, `notifications/tasks/status` | `2025-11-25` only; experimental. | +| `server/discover`, `subscriptions/listen` | `2026-07-28` only. | + +For `2026-07-28` HTTP requests, cancel a request by closing its response stream. OpenShell rejects `notifications/cancelled` over HTTP in that revision. + +MCP introduced [tasks](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks) as an experimental feature in `2025-11-25`, so the March and June 2025 revisions do not include the task methods or `notifications/tasks/status`. The default policy revision includes them, but using tasks also requires the peer's task capabilities and, for task-augmented tool calls, the tool's task-support declaration. The policy option does not negotiate these capabilities. + #### MCP Version Selection `mcp.versions` lists the MCP revisions an endpoint accepts: `2025-03-26`, @@ -408,6 +452,16 @@ rejects `initialize`. For a client that requires an unsupported revision, omit `protocol` and `mcp` to allow its traffic without MCP inspection. +#### Understand MCP Rejections + +Use the response's error code and detail to distinguish a protocol problem from a policy denial: + +- `unsupported_mcp_protocol_version` (`400`) means this OpenShell build does not support the header's revision. Configure the client to use a revision that OpenShell and the server support and that `mcp.versions` permits. +- `mcp_protocol_version_not_allowed` (`403`) means the selected revision is supported but excluded by the endpoint policy. Use a compatible revision the policy permits, or ask the policy owner to review `mcp.versions`. +- A detail that names the missing-header fallback means OpenShell selected `2025-03-26`, even if the policy defaults to `2025-11-25`. Send the client/server revision explicitly in `MCP-Protocol-Version`; the policy must permit it. +- `invalid_mcp_request` (`400`) can mean the method is unavailable in the selected revision. For example, `tasks/get` is unavailable in `2025-06-18`. Use a method available in that revision, or configure the client and server to use a compatible revision that includes it and is permitted by policy. Adding an allow rule or enabling `allow_all_known_mcp_methods` cannot override this protocol check. +- A rule denial (`403` under `enforcement: enforce`) requires a policy review. An extension method needs an exact method allow rule; a denied tool call may need a matching tool selector. An explicit deny rule takes precedence, so adding an allow rule cannot override it. Ask the policy owner to review the relevant allow or deny rule. + #### Sessionless MCP Requests The `2026-07-28` revision has no `initialize` handshake or session. Each request diff --git a/docs/how-it-works/providers/profiles.mdx b/docs/how-it-works/providers/profiles.mdx index f28124c82c..11c5438d3c 100644 --- a/docs/how-it-works/providers/profiles.mdx +++ b/docs/how-it-works/providers/profiles.mdx @@ -238,6 +238,8 @@ openshell profile describe github -o yaml The description shows metadata, credential names and authentication settings, endpoints with their protocols and policy rule counts, allowed binaries, source, and scope. Endpoint details include TLS handling, permission for uninspected credential traffic, and MCP method and tool-name settings. A `tls: skip` endpoint is shown as a raw tunnel without L7 inspection or credential rewrite, even when it declares an L7 protocol and rules. Use JSON or YAML output to inspect the complete rule definitions. The description reads the reusable definition without reading credential values from provider instances. A missing profile ID returns an error. +For MCP endpoints, the text output labels `allow_all_known_mcp_methods` as `Allow core MCP methods for the selected revision` and shows the profile's declared revisions. These are configuration values; `describe` does not observe a connection or its negotiated capabilities. At request time, OpenShell selects the revision from `MCP-Protocol-Version`, or uses `2025-03-26` when the header is absent. Legacy standalone `initialize` requests negotiate their revision in the body, as described in [MCP version selection](/how-it-works/policies/schema#mcp-version-selection). The option allows [core methods for that revision](/how-it-works/policies/schema#core-mcp-methods), subject to tool restrictions and deny rules. Without tool-specific allow rules, it allows every tool name, subject to deny rules and tool-name validation. Extension methods still require an exact allow rule. JSON and YAML output retain the `allow_all_known_mcp_methods` field name. + List and describe use the selected workspace's effective catalog. Pass the inherited `--workspace` flag to select another workspace, or `--global` to target platform scope. Platform operations require Platform Admin access. ```shell diff --git a/docs/how-it-works/sandboxes/overview.mdx b/docs/how-it-works/sandboxes/overview.mdx index b20756c2e3..09f2e65fa8 100644 --- a/docs/how-it-works/sandboxes/overview.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -278,6 +278,10 @@ process. It retries transient transport failures for up to 60 seconds. Initial authentication failures, sandbox lifecycle changes, and clean SSH exits are not retried. +The supervisor sends SSH keepalive probes after 15 seconds without inbound traffic and closes a connection after 60 seconds without receiving peer bytes, including when relay writes are stalled. Healthy idle clients answer these probes and stay attached. The timeout starts when the supervisor last reads peer bytes; relay buffering and scheduling can delay detection after physical network loss. The canonical process keeps running when its dead attachment closes. + +If recovery reaches the sandbox before the old connection releases stdin, the replacement reports `attached read-only`. After the old connection times out, type again: the replacement acquires stdin if it is available, reports `input enabled`, and forwards that new input. Keystrokes sent while another attachment owned stdin are discarded. An explicitly read-only attachment stays read-only, and recovery never displaces a healthy input owner. + `Ctrl-C` retains its normal terminal behavior and interrupts the foreground process. For read-only attachments, `Ctrl-C` or `Ctrl-D` exits only the current viewer. diff --git a/e2e/rust/Cargo.toml b/e2e/rust/Cargo.toml index 4d15f09d20..492c7c4c2d 100644 --- a/e2e/rust/Cargo.toml +++ b/e2e/rust/Cargo.toml @@ -43,6 +43,11 @@ name = "policy_activation" path = "tests/policy_activation.rs" required-features = ["e2e-docker"] +[[test]] +name = "provider_files" +path = "tests/provider_files.rs" +required-features = ["e2e-docker"] + [[test]] name = "oidc_pkce" path = "tests/oidc_pkce.rs" diff --git a/e2e/rust/tests/provider_files.rs b/e2e/rust/tests/provider_files.rs new file mode 100644 index 0000000000..c2779fe097 --- /dev/null +++ b/e2e/rust/tests/provider_files.rs @@ -0,0 +1,159 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![cfg(feature = "e2e-docker")] + +//! A provider profile serves read-only config on each workload open. + +use std::io::Write as _; +use std::process::Stdio; +use std::time::Duration; + +use openshell_e2e::harness::binary::openshell_bin; +use openshell_e2e::harness::cli::run_cli; +use openshell_e2e::harness::sandbox::SandboxGuard; +use tokio::time::sleep; + +struct ProviderGuard { + profile: String, + provider: String, +} + +impl Drop for ProviderGuard { + fn drop(&mut self) { + let binary = openshell_bin(); + for _ in 0..20 { + let deleted = std::process::Command::new(&binary) + .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(&binary) + .args(["profile", "delete", &self.profile]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status(); + } +} + +async fn cli_ok(args: &[&str]) -> Result<(), String> { + let (output, code) = run_cli(args).await; + if code == 0 { + Ok(()) + } else { + Err(format!( + "{} failed (exit {code}):\n{output}", + args.join(" ") + )) + } +} + +#[tokio::test] +async fn provider_file_open_update_and_detach() -> Result<(), String> { + let suffix = format!("{}-{:08x}", std::process::id(), rand::random::()); + let profile_id = format!("pf-{suffix}"); + let provider = format!("pf-{suffix}"); + let profile_yaml = include_str!("../../../examples/provider-managed-files/acme-config.yaml") + .replace("id: acme-config", &format!("id: {profile_id}")); + let mut profile_file = tempfile::Builder::new() + .suffix(".yaml") + .tempfile() + .map_err(|error| error.to_string())?; + profile_file + .write_all(profile_yaml.as_bytes()) + .map_err(|error| error.to_string())?; + cli_ok(&[ + "profile", + "import", + "--file", + profile_file + .path() + .to_str() + .ok_or("profile path is not UTF-8")?, + ]) + .await?; + let _provider_guard = ProviderGuard { + profile: profile_id.clone(), + provider: provider.clone(), + }; + cli_ok(&[ + "provider", + "create", + "--name", + &provider, + "--type", + &profile_id, + "--config", + "endpoint=https://api.acme.example", + "--config", + "project=production", + ]) + .await?; + + let mut sandbox = SandboxGuard::create(&["--provider", &provider, "--no-tty"]).await?; + let path = format!("/run/openshell/providers/{provider}/client.toml"); + let environment_path = sandbox.exec(&["printenv", "ACME_CONFIG_FILE"]).await?; + if !environment_path.contains(&path) { + return Err(format!( + "provider path environment variable missing: {environment_path}" + )); + } + let before = sandbox.exec(&["cat", &path]).await?; + if !before.contains("project = \"production\"") { + return Err(format!("initial provider file content missing:\n{before}")); + } + + cli_ok(&[ + "provider", + "update", + &provider, + "--config", + "project=staging", + "--wait", + "--timeout", + "90", + ]) + .await?; + let after = sandbox.exec(&["cat", &path]).await?; + if !after.contains("project = \"staging\"") { + return Err(format!("updated provider file content missing:\n{after}")); + } + + cli_ok(&[ + "sandbox", + "provider", + "detach", + &sandbox.name, + &provider, + "--wait", + "--timeout", + "90", + ]) + .await?; + let (detached, code) = run_cli(&[ + "sandbox", + "exec", + "--name", + &sandbox.name, + "--no-tty", + "--", + "cat", + &path, + ]) + .await; + if code == 0 || !detached.contains("No such file or directory") { + return Err(format!( + "detached provider path remained readable: {detached}" + )); + } + sandbox.cleanup().await; + // Let the asynchronous sandbox deletion release the provider before + // ProviderGuard removes the provider record and its profile. + sleep(Duration::from_millis(250)).await; + Ok(()) +} diff --git a/examples/provider-managed-files/acme-config.yaml b/examples/provider-managed-files/acme-config.yaml new file mode 100644 index 0000000000..59919575f5 --- /dev/null +++ b/examples/provider-managed-files/acme-config.yaml @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +id: acme-config +display_name: Acme client configuration +description: Non-secret settings installed as a managed sandbox file +category: other +files: + - path: client.toml + env_var: ACME_CONFIG_FILE + content: | + endpoint = "{{config.endpoint}}" + project = "{{config.project}}" diff --git a/proto/openshell.proto b/proto/openshell.proto index 4323277886..0eaf469f83 100644 --- a/proto/openshell.proto +++ b/proto/openshell.proto @@ -2480,6 +2480,19 @@ message ProviderProfile { // Server-set visibility: "platform", "workspace", or empty for // non-scoped sources. Ignored on import/update payloads. string scope = 13; + // EXPERIMENTAL: Non-secret files rendered from provider configuration for the + // workload. This API and its behavior may change or be removed. + repeated ProviderProfileFile files = 14; +} + +// EXPERIMENTAL: Provider file templates may change or be removed. +message ProviderProfileFile { + // One virtual file name below /run/openshell/providers//. + string path = 1; + // UTF-8 template. Only {{config.KEY}} references are supported. + string content = 2; + // Optional environment variable containing the virtual absolute path. + string env_var = 3; } // Provider profile response. @@ -2633,6 +2646,8 @@ message GetSandboxProviderEnvironmentResponse { string policy_hash = 8; // Nonzero when material was withheld; installing an empty map is not readiness. ProviderReadinessReason readiness_reason = 9; + // Complete desired set of non-secret managed files, keyed by absolute path. + map files = 10; } message ExchangeProviderSubjectTokenRequest { diff --git a/providers/oci-genai.yaml b/providers/oci-genai.yaml new file mode 100644 index 0000000000..fc48abb203 --- /dev/null +++ b/providers/oci-genai.yaml @@ -0,0 +1,93 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# Example provider profile. OpenShell does not load it; import it explicitly: +# openshell provider profile lint -f providers/oci-genai.yaml +# openshell provider profile import -f providers/oci-genai.yaml --global +# +# Copy and edit this file rather than importing it unchanged. `binaries` is the +# least-privilege control that decides which processes may reach the endpoints +# below, so it has to name the paths in *your* image. +# +# Client binaries: curl. Add the interpreter or agent CLI that calls the +# OpenAI-compatible endpoint (python, node, ...) before +# relying on binary-scoped attribution for this profile. +# Reference layout: any image with curl or an OpenAI SDK. Point the SDK at +# https://inference.generativeai..oci.oraclecloud.com/openai/v1 +# and pass OCI_GENAI_API_KEY as the API key; the sandbox +# proxy resolves the placeholder only at the hosts below. +# Credential scope: one OCI Generative AI API key (sk-...). The key is scoped +# to the compartment it was created in, so requests need no +# opc-compartment-id header and the sandbox never learns a +# compartment OCID. +# Endpoint access: the regional OCI Generative AI inference hosts in the +# commercial realm (oraclecloud.com), TLS terminated, L7 +# enforced, limited to the OpenAI-compatible /openai/v1 +# surface with GET, POST, and DELETE. Generative AI API keys +# are only valid there; the native /20231130 API needs OCI +# request signing, which this profile does not grant. +# Smoke test: openshell sandbox create --provider -- \ +# curl -sS --compressed \ +# https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/openai/v1/chat/completions \ +# -H "Authorization: Bearer $OCI_GENAI_API_KEY" \ +# -H 'Content-Type: application/json' \ +# -d '{"model":"meta.llama-3.3-70b-instruct","messages":[{"role":"user","content":"Reply with OK"}]}' +# +# OCI-side setup, in this order: +# 1. Create the IAM policy BEFORE the key. A key minted before its policy can +# stay unauthorized long after the policy lands, and OCI returns the same +# 401 for an unknown key and an unauthorized one. Least privilege: +# allow any-user to use generative-ai-family in compartment id +# where ALL {request.principal.type='generativeaiapikey'} +# Pin it to one key later by adding request.principal.id=''. +# 2. Create the key in that compartment and region, with an expiry: +# oci generative-ai api-key create --compartment-id \ +# --region us-chicago-1 --display-name openshell-agents \ +# --key-details '[{"keyName":"primary","timeExpiry":"2027-01-01T00:00:00Z"}]' +# The sk-... secret is returned once. Rotate with `api-key renew`, +# disable with `api-key set-api-key-state`; sandboxes are unaffected +# because the gateway, not the sandbox, holds the value. +# 3. openshell provider create --name my-oci-genai --type oci-genai \ +# --credential OCI_GENAI_API_KEY="$OCI_GENAI_API_KEY" +# +# Verified through the sandbox proxy with this profile: chat completions with +# stream=true, tool calling, vision input via data: URLs (for example +# meta.llama-4-maverick-17b-128e-instruct-fp8 and google.gemini-2.5-flash, +# including a 263 KB request body), embeddings with openai.text-embedding-3-small, +# and the Responses API with stream=true. Model ids use the OCI form, such as +# meta.llama-3.3-70b-instruct or openai.gpt-oss-120b. Expect from OCI, not from +# the proxy: 404 "Entity with key not found" for models not served on +# this endpoint, 404 on GET /openai/v1/models (not a health check), and +# 400 "Unsupported OpenAI operation" for Cohere embeddings. +# +# Other realms use their realm domain instead of oraclecloud.com: copy the +# profile and add a matching endpoint entry. Signed OCI transports (API key +# signing, security token, instance/resource principal, OKE workload identity) +# need proxy-side request signing; see https://github.com/NVIDIA/OpenShell/issues/3879. + +id: oci-genai +display_name: OCI Generative AI +description: OCI Generative AI inference through the OpenAI-compatible endpoint with a compartment-scoped Generative AI API key +category: inference +inference_capable: true +credentials: + - name: api_key + description: OCI Generative AI API key (compartment-scoped, sent as a bearer token) + env_vars: [OCI_GENAI_API_KEY] + required: true + auth_style: bearer + header_name: authorization +discovery: + credentials: [api_key] +endpoints: + # `*` matches exactly one DNS label, which is the region identifier, for + # example us-chicago-1, eu-frankfurt-1, or ap-osaka-1. + - host: "inference.generativeai.*.oci.oraclecloud.com" + port: 443 + protocol: rest + enforcement: enforce + rules: + - allow: { method: POST, path: "/openai/v1/**" } + - allow: { method: GET, path: "/openai/v1/**" } + - allow: { method: DELETE, path: "/openai/v1/**" } +binaries: [/usr/bin/curl, /usr/local/bin/curl] diff --git a/sdk/go/openshell/v1/internal/converter/coverage_test.go b/sdk/go/openshell/v1/internal/converter/coverage_test.go index 85342ce387..43577d61d0 100644 --- a/sdk/go/openshell/v1/internal/converter/coverage_test.go +++ b/sdk/go/openshell/v1/internal/converter/coverage_test.go @@ -308,6 +308,7 @@ func TestConverterCoversAllProtoFields_ProviderProfile(t *testing.T) { "description": true, "category": true, "credentials": true, + "files": true, "endpoints": true, "binaries": true, "inference_capable": true, diff --git a/sdk/go/openshell/v1/internal/converter/profile.go b/sdk/go/openshell/v1/internal/converter/profile.go index 12be9618b8..9ef58e8057 100644 --- a/sdk/go/openshell/v1/internal/converter/profile.go +++ b/sdk/go/openshell/v1/internal/converter/profile.go @@ -363,6 +363,18 @@ func ProviderProfileFromProto(p *pb.ProviderProfile) *types.ProviderProfile { } } + // Files + if files := p.GetFiles(); len(files) > 0 { + result.Files = make([]types.ProfileFile, len(files)) + for i, file := range files { + if file != nil { + result.Files[i] = types.ProfileFile{ + Path: file.GetPath(), Content: file.GetContent(), EnvVar: file.GetEnvVar(), + } + } + } + } + // Endpoints if eps := p.GetEndpoints(); len(eps) > 0 { result.Endpoints = make([]types.NetworkEndpoint, len(eps)) @@ -419,6 +431,16 @@ func ProviderProfileToProto(p *types.ProviderProfile) *pb.ProviderProfile { } } + // Files + if len(p.Files) > 0 { + result.Files = make([]*pb.ProviderProfileFile, len(p.Files)) + for i, file := range p.Files { + result.Files[i] = &pb.ProviderProfileFile{ + Path: file.Path, Content: file.Content, EnvVar: file.EnvVar, + } + } + } + // Endpoints if len(p.Endpoints) > 0 { result.Endpoints = make([]*sbv1.NetworkEndpoint, len(p.Endpoints)) diff --git a/sdk/go/openshell/v1/internal/converter/profile_test.go b/sdk/go/openshell/v1/internal/converter/profile_test.go index 162542d1a0..e1aaf0af75 100644 --- a/sdk/go/openshell/v1/internal/converter/profile_test.go +++ b/sdk/go/openshell/v1/internal/converter/profile_test.go @@ -470,6 +470,9 @@ func TestProviderProfileFromProto(t *testing.T) { Credentials: []*pb.ProviderProfileCredential{ {Name: "API_KEY", Description: "key", Required: true}, }, + Files: []*pb.ProviderProfileFile{ + {Path: "client.toml", Content: "project = \"{{config.project}}\"", EnvVar: "CLIENT_CONFIG"}, + }, Endpoints: []*sbv1.NetworkEndpoint{ {Host: "api.anthropic.com", Port: 443, Protocol: "rest"}, }, @@ -502,6 +505,9 @@ func TestProviderProfileFromProto(t *testing.T) { require.Len(t, profile.Credentials, 1) assert.Equal(t, "API_KEY", profile.Credentials[0].Name) assert.True(t, profile.Credentials[0].Required) + require.Len(t, profile.Files, 1) + assert.Equal(t, "client.toml", profile.Files[0].Path) + assert.Equal(t, "CLIENT_CONFIG", profile.Files[0].EnvVar) require.Len(t, profile.Endpoints, 1) assert.Equal(t, "api.anthropic.com", profile.Endpoints[0].Host) @@ -514,6 +520,8 @@ func TestProviderProfileFromProto(t *testing.T) { proto.Annotations["env"] = "MUTATED" assert.Equal(t, "prod", profile.Annotations["env"], "annotations must be deep copied") + proto.Files[0].Content = "changed" + assert.Equal(t, "project = \"{{config.project}}\"", profile.Files[0].Content) } func TestProviderProfileFromProto_NilDiscovery(t *testing.T) { @@ -541,6 +549,9 @@ func TestProviderProfileToProto(t *testing.T) { Credentials: []v1.ProfileCredential{ {Name: "API_KEY", Description: "key", Required: true, Secret: true}, }, + Files: []v1.ProfileFile{ + {Path: "client.toml", Content: "project = \"{{config.project}}\"", EnvVar: "CLIENT_CONFIG"}, + }, Endpoints: []v1.NetworkEndpoint{ {Host: "api.anthropic.com", Port: 443, Protocol: "rest"}, }, @@ -572,6 +583,8 @@ func TestProviderProfileToProto(t *testing.T) { require.Len(t, proto.Credentials, 1) assert.Equal(t, "API_KEY", proto.Credentials[0].Name) + require.Len(t, proto.Files, 1) + assert.Equal(t, "client.toml", proto.Files[0].Path) require.Len(t, proto.Endpoints, 1) assert.Equal(t, "api.anthropic.com", proto.Endpoints[0].Host) @@ -584,6 +597,8 @@ func TestProviderProfileToProto(t *testing.T) { profile.Annotations["env"] = "MUTATED" assert.Equal(t, "prod", proto.Annotations["env"], "annotations must be deep copied") + profile.Files[0].Content = "changed" + assert.Equal(t, "project = \"{{config.project}}\"", proto.Files[0].Content) } func TestProviderProfileToProto_Nil(t *testing.T) { @@ -670,6 +685,9 @@ func TestProviderProfileRoundTrip(t *testing.T) { }, }, }, + Files: []v1.ProfileFile{ + {Path: "client.toml", Content: "project = \"{{config.project}}\"", EnvVar: "CLIENT_CONFIG"}, + }, Endpoints: []v1.NetworkEndpoint{ {Host: "agent.example.com", Port: 8080, Protocol: "websocket"}, }, @@ -699,6 +717,7 @@ func TestProviderProfileRoundTrip(t *testing.T) { assert.Equal(t, original.Annotations, back.Annotations) assert.Equal(t, original.Source, back.Source) assert.Equal(t, original.Scope, back.Scope) + assert.Equal(t, original.Files, back.Files) require.Len(t, back.Credentials, 1) c := back.Credentials[0] diff --git a/sdk/go/openshell/v1/types/profile.go b/sdk/go/openshell/v1/types/profile.go index b7834d2ab0..fdffd2bfe6 100644 --- a/sdk/go/openshell/v1/types/profile.go +++ b/sdk/go/openshell/v1/types/profile.go @@ -18,13 +18,15 @@ const ( ) // ProviderProfile defines a provider type template with credentials schema, -// endpoints, binaries, and discovery configuration. +// files, endpoints, binaries, and discovery configuration. type ProviderProfile struct { - ID string - DisplayName string - Description string - Category ProfileCategory - Credentials []ProfileCredential + ID string + DisplayName string + Description string + Category ProfileCategory + Credentials []ProfileCredential + // Files is EXPERIMENTAL. This API and its behavior may change or be removed. + Files []ProfileFile Endpoints []NetworkEndpoint Binaries []NetworkBinary InferenceCapable bool @@ -35,6 +37,14 @@ type ProviderProfile struct { Scope string } +// ProfileFile declares non-secret content served at a virtual sandbox path. +// EXPERIMENTAL: This API and its behavior may change or be removed. +type ProfileFile struct { + Path string + Content string + EnvVar string +} + // ProfileCredential defines a single credential required by a provider profile. type ProfileCredential struct { Name string diff --git a/sdk/go/proto/openshellv1/openshell.pb.go b/sdk/go/proto/openshellv1/openshell.pb.go index 6e1519314d..f4258a87b6 100644 --- a/sdk/go/proto/openshellv1/openshell.pb.go +++ b/sdk/go/proto/openshellv1/openshell.pb.go @@ -10066,7 +10066,10 @@ type ProviderProfile struct { Source string `protobuf:"bytes,12,opt,name=source,proto3" json:"source,omitempty"` // Server-set visibility: "platform", "workspace", or empty for // non-scoped sources. Ignored on import/update payloads. - Scope string `protobuf:"bytes,13,opt,name=scope,proto3" json:"scope,omitempty"` + Scope string `protobuf:"bytes,13,opt,name=scope,proto3" json:"scope,omitempty"` + // EXPERIMENTAL: Non-secret files rendered from provider configuration for the + // workload. This API and its behavior may change or be removed. + Files []*ProviderProfileFile `protobuf:"bytes,14,rep,name=files,proto3" json:"files,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -10192,6 +10195,77 @@ func (x *ProviderProfile) GetScope() string { return "" } +func (x *ProviderProfile) GetFiles() []*ProviderProfileFile { + if x != nil { + return x.Files + } + return nil +} + +// EXPERIMENTAL: Provider file templates may change or be removed. +type ProviderProfileFile struct { + state protoimpl.MessageState `protogen:"open.v1"` + // One virtual file name below /run/openshell/providers//. + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + // UTF-8 template. Only {{config.KEY}} references are supported. + Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` + // Optional environment variable containing the virtual absolute path. + EnvVar string `protobuf:"bytes,3,opt,name=env_var,json=envVar,proto3" json:"env_var,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProviderProfileFile) Reset() { + *x = ProviderProfileFile{} + mi := &file_openshell_proto_msgTypes[122] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProviderProfileFile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProviderProfileFile) ProtoMessage() {} + +func (x *ProviderProfileFile) ProtoReflect() protoreflect.Message { + mi := &file_openshell_proto_msgTypes[122] + 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 ProviderProfileFile.ProtoReflect.Descriptor instead. +func (*ProviderProfileFile) Descriptor() ([]byte, []int) { + return file_openshell_proto_rawDescGZIP(), []int{122} +} + +func (x *ProviderProfileFile) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *ProviderProfileFile) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *ProviderProfileFile) GetEnvVar() string { + if x != nil { + return x.EnvVar + } + return "" +} + // Provider profile response. type ProviderProfileResponse struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -10202,7 +10276,7 @@ type ProviderProfileResponse struct { func (x *ProviderProfileResponse) Reset() { *x = ProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10214,7 +10288,7 @@ func (x *ProviderProfileResponse) String() string { func (*ProviderProfileResponse) ProtoMessage() {} func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[122] + mi := &file_openshell_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10227,7 +10301,7 @@ func (x *ProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProviderProfileResponse.ProtoReflect.Descriptor instead. func (*ProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{122} + return file_openshell_proto_rawDescGZIP(), []int{123} } func (x *ProviderProfileResponse) GetProfile() *ProviderProfile { @@ -10249,7 +10323,7 @@ type ListProviderProfilesResponse struct { func (x *ListProviderProfilesResponse) Reset() { *x = ListProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10261,7 +10335,7 @@ func (x *ListProviderProfilesResponse) String() string { func (*ListProviderProfilesResponse) ProtoMessage() {} func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[123] + mi := &file_openshell_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10274,7 +10348,7 @@ func (x *ListProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ListProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{123} + return file_openshell_proto_rawDescGZIP(), []int{124} } func (x *ListProviderProfilesResponse) GetProfiles() []*ProviderProfile { @@ -10306,7 +10380,7 @@ type ImportProviderProfilesRequest struct { func (x *ImportProviderProfilesRequest) Reset() { *x = ImportProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10318,7 +10392,7 @@ func (x *ImportProviderProfilesRequest) String() string { func (*ImportProviderProfilesRequest) ProtoMessage() {} func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[124] + mi := &file_openshell_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10331,7 +10405,7 @@ func (x *ImportProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{124} + return file_openshell_proto_rawDescGZIP(), []int{125} } func (x *ImportProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10367,7 +10441,7 @@ type ImportProviderProfilesResponse struct { func (x *ImportProviderProfilesResponse) Reset() { *x = ImportProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10379,7 +10453,7 @@ func (x *ImportProviderProfilesResponse) String() string { func (*ImportProviderProfilesResponse) ProtoMessage() {} func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[125] + mi := &file_openshell_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10392,7 +10466,7 @@ func (x *ImportProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*ImportProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{125} + return file_openshell_proto_rawDescGZIP(), []int{126} } func (x *ImportProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -10438,7 +10512,7 @@ type UpdateProviderProfilesRequest struct { func (x *UpdateProviderProfilesRequest) Reset() { *x = UpdateProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10450,7 +10524,7 @@ func (x *UpdateProviderProfilesRequest) String() string { func (*UpdateProviderProfilesRequest) ProtoMessage() {} func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[126] + mi := &file_openshell_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10463,7 +10537,7 @@ func (x *UpdateProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{126} + return file_openshell_proto_rawDescGZIP(), []int{127} } func (x *UpdateProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10513,7 +10587,7 @@ type UpdateProviderProfilesResponse struct { func (x *UpdateProviderProfilesResponse) Reset() { *x = UpdateProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10525,7 +10599,7 @@ func (x *UpdateProviderProfilesResponse) String() string { func (*UpdateProviderProfilesResponse) ProtoMessage() {} func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[127] + mi := &file_openshell_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10538,7 +10612,7 @@ func (x *UpdateProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*UpdateProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{127} + return file_openshell_proto_rawDescGZIP(), []int{128} } func (x *UpdateProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -10574,7 +10648,7 @@ type LintProviderProfilesRequest struct { func (x *LintProviderProfilesRequest) Reset() { *x = LintProviderProfilesRequest{} - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10586,7 +10660,7 @@ func (x *LintProviderProfilesRequest) String() string { func (*LintProviderProfilesRequest) ProtoMessage() {} func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[128] + mi := &file_openshell_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10599,7 +10673,7 @@ func (x *LintProviderProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesRequest.ProtoReflect.Descriptor instead. func (*LintProviderProfilesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{128} + return file_openshell_proto_rawDescGZIP(), []int{129} } func (x *LintProviderProfilesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10627,7 +10701,7 @@ type LintProviderProfilesResponse struct { func (x *LintProviderProfilesResponse) Reset() { *x = LintProviderProfilesResponse{} - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10639,7 +10713,7 @@ func (x *LintProviderProfilesResponse) String() string { func (*LintProviderProfilesResponse) ProtoMessage() {} func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[129] + mi := &file_openshell_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10652,7 +10726,7 @@ func (x *LintProviderProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LintProviderProfilesResponse.ProtoReflect.Descriptor instead. func (*LintProviderProfilesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{129} + return file_openshell_proto_rawDescGZIP(), []int{130} } func (x *LintProviderProfilesResponse) GetDiagnostics() []*ProviderProfileDiagnostic { @@ -10679,7 +10753,7 @@ type DeleteProviderResponse struct { func (x *DeleteProviderResponse) Reset() { *x = DeleteProviderResponse{} - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10691,7 +10765,7 @@ func (x *DeleteProviderResponse) String() string { func (*DeleteProviderResponse) ProtoMessage() {} func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[130] + mi := &file_openshell_proto_msgTypes[131] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10704,7 +10778,7 @@ func (x *DeleteProviderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{130} + return file_openshell_proto_rawDescGZIP(), []int{131} } func (x *DeleteProviderResponse) GetOutcome() DeletionOutcome { @@ -10730,7 +10804,7 @@ type DeleteProviderProfileRequest struct { func (x *DeleteProviderProfileRequest) Reset() { *x = DeleteProviderProfileRequest{} - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10742,7 +10816,7 @@ func (x *DeleteProviderProfileRequest) String() string { func (*DeleteProviderProfileRequest) ProtoMessage() {} func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[131] + mi := &file_openshell_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10755,7 +10829,7 @@ func (x *DeleteProviderProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileRequest.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{131} + return file_openshell_proto_rawDescGZIP(), []int{132} } func (x *DeleteProviderProfileRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -10796,7 +10870,7 @@ type DeleteProviderProfileResponse struct { func (x *DeleteProviderProfileResponse) Reset() { *x = DeleteProviderProfileResponse{} - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10808,7 +10882,7 @@ func (x *DeleteProviderProfileResponse) String() string { func (*DeleteProviderProfileResponse) ProtoMessage() {} func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[132] + mi := &file_openshell_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10821,7 +10895,7 @@ func (x *DeleteProviderProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteProviderProfileResponse.ProtoReflect.Descriptor instead. func (*DeleteProviderProfileResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{132} + return file_openshell_proto_rawDescGZIP(), []int{133} } func (x *DeleteProviderProfileResponse) GetOutcome() DeletionOutcome { @@ -10846,7 +10920,7 @@ type GetSandboxProviderEnvironmentRequest struct { func (x *GetSandboxProviderEnvironmentRequest) Reset() { *x = GetSandboxProviderEnvironmentRequest{} - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10858,7 +10932,7 @@ func (x *GetSandboxProviderEnvironmentRequest) String() string { func (*GetSandboxProviderEnvironmentRequest) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[133] + mi := &file_openshell_proto_msgTypes[134] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10871,7 +10945,7 @@ func (x *GetSandboxProviderEnvironmentRequest) ProtoReflect() protoreflect.Messa // Deprecated: Use GetSandboxProviderEnvironmentRequest.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{133} + return file_openshell_proto_rawDescGZIP(), []int{134} } func (x *GetSandboxProviderEnvironmentRequest) GetSandboxId() string { @@ -10900,7 +10974,7 @@ type StaticCredentialEndpointBinding struct { func (x *StaticCredentialEndpointBinding) Reset() { *x = StaticCredentialEndpointBinding{} - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10912,7 +10986,7 @@ func (x *StaticCredentialEndpointBinding) String() string { func (*StaticCredentialEndpointBinding) ProtoMessage() {} func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[134] + mi := &file_openshell_proto_msgTypes[135] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10925,7 +10999,7 @@ func (x *StaticCredentialEndpointBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialEndpointBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialEndpointBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{134} + return file_openshell_proto_rawDescGZIP(), []int{135} } func (x *StaticCredentialEndpointBinding) GetHost() string { @@ -10969,7 +11043,7 @@ type StaticCredentialBinding struct { func (x *StaticCredentialBinding) Reset() { *x = StaticCredentialBinding{} - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10981,7 +11055,7 @@ func (x *StaticCredentialBinding) String() string { func (*StaticCredentialBinding) ProtoMessage() {} func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[135] + mi := &file_openshell_proto_msgTypes[136] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10994,7 +11068,7 @@ func (x *StaticCredentialBinding) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticCredentialBinding.ProtoReflect.Descriptor instead. func (*StaticCredentialBinding) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{135} + return file_openshell_proto_rawDescGZIP(), []int{136} } func (x *StaticCredentialBinding) GetEndpoints() []*StaticCredentialEndpointBinding { @@ -11045,13 +11119,15 @@ type GetSandboxProviderEnvironmentResponse struct { PolicyHash string `protobuf:"bytes,8,opt,name=policy_hash,json=policyHash,proto3" json:"policy_hash,omitempty"` // Nonzero when material was withheld; installing an empty map is not readiness. ReadinessReason ProviderReadinessReason `protobuf:"varint,9,opt,name=readiness_reason,json=readinessReason,proto3,enum=openshell.v1.ProviderReadinessReason" json:"readiness_reason,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Complete desired set of non-secret managed files, keyed by absolute path. + Files map[string]string `protobuf:"bytes,10,rep,name=files,proto3" json:"files,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetSandboxProviderEnvironmentResponse) Reset() { *x = GetSandboxProviderEnvironmentResponse{} - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11063,7 +11139,7 @@ func (x *GetSandboxProviderEnvironmentResponse) String() string { func (*GetSandboxProviderEnvironmentResponse) ProtoMessage() {} func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[136] + mi := &file_openshell_proto_msgTypes[137] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11076,7 +11152,7 @@ func (x *GetSandboxProviderEnvironmentResponse) ProtoReflect() protoreflect.Mess // Deprecated: Use GetSandboxProviderEnvironmentResponse.ProtoReflect.Descriptor instead. func (*GetSandboxProviderEnvironmentResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{136} + return file_openshell_proto_rawDescGZIP(), []int{137} } func (x *GetSandboxProviderEnvironmentResponse) GetEnvironment() map[string]string { @@ -11142,6 +11218,13 @@ func (x *GetSandboxProviderEnvironmentResponse) GetReadinessReason() ProviderRea return ProviderReadinessReason_PROVIDER_READINESS_REASON_UNSPECIFIED } +func (x *GetSandboxProviderEnvironmentResponse) GetFiles() map[string]string { + if x != nil { + return x.Files + } + return nil +} + type ExchangeProviderSubjectTokenRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // The sandbox ID. Must match the authenticated sandbox principal. @@ -11159,7 +11242,7 @@ type ExchangeProviderSubjectTokenRequest struct { func (x *ExchangeProviderSubjectTokenRequest) Reset() { *x = ExchangeProviderSubjectTokenRequest{} - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11171,7 +11254,7 @@ func (x *ExchangeProviderSubjectTokenRequest) String() string { func (*ExchangeProviderSubjectTokenRequest) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[137] + mi := &file_openshell_proto_msgTypes[138] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11184,7 +11267,7 @@ func (x *ExchangeProviderSubjectTokenRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use ExchangeProviderSubjectTokenRequest.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{137} + return file_openshell_proto_rawDescGZIP(), []int{138} } func (x *ExchangeProviderSubjectTokenRequest) GetSandboxId() string { @@ -11226,7 +11309,7 @@ type ExchangeProviderSubjectTokenResponse struct { func (x *ExchangeProviderSubjectTokenResponse) Reset() { *x = ExchangeProviderSubjectTokenResponse{} - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11238,7 +11321,7 @@ func (x *ExchangeProviderSubjectTokenResponse) String() string { func (*ExchangeProviderSubjectTokenResponse) ProtoMessage() {} func (x *ExchangeProviderSubjectTokenResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[138] + mi := &file_openshell_proto_msgTypes[139] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11251,7 +11334,7 @@ func (x *ExchangeProviderSubjectTokenResponse) ProtoReflect() protoreflect.Messa // Deprecated: Use ExchangeProviderSubjectTokenResponse.ProtoReflect.Descriptor instead. func (*ExchangeProviderSubjectTokenResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{138} + return file_openshell_proto_rawDescGZIP(), []int{139} } func (x *ExchangeProviderSubjectTokenResponse) GetAccessToken() string { @@ -11324,7 +11407,7 @@ type UpdateConfigRequest struct { func (x *UpdateConfigRequest) Reset() { *x = UpdateConfigRequest{} - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[140] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11336,7 +11419,7 @@ func (x *UpdateConfigRequest) String() string { func (*UpdateConfigRequest) ProtoMessage() {} func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[139] + mi := &file_openshell_proto_msgTypes[140] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11349,7 +11432,7 @@ func (x *UpdateConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigRequest.ProtoReflect.Descriptor instead. func (*UpdateConfigRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{139} + return file_openshell_proto_rawDescGZIP(), []int{140} } func (x *UpdateConfigRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -11446,7 +11529,7 @@ type PolicyMergeOperation struct { func (x *PolicyMergeOperation) Reset() { *x = PolicyMergeOperation{} - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11458,7 +11541,7 @@ func (x *PolicyMergeOperation) String() string { func (*PolicyMergeOperation) ProtoMessage() {} func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[140] + mi := &file_openshell_proto_msgTypes[141] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11471,7 +11554,7 @@ func (x *PolicyMergeOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyMergeOperation.ProtoReflect.Descriptor instead. func (*PolicyMergeOperation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{140} + return file_openshell_proto_rawDescGZIP(), []int{141} } func (x *PolicyMergeOperation) GetOperation() isPolicyMergeOperation_Operation { @@ -11585,7 +11668,7 @@ type AddNetworkRule struct { func (x *AddNetworkRule) Reset() { *x = AddNetworkRule{} - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[142] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11597,7 +11680,7 @@ func (x *AddNetworkRule) String() string { func (*AddNetworkRule) ProtoMessage() {} func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[141] + mi := &file_openshell_proto_msgTypes[142] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11610,7 +11693,7 @@ func (x *AddNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use AddNetworkRule.ProtoReflect.Descriptor instead. func (*AddNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{141} + return file_openshell_proto_rawDescGZIP(), []int{142} } func (x *AddNetworkRule) GetRuleName() string { @@ -11638,7 +11721,7 @@ type RemoveNetworkEndpoint struct { func (x *RemoveNetworkEndpoint) Reset() { *x = RemoveNetworkEndpoint{} - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[143] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11650,7 +11733,7 @@ func (x *RemoveNetworkEndpoint) String() string { func (*RemoveNetworkEndpoint) ProtoMessage() {} func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[142] + mi := &file_openshell_proto_msgTypes[143] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11663,7 +11746,7 @@ func (x *RemoveNetworkEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkEndpoint.ProtoReflect.Descriptor instead. func (*RemoveNetworkEndpoint) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{142} + return file_openshell_proto_rawDescGZIP(), []int{143} } func (x *RemoveNetworkEndpoint) GetRuleName() string { @@ -11696,7 +11779,7 @@ type RemoveNetworkRule struct { func (x *RemoveNetworkRule) Reset() { *x = RemoveNetworkRule{} - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[144] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11708,7 +11791,7 @@ func (x *RemoveNetworkRule) String() string { func (*RemoveNetworkRule) ProtoMessage() {} func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[143] + mi := &file_openshell_proto_msgTypes[144] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11721,7 +11804,7 @@ func (x *RemoveNetworkRule) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkRule.ProtoReflect.Descriptor instead. func (*RemoveNetworkRule) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{143} + return file_openshell_proto_rawDescGZIP(), []int{144} } func (x *RemoveNetworkRule) GetRuleName() string { @@ -11750,7 +11833,7 @@ type L7RuleTarget struct { func (x *L7RuleTarget) Reset() { *x = L7RuleTarget{} - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11762,7 +11845,7 @@ func (x *L7RuleTarget) String() string { func (*L7RuleTarget) ProtoMessage() {} func (x *L7RuleTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[144] + mi := &file_openshell_proto_msgTypes[145] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11775,7 +11858,7 @@ func (x *L7RuleTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RuleTarget.ProtoReflect.Descriptor instead. func (*L7RuleTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{144} + return file_openshell_proto_rawDescGZIP(), []int{145} } func (x *L7RuleTarget) GetRuleName() string { @@ -11830,7 +11913,7 @@ type AddDenyRules struct { func (x *AddDenyRules) Reset() { *x = AddDenyRules{} - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11842,7 +11925,7 @@ func (x *AddDenyRules) String() string { func (*AddDenyRules) ProtoMessage() {} func (x *AddDenyRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[145] + mi := &file_openshell_proto_msgTypes[146] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11855,7 +11938,7 @@ func (x *AddDenyRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddDenyRules.ProtoReflect.Descriptor instead. func (*AddDenyRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{145} + return file_openshell_proto_rawDescGZIP(), []int{146} } func (x *AddDenyRules) GetDenyRules() []*sandboxv1.L7DenyRule { @@ -11882,7 +11965,7 @@ type AddAllowRules struct { func (x *AddAllowRules) Reset() { *x = AddAllowRules{} - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[147] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11894,7 +11977,7 @@ func (x *AddAllowRules) String() string { func (*AddAllowRules) ProtoMessage() {} func (x *AddAllowRules) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[146] + mi := &file_openshell_proto_msgTypes[147] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11907,7 +11990,7 @@ func (x *AddAllowRules) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAllowRules.ProtoReflect.Descriptor instead. func (*AddAllowRules) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{146} + return file_openshell_proto_rawDescGZIP(), []int{147} } func (x *AddAllowRules) GetRules() []*sandboxv1.L7Rule { @@ -11934,7 +12017,7 @@ type RemoveNetworkBinary struct { func (x *RemoveNetworkBinary) Reset() { *x = RemoveNetworkBinary{} - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11946,7 +12029,7 @@ func (x *RemoveNetworkBinary) String() string { func (*RemoveNetworkBinary) ProtoMessage() {} func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[147] + mi := &file_openshell_proto_msgTypes[148] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11959,7 +12042,7 @@ func (x *RemoveNetworkBinary) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveNetworkBinary.ProtoReflect.Descriptor instead. func (*RemoveNetworkBinary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{147} + return file_openshell_proto_rawDescGZIP(), []int{148} } func (x *RemoveNetworkBinary) GetRuleName() string { @@ -11995,7 +12078,7 @@ type UpdateConfigResponse struct { func (x *UpdateConfigResponse) Reset() { *x = UpdateConfigResponse{} - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12007,7 +12090,7 @@ func (x *UpdateConfigResponse) String() string { func (*UpdateConfigResponse) ProtoMessage() {} func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[148] + mi := &file_openshell_proto_msgTypes[149] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12020,7 +12103,7 @@ func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateConfigResponse.ProtoReflect.Descriptor instead. func (*UpdateConfigResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{148} + return file_openshell_proto_rawDescGZIP(), []int{149} } func (x *UpdateConfigResponse) GetVersion() uint32 { @@ -12074,7 +12157,7 @@ type GetSandboxPolicyStatusRequest struct { func (x *GetSandboxPolicyStatusRequest) Reset() { *x = GetSandboxPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12086,7 +12169,7 @@ func (x *GetSandboxPolicyStatusRequest) String() string { func (*GetSandboxPolicyStatusRequest) ProtoMessage() {} func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[149] + mi := &file_openshell_proto_msgTypes[150] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12099,7 +12182,7 @@ func (x *GetSandboxPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{149} + return file_openshell_proto_rawDescGZIP(), []int{150} } func (x *GetSandboxPolicyStatusRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -12143,7 +12226,7 @@ type GetSandboxPolicyStatusResponse struct { func (x *GetSandboxPolicyStatusResponse) Reset() { *x = GetSandboxPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12155,7 +12238,7 @@ func (x *GetSandboxPolicyStatusResponse) String() string { func (*GetSandboxPolicyStatusResponse) ProtoMessage() {} func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[150] + mi := &file_openshell_proto_msgTypes[151] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12168,7 +12251,7 @@ func (x *GetSandboxPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*GetSandboxPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{150} + return file_openshell_proto_rawDescGZIP(), []int{151} } func (x *GetSandboxPolicyStatusResponse) GetRevision() *SandboxPolicyRevision { @@ -12205,7 +12288,7 @@ type ListSandboxPoliciesRequest struct { func (x *ListSandboxPoliciesRequest) Reset() { *x = ListSandboxPoliciesRequest{} - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12217,7 +12300,7 @@ func (x *ListSandboxPoliciesRequest) String() string { func (*ListSandboxPoliciesRequest) ProtoMessage() {} func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[151] + mi := &file_openshell_proto_msgTypes[152] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12230,7 +12313,7 @@ func (x *ListSandboxPoliciesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesRequest.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{151} + return file_openshell_proto_rawDescGZIP(), []int{152} } func (x *ListSandboxPoliciesRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -12282,7 +12365,7 @@ type ListSandboxPoliciesResponse struct { func (x *ListSandboxPoliciesResponse) Reset() { *x = ListSandboxPoliciesResponse{} - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12294,7 +12377,7 @@ func (x *ListSandboxPoliciesResponse) String() string { func (*ListSandboxPoliciesResponse) ProtoMessage() {} func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[152] + mi := &file_openshell_proto_msgTypes[153] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12307,7 +12390,7 @@ func (x *ListSandboxPoliciesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSandboxPoliciesResponse.ProtoReflect.Descriptor instead. func (*ListSandboxPoliciesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{152} + return file_openshell_proto_rawDescGZIP(), []int{153} } func (x *ListSandboxPoliciesResponse) GetRevisions() []*SandboxPolicyRevision { @@ -12341,7 +12424,7 @@ type ReportPolicyStatusRequest struct { func (x *ReportPolicyStatusRequest) Reset() { *x = ReportPolicyStatusRequest{} - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[154] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12353,7 +12436,7 @@ func (x *ReportPolicyStatusRequest) String() string { func (*ReportPolicyStatusRequest) ProtoMessage() {} func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[153] + mi := &file_openshell_proto_msgTypes[154] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12366,7 +12449,7 @@ func (x *ReportPolicyStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusRequest.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{153} + return file_openshell_proto_rawDescGZIP(), []int{154} } func (x *ReportPolicyStatusRequest) GetSandboxId() string { @@ -12406,7 +12489,7 @@ type ReportPolicyStatusResponse struct { func (x *ReportPolicyStatusResponse) Reset() { *x = ReportPolicyStatusResponse{} - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[155] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12418,7 +12501,7 @@ func (x *ReportPolicyStatusResponse) String() string { func (*ReportPolicyStatusResponse) ProtoMessage() {} func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[154] + mi := &file_openshell_proto_msgTypes[155] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12431,7 +12514,7 @@ func (x *ReportPolicyStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportPolicyStatusResponse.ProtoReflect.Descriptor instead. func (*ReportPolicyStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{154} + return file_openshell_proto_rawDescGZIP(), []int{155} } type SandboxConfigurationAdmission struct { @@ -12449,7 +12532,7 @@ type SandboxConfigurationAdmission struct { func (x *SandboxConfigurationAdmission) Reset() { *x = SandboxConfigurationAdmission{} - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[156] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12461,7 +12544,7 @@ func (x *SandboxConfigurationAdmission) String() string { func (*SandboxConfigurationAdmission) ProtoMessage() {} func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[155] + mi := &file_openshell_proto_msgTypes[156] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12474,7 +12557,7 @@ func (x *SandboxConfigurationAdmission) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfigurationAdmission.ProtoReflect.Descriptor instead. func (*SandboxConfigurationAdmission) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{155} + return file_openshell_proto_rawDescGZIP(), []int{156} } func (x *SandboxConfigurationAdmission) GetInstanceId() string { @@ -12538,7 +12621,7 @@ type ReportSandboxConfigurationRequest struct { func (x *ReportSandboxConfigurationRequest) Reset() { *x = ReportSandboxConfigurationRequest{} - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[157] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12550,7 +12633,7 @@ func (x *ReportSandboxConfigurationRequest) String() string { func (*ReportSandboxConfigurationRequest) ProtoMessage() {} func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[156] + mi := &file_openshell_proto_msgTypes[157] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12563,7 +12646,7 @@ func (x *ReportSandboxConfigurationRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ReportSandboxConfigurationRequest.ProtoReflect.Descriptor instead. func (*ReportSandboxConfigurationRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{156} + return file_openshell_proto_rawDescGZIP(), []int{157} } func (x *ReportSandboxConfigurationRequest) GetSandboxId() string { @@ -12595,7 +12678,7 @@ type ReportSandboxConfigurationResponse struct { func (x *ReportSandboxConfigurationResponse) Reset() { *x = ReportSandboxConfigurationResponse{} - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[158] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12607,7 +12690,7 @@ func (x *ReportSandboxConfigurationResponse) String() string { func (*ReportSandboxConfigurationResponse) ProtoMessage() {} func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[157] + mi := &file_openshell_proto_msgTypes[158] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12620,7 +12703,7 @@ func (x *ReportSandboxConfigurationResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ReportSandboxConfigurationResponse.ProtoReflect.Descriptor instead. func (*ReportSandboxConfigurationResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{157} + return file_openshell_proto_rawDescGZIP(), []int{158} } // A versioned policy revision with metadata. @@ -12653,7 +12736,7 @@ type SandboxPolicyRevision struct { func (x *SandboxPolicyRevision) Reset() { *x = SandboxPolicyRevision{} - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[159] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12665,7 +12748,7 @@ func (x *SandboxPolicyRevision) String() string { func (*SandboxPolicyRevision) ProtoMessage() {} func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[158] + mi := &file_openshell_proto_msgTypes[159] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12678,7 +12761,7 @@ func (x *SandboxPolicyRevision) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxPolicyRevision.ProtoReflect.Descriptor instead. func (*SandboxPolicyRevision) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{158} + return file_openshell_proto_rawDescGZIP(), []int{159} } func (x *SandboxPolicyRevision) GetVersion() uint32 { @@ -12758,7 +12841,7 @@ type GetSandboxLogsRequest struct { func (x *GetSandboxLogsRequest) Reset() { *x = GetSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[160] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12770,7 +12853,7 @@ func (x *GetSandboxLogsRequest) String() string { func (*GetSandboxLogsRequest) ProtoMessage() {} func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[159] + mi := &file_openshell_proto_msgTypes[160] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12783,7 +12866,7 @@ func (x *GetSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*GetSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{159} + return file_openshell_proto_rawDescGZIP(), []int{160} } func (x *GetSandboxLogsRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -12841,7 +12924,7 @@ type PushSandboxLogsRequest struct { func (x *PushSandboxLogsRequest) Reset() { *x = PushSandboxLogsRequest{} - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[161] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12853,7 +12936,7 @@ func (x *PushSandboxLogsRequest) String() string { func (*PushSandboxLogsRequest) ProtoMessage() {} func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[160] + mi := &file_openshell_proto_msgTypes[161] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12866,7 +12949,7 @@ func (x *PushSandboxLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsRequest.ProtoReflect.Descriptor instead. func (*PushSandboxLogsRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{160} + return file_openshell_proto_rawDescGZIP(), []int{161} } func (x *PushSandboxLogsRequest) GetSandboxId() string { @@ -12892,7 +12975,7 @@ type PushSandboxLogsResponse struct { func (x *PushSandboxLogsResponse) Reset() { *x = PushSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[162] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12904,7 +12987,7 @@ func (x *PushSandboxLogsResponse) String() string { func (*PushSandboxLogsResponse) ProtoMessage() {} func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[161] + mi := &file_openshell_proto_msgTypes[162] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12917,7 +13000,7 @@ func (x *PushSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PushSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*PushSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{161} + return file_openshell_proto_rawDescGZIP(), []int{162} } // Get sandbox logs response. @@ -12933,7 +13016,7 @@ type GetSandboxLogsResponse struct { func (x *GetSandboxLogsResponse) Reset() { *x = GetSandboxLogsResponse{} - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[163] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12945,7 +13028,7 @@ func (x *GetSandboxLogsResponse) String() string { func (*GetSandboxLogsResponse) ProtoMessage() {} func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[162] + mi := &file_openshell_proto_msgTypes[163] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12958,7 +13041,7 @@ func (x *GetSandboxLogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSandboxLogsResponse.ProtoReflect.Descriptor instead. func (*GetSandboxLogsResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{162} + return file_openshell_proto_rawDescGZIP(), []int{163} } func (x *GetSandboxLogsResponse) GetLogs() []*SandboxLogLine { @@ -12991,7 +13074,7 @@ type SupervisorMessage struct { func (x *SupervisorMessage) Reset() { *x = SupervisorMessage{} - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[164] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13003,7 +13086,7 @@ func (x *SupervisorMessage) String() string { func (*SupervisorMessage) ProtoMessage() {} func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[163] + mi := &file_openshell_proto_msgTypes[164] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13016,7 +13099,7 @@ func (x *SupervisorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorMessage.ProtoReflect.Descriptor instead. func (*SupervisorMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{163} + return file_openshell_proto_rawDescGZIP(), []int{164} } func (x *SupervisorMessage) GetPayload() isSupervisorMessage_Payload { @@ -13107,7 +13190,7 @@ type GatewayMessage struct { func (x *GatewayMessage) Reset() { *x = GatewayMessage{} - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[165] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13119,7 +13202,7 @@ func (x *GatewayMessage) String() string { func (*GatewayMessage) ProtoMessage() {} func (x *GatewayMessage) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[164] + mi := &file_openshell_proto_msgTypes[165] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13132,7 +13215,7 @@ func (x *GatewayMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayMessage.ProtoReflect.Descriptor instead. func (*GatewayMessage) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{164} + return file_openshell_proto_rawDescGZIP(), []int{165} } func (x *GatewayMessage) GetPayload() isGatewayMessage_Payload { @@ -13239,7 +13322,7 @@ type SupervisorHello struct { func (x *SupervisorHello) Reset() { *x = SupervisorHello{} - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[166] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13251,7 +13334,7 @@ func (x *SupervisorHello) String() string { func (*SupervisorHello) ProtoMessage() {} func (x *SupervisorHello) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[165] + mi := &file_openshell_proto_msgTypes[166] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13264,7 +13347,7 @@ func (x *SupervisorHello) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHello.ProtoReflect.Descriptor instead. func (*SupervisorHello) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{165} + return file_openshell_proto_rawDescGZIP(), []int{166} } func (x *SupervisorHello) GetSandboxId() string { @@ -13308,7 +13391,7 @@ type SessionAccepted struct { func (x *SessionAccepted) Reset() { *x = SessionAccepted{} - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[167] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13320,7 +13403,7 @@ func (x *SessionAccepted) String() string { func (*SessionAccepted) ProtoMessage() {} func (x *SessionAccepted) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[166] + mi := &file_openshell_proto_msgTypes[167] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13333,7 +13416,7 @@ func (x *SessionAccepted) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionAccepted.ProtoReflect.Descriptor instead. func (*SessionAccepted) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{166} + return file_openshell_proto_rawDescGZIP(), []int{167} } func (x *SessionAccepted) GetSessionId() string { @@ -13361,7 +13444,7 @@ type SessionRejected struct { func (x *SessionRejected) Reset() { *x = SessionRejected{} - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[168] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13373,7 +13456,7 @@ func (x *SessionRejected) String() string { func (*SessionRejected) ProtoMessage() {} func (x *SessionRejected) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[167] + mi := &file_openshell_proto_msgTypes[168] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13386,7 +13469,7 @@ func (x *SessionRejected) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionRejected.ProtoReflect.Descriptor instead. func (*SessionRejected) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{167} + return file_openshell_proto_rawDescGZIP(), []int{168} } func (x *SessionRejected) GetReason() string { @@ -13405,7 +13488,7 @@ type SupervisorHeartbeat struct { func (x *SupervisorHeartbeat) Reset() { *x = SupervisorHeartbeat{} - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[169] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13417,7 +13500,7 @@ func (x *SupervisorHeartbeat) String() string { func (*SupervisorHeartbeat) ProtoMessage() {} func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[168] + mi := &file_openshell_proto_msgTypes[169] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13430,7 +13513,7 @@ func (x *SupervisorHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use SupervisorHeartbeat.ProtoReflect.Descriptor instead. func (*SupervisorHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{168} + return file_openshell_proto_rawDescGZIP(), []int{169} } // Gateway heartbeat. @@ -13442,7 +13525,7 @@ type GatewayHeartbeat struct { func (x *GatewayHeartbeat) Reset() { *x = GatewayHeartbeat{} - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[170] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13454,7 +13537,7 @@ func (x *GatewayHeartbeat) String() string { func (*GatewayHeartbeat) ProtoMessage() {} func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[169] + mi := &file_openshell_proto_msgTypes[170] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13467,7 +13550,7 @@ func (x *GatewayHeartbeat) ProtoReflect() protoreflect.Message { // Deprecated: Use GatewayHeartbeat.ProtoReflect.Descriptor instead. func (*GatewayHeartbeat) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{169} + return file_openshell_proto_rawDescGZIP(), []int{170} } // Terminal result reported before the supervisor shuts down. A successful RPC @@ -13484,7 +13567,7 @@ type ReportMainProcessExitRequest struct { func (x *ReportMainProcessExitRequest) Reset() { *x = ReportMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[171] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13496,7 +13579,7 @@ func (x *ReportMainProcessExitRequest) String() string { func (*ReportMainProcessExitRequest) ProtoMessage() {} func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[170] + mi := &file_openshell_proto_msgTypes[171] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13509,7 +13592,7 @@ func (x *ReportMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{170} + return file_openshell_proto_rawDescGZIP(), []int{171} } func (x *ReportMainProcessExitRequest) GetSandboxId() string { @@ -13541,7 +13624,7 @@ type ReportMainProcessExitResponse struct { func (x *ReportMainProcessExitResponse) Reset() { *x = ReportMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[172] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13553,7 +13636,7 @@ func (x *ReportMainProcessExitResponse) String() string { func (*ReportMainProcessExitResponse) ProtoMessage() {} func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[171] + mi := &file_openshell_proto_msgTypes[172] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13566,7 +13649,7 @@ func (x *ReportMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*ReportMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{171} + return file_openshell_proto_rawDescGZIP(), []int{172} } // Terminal-delivery completion reported after all expected foreground SSH @@ -13581,7 +13664,7 @@ type FinalizeMainProcessExitRequest struct { func (x *FinalizeMainProcessExitRequest) Reset() { *x = FinalizeMainProcessExitRequest{} - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[173] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13593,7 +13676,7 @@ func (x *FinalizeMainProcessExitRequest) String() string { func (*FinalizeMainProcessExitRequest) ProtoMessage() {} func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[172] + mi := &file_openshell_proto_msgTypes[173] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13606,7 +13689,7 @@ func (x *FinalizeMainProcessExitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitRequest.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{172} + return file_openshell_proto_rawDescGZIP(), []int{173} } func (x *FinalizeMainProcessExitRequest) GetSandboxId() string { @@ -13631,7 +13714,7 @@ type FinalizeMainProcessExitResponse struct { func (x *FinalizeMainProcessExitResponse) Reset() { *x = FinalizeMainProcessExitResponse{} - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[174] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13643,7 +13726,7 @@ func (x *FinalizeMainProcessExitResponse) String() string { func (*FinalizeMainProcessExitResponse) ProtoMessage() {} func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[173] + mi := &file_openshell_proto_msgTypes[174] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13656,7 +13739,7 @@ func (x *FinalizeMainProcessExitResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FinalizeMainProcessExitResponse.ProtoReflect.Descriptor instead. func (*FinalizeMainProcessExitResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{173} + return file_openshell_proto_rawDescGZIP(), []int{174} } // Gateway requests the supervisor to open a relay channel. @@ -13685,7 +13768,7 @@ type RelayOpen struct { func (x *RelayOpen) Reset() { *x = RelayOpen{} - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[175] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13697,7 +13780,7 @@ func (x *RelayOpen) String() string { func (*RelayOpen) ProtoMessage() {} func (x *RelayOpen) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[174] + mi := &file_openshell_proto_msgTypes[175] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13710,7 +13793,7 @@ func (x *RelayOpen) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpen.ProtoReflect.Descriptor instead. func (*RelayOpen) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{174} + return file_openshell_proto_rawDescGZIP(), []int{175} } func (x *RelayOpen) GetChannelId() string { @@ -13777,7 +13860,7 @@ type SshRelayTarget struct { func (x *SshRelayTarget) Reset() { *x = SshRelayTarget{} - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[176] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13789,7 +13872,7 @@ func (x *SshRelayTarget) String() string { func (*SshRelayTarget) ProtoMessage() {} func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[175] + mi := &file_openshell_proto_msgTypes[176] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13802,7 +13885,7 @@ func (x *SshRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use SshRelayTarget.ProtoReflect.Descriptor instead. func (*SshRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{175} + return file_openshell_proto_rawDescGZIP(), []int{176} } // TCP target dialed by the supervisor from inside the sandbox. @@ -13818,7 +13901,7 @@ type TcpRelayTarget struct { func (x *TcpRelayTarget) Reset() { *x = TcpRelayTarget{} - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[177] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13830,7 +13913,7 @@ func (x *TcpRelayTarget) String() string { func (*TcpRelayTarget) ProtoMessage() {} func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[176] + mi := &file_openshell_proto_msgTypes[177] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13843,7 +13926,7 @@ func (x *TcpRelayTarget) ProtoReflect() protoreflect.Message { // Deprecated: Use TcpRelayTarget.ProtoReflect.Descriptor instead. func (*TcpRelayTarget) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{176} + return file_openshell_proto_rawDescGZIP(), []int{177} } func (x *TcpRelayTarget) GetHost() string { @@ -13871,7 +13954,7 @@ type RelayInit struct { func (x *RelayInit) Reset() { *x = RelayInit{} - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[178] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13883,7 +13966,7 @@ func (x *RelayInit) String() string { func (*RelayInit) ProtoMessage() {} func (x *RelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[177] + mi := &file_openshell_proto_msgTypes[178] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13896,7 +13979,7 @@ func (x *RelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayInit.ProtoReflect.Descriptor instead. func (*RelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{177} + return file_openshell_proto_rawDescGZIP(), []int{178} } func (x *RelayInit) GetChannelId() string { @@ -13923,7 +14006,7 @@ type RelayFrame struct { func (x *RelayFrame) Reset() { *x = RelayFrame{} - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[179] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -13935,7 +14018,7 @@ func (x *RelayFrame) String() string { func (*RelayFrame) ProtoMessage() {} func (x *RelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[178] + mi := &file_openshell_proto_msgTypes[179] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -13948,7 +14031,7 @@ func (x *RelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayFrame.ProtoReflect.Descriptor instead. func (*RelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{178} + return file_openshell_proto_rawDescGZIP(), []int{179} } func (x *RelayFrame) GetPayload() isRelayFrame_Payload { @@ -14008,7 +14091,7 @@ type PeerRelayInit struct { func (x *PeerRelayInit) Reset() { *x = PeerRelayInit{} - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[180] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14020,7 +14103,7 @@ func (x *PeerRelayInit) String() string { func (*PeerRelayInit) ProtoMessage() {} func (x *PeerRelayInit) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[179] + mi := &file_openshell_proto_msgTypes[180] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14033,7 +14116,7 @@ func (x *PeerRelayInit) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerRelayInit.ProtoReflect.Descriptor instead. func (*PeerRelayInit) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{179} + return file_openshell_proto_rawDescGZIP(), []int{180} } func (x *PeerRelayInit) GetSandboxId() string { @@ -14071,7 +14154,7 @@ type PeerRelayFrame struct { func (x *PeerRelayFrame) Reset() { *x = PeerRelayFrame{} - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[181] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14083,7 +14166,7 @@ func (x *PeerRelayFrame) String() string { func (*PeerRelayFrame) ProtoMessage() {} func (x *PeerRelayFrame) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[180] + mi := &file_openshell_proto_msgTypes[181] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14096,7 +14179,7 @@ func (x *PeerRelayFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerRelayFrame.ProtoReflect.Descriptor instead. func (*PeerRelayFrame) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{180} + return file_openshell_proto_rawDescGZIP(), []int{181} } func (x *PeerRelayFrame) GetPayload() isPeerRelayFrame_Payload { @@ -14155,7 +14238,7 @@ type RelayOpenResult struct { func (x *RelayOpenResult) Reset() { *x = RelayOpenResult{} - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[182] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14167,7 +14250,7 @@ func (x *RelayOpenResult) String() string { func (*RelayOpenResult) ProtoMessage() {} func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[181] + mi := &file_openshell_proto_msgTypes[182] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14180,7 +14263,7 @@ func (x *RelayOpenResult) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayOpenResult.ProtoReflect.Descriptor instead. func (*RelayOpenResult) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{181} + return file_openshell_proto_rawDescGZIP(), []int{182} } func (x *RelayOpenResult) GetChannelId() string { @@ -14217,7 +14300,7 @@ type RelayClose struct { func (x *RelayClose) Reset() { *x = RelayClose{} - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[183] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14229,7 +14312,7 @@ func (x *RelayClose) String() string { func (*RelayClose) ProtoMessage() {} func (x *RelayClose) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[182] + mi := &file_openshell_proto_msgTypes[183] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14242,7 +14325,7 @@ func (x *RelayClose) ProtoReflect() protoreflect.Message { // Deprecated: Use RelayClose.ProtoReflect.Descriptor instead. func (*RelayClose) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{182} + return file_openshell_proto_rawDescGZIP(), []int{183} } func (x *RelayClose) GetChannelId() string { @@ -14276,7 +14359,7 @@ type L7RequestSample struct { func (x *L7RequestSample) Reset() { *x = L7RequestSample{} - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[184] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14288,7 +14371,7 @@ func (x *L7RequestSample) String() string { func (*L7RequestSample) ProtoMessage() {} func (x *L7RequestSample) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[183] + mi := &file_openshell_proto_msgTypes[184] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14301,7 +14384,7 @@ func (x *L7RequestSample) ProtoReflect() protoreflect.Message { // Deprecated: Use L7RequestSample.ProtoReflect.Descriptor instead. func (*L7RequestSample) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{183} + return file_openshell_proto_rawDescGZIP(), []int{184} } func (x *L7RequestSample) GetMethod() string { @@ -14375,7 +14458,7 @@ type DenialSummary struct { func (x *DenialSummary) Reset() { *x = DenialSummary{} - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[185] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14387,7 +14470,7 @@ func (x *DenialSummary) String() string { func (*DenialSummary) ProtoMessage() {} func (x *DenialSummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[184] + mi := &file_openshell_proto_msgTypes[185] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14400,7 +14483,7 @@ func (x *DenialSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialSummary.ProtoReflect.Descriptor instead. func (*DenialSummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{184} + return file_openshell_proto_rawDescGZIP(), []int{185} } func (x *DenialSummary) GetSandboxId() string { @@ -14535,7 +14618,7 @@ type DenialGroupCount struct { func (x *DenialGroupCount) Reset() { *x = DenialGroupCount{} - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[186] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14547,7 +14630,7 @@ func (x *DenialGroupCount) String() string { func (*DenialGroupCount) ProtoMessage() {} func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[185] + mi := &file_openshell_proto_msgTypes[186] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14560,7 +14643,7 @@ func (x *DenialGroupCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DenialGroupCount.ProtoReflect.Descriptor instead. func (*DenialGroupCount) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{185} + return file_openshell_proto_rawDescGZIP(), []int{186} } func (x *DenialGroupCount) GetDenyGroup() string { @@ -14593,7 +14676,7 @@ type NetworkActivitySummary struct { func (x *NetworkActivitySummary) Reset() { *x = NetworkActivitySummary{} - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[187] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14605,7 +14688,7 @@ func (x *NetworkActivitySummary) String() string { func (*NetworkActivitySummary) ProtoMessage() {} func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[186] + mi := &file_openshell_proto_msgTypes[187] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14618,7 +14701,7 @@ func (x *NetworkActivitySummary) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkActivitySummary.ProtoReflect.Descriptor instead. func (*NetworkActivitySummary) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{186} + return file_openshell_proto_rawDescGZIP(), []int{187} } func (x *NetworkActivitySummary) GetNetworkActivityCount() uint32 { @@ -14706,7 +14789,7 @@ type PolicyChunk struct { func (x *PolicyChunk) Reset() { *x = PolicyChunk{} - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[188] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14718,7 +14801,7 @@ func (x *PolicyChunk) String() string { func (*PolicyChunk) ProtoMessage() {} func (x *PolicyChunk) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[187] + mi := &file_openshell_proto_msgTypes[188] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14731,7 +14814,7 @@ func (x *PolicyChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyChunk.ProtoReflect.Descriptor instead. func (*PolicyChunk) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{187} + return file_openshell_proto_rawDescGZIP(), []int{188} } func (x *PolicyChunk) GetId() string { @@ -14919,7 +15002,7 @@ type DraftPolicyUpdate struct { func (x *DraftPolicyUpdate) Reset() { *x = DraftPolicyUpdate{} - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[189] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14931,7 +15014,7 @@ func (x *DraftPolicyUpdate) String() string { func (*DraftPolicyUpdate) ProtoMessage() {} func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[188] + mi := &file_openshell_proto_msgTypes[189] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14944,7 +15027,7 @@ func (x *DraftPolicyUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftPolicyUpdate.ProtoReflect.Descriptor instead. func (*DraftPolicyUpdate) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{188} + return file_openshell_proto_rawDescGZIP(), []int{189} } func (x *DraftPolicyUpdate) GetDraftVersion() uint64 { @@ -15003,7 +15086,7 @@ type SubmitPolicyAnalysisRequest struct { func (x *SubmitPolicyAnalysisRequest) Reset() { *x = SubmitPolicyAnalysisRequest{} - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[190] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15015,7 +15098,7 @@ func (x *SubmitPolicyAnalysisRequest) String() string { func (*SubmitPolicyAnalysisRequest) ProtoMessage() {} func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[189] + mi := &file_openshell_proto_msgTypes[190] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15028,7 +15111,7 @@ func (x *SubmitPolicyAnalysisRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisRequest.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{189} + return file_openshell_proto_rawDescGZIP(), []int{190} } func (x *SubmitPolicyAnalysisRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -15091,7 +15174,7 @@ type SubmitPolicyAnalysisResponse struct { func (x *SubmitPolicyAnalysisResponse) Reset() { *x = SubmitPolicyAnalysisResponse{} - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[191] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15103,7 +15186,7 @@ func (x *SubmitPolicyAnalysisResponse) String() string { func (*SubmitPolicyAnalysisResponse) ProtoMessage() {} func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[190] + mi := &file_openshell_proto_msgTypes[191] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15116,7 +15199,7 @@ func (x *SubmitPolicyAnalysisResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitPolicyAnalysisResponse.ProtoReflect.Descriptor instead. func (*SubmitPolicyAnalysisResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{190} + return file_openshell_proto_rawDescGZIP(), []int{191} } func (x *SubmitPolicyAnalysisResponse) GetAcceptedChunks() uint32 { @@ -15161,7 +15244,7 @@ type GetDraftPolicyRequest struct { func (x *GetDraftPolicyRequest) Reset() { *x = GetDraftPolicyRequest{} - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[192] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15173,7 +15256,7 @@ func (x *GetDraftPolicyRequest) String() string { func (*GetDraftPolicyRequest) ProtoMessage() {} func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[191] + mi := &file_openshell_proto_msgTypes[192] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15186,7 +15269,7 @@ func (x *GetDraftPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyRequest.ProtoReflect.Descriptor instead. func (*GetDraftPolicyRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{191} + return file_openshell_proto_rawDescGZIP(), []int{192} } func (x *GetDraftPolicyRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -15226,7 +15309,7 @@ type GetDraftPolicyResponse struct { func (x *GetDraftPolicyResponse) Reset() { *x = GetDraftPolicyResponse{} - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15238,7 +15321,7 @@ func (x *GetDraftPolicyResponse) String() string { func (*GetDraftPolicyResponse) ProtoMessage() {} func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[192] + mi := &file_openshell_proto_msgTypes[193] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15251,7 +15334,7 @@ func (x *GetDraftPolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftPolicyResponse.ProtoReflect.Descriptor instead. func (*GetDraftPolicyResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{192} + return file_openshell_proto_rawDescGZIP(), []int{193} } func (x *GetDraftPolicyResponse) GetChunks() []*PolicyChunk { @@ -15302,7 +15385,7 @@ type ApproveDraftChunkRequest struct { func (x *ApproveDraftChunkRequest) Reset() { *x = ApproveDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15314,7 +15397,7 @@ func (x *ApproveDraftChunkRequest) String() string { func (*ApproveDraftChunkRequest) ProtoMessage() {} func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[193] + mi := &file_openshell_proto_msgTypes[194] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15327,7 +15410,7 @@ func (x *ApproveDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkRequest.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{193} + return file_openshell_proto_rawDescGZIP(), []int{194} } func (x *ApproveDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -15377,7 +15460,7 @@ type ApproveDraftChunkResponse struct { func (x *ApproveDraftChunkResponse) Reset() { *x = ApproveDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15389,7 +15472,7 @@ func (x *ApproveDraftChunkResponse) String() string { func (*ApproveDraftChunkResponse) ProtoMessage() {} func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[194] + mi := &file_openshell_proto_msgTypes[195] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15402,7 +15485,7 @@ func (x *ApproveDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveDraftChunkResponse.ProtoReflect.Descriptor instead. func (*ApproveDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{194} + return file_openshell_proto_rawDescGZIP(), []int{195} } func (x *ApproveDraftChunkResponse) GetPolicyVersion() uint32 { @@ -15438,7 +15521,7 @@ type RejectDraftChunkRequest struct { func (x *RejectDraftChunkRequest) Reset() { *x = RejectDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15450,7 +15533,7 @@ func (x *RejectDraftChunkRequest) String() string { func (*RejectDraftChunkRequest) ProtoMessage() {} func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[195] + mi := &file_openshell_proto_msgTypes[196] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15463,7 +15546,7 @@ func (x *RejectDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkRequest.ProtoReflect.Descriptor instead. func (*RejectDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{195} + return file_openshell_proto_rawDescGZIP(), []int{196} } func (x *RejectDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -15509,7 +15592,7 @@ type RejectDraftChunkResponse struct { func (x *RejectDraftChunkResponse) Reset() { *x = RejectDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15521,7 +15604,7 @@ func (x *RejectDraftChunkResponse) String() string { func (*RejectDraftChunkResponse) ProtoMessage() {} func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[196] + mi := &file_openshell_proto_msgTypes[197] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15534,7 +15617,7 @@ func (x *RejectDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectDraftChunkResponse.ProtoReflect.Descriptor instead. func (*RejectDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{196} + return file_openshell_proto_rawDescGZIP(), []int{197} } // Approve all pending chunks. @@ -15548,7 +15631,7 @@ type DraftChunkApproval struct { func (x *DraftChunkApproval) Reset() { *x = DraftChunkApproval{} - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15560,7 +15643,7 @@ func (x *DraftChunkApproval) String() string { func (*DraftChunkApproval) ProtoMessage() {} func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[197] + mi := &file_openshell_proto_msgTypes[198] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15573,7 +15656,7 @@ func (x *DraftChunkApproval) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftChunkApproval.ProtoReflect.Descriptor instead. func (*DraftChunkApproval) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{197} + return file_openshell_proto_rawDescGZIP(), []int{198} } func (x *DraftChunkApproval) GetChunkId() string { @@ -15609,7 +15692,7 @@ type ApproveAllDraftChunksRequest struct { func (x *ApproveAllDraftChunksRequest) Reset() { *x = ApproveAllDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15621,7 +15704,7 @@ func (x *ApproveAllDraftChunksRequest) String() string { func (*ApproveAllDraftChunksRequest) ProtoMessage() {} func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[198] + mi := &file_openshell_proto_msgTypes[199] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15634,7 +15717,7 @@ func (x *ApproveAllDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{198} + return file_openshell_proto_rawDescGZIP(), []int{199} } func (x *ApproveAllDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -15689,7 +15772,7 @@ type ApproveAllDraftChunksResponse struct { func (x *ApproveAllDraftChunksResponse) Reset() { *x = ApproveAllDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[200] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15701,7 +15784,7 @@ func (x *ApproveAllDraftChunksResponse) String() string { func (*ApproveAllDraftChunksResponse) ProtoMessage() {} func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[199] + mi := &file_openshell_proto_msgTypes[200] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15714,7 +15797,7 @@ func (x *ApproveAllDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ApproveAllDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ApproveAllDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{199} + return file_openshell_proto_rawDescGZIP(), []int{200} } func (x *ApproveAllDraftChunksResponse) GetPolicyVersion() uint32 { @@ -15764,7 +15847,7 @@ type EditDraftChunkRequest struct { func (x *EditDraftChunkRequest) Reset() { *x = EditDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[201] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15776,7 +15859,7 @@ func (x *EditDraftChunkRequest) String() string { func (*EditDraftChunkRequest) ProtoMessage() {} func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[200] + mi := &file_openshell_proto_msgTypes[201] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15789,7 +15872,7 @@ func (x *EditDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkRequest.ProtoReflect.Descriptor instead. func (*EditDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{200} + return file_openshell_proto_rawDescGZIP(), []int{201} } func (x *EditDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -15835,7 +15918,7 @@ type EditDraftChunkResponse struct { func (x *EditDraftChunkResponse) Reset() { *x = EditDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[202] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15847,7 +15930,7 @@ func (x *EditDraftChunkResponse) String() string { func (*EditDraftChunkResponse) ProtoMessage() {} func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[201] + mi := &file_openshell_proto_msgTypes[202] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15860,7 +15943,7 @@ func (x *EditDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EditDraftChunkResponse.ProtoReflect.Descriptor instead. func (*EditDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{201} + return file_openshell_proto_rawDescGZIP(), []int{202} } // Reverse an approval (remove merged rule from active policy). @@ -15880,7 +15963,7 @@ type UndoDraftChunkRequest struct { func (x *UndoDraftChunkRequest) Reset() { *x = UndoDraftChunkRequest{} - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[203] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15892,7 +15975,7 @@ func (x *UndoDraftChunkRequest) String() string { func (*UndoDraftChunkRequest) ProtoMessage() {} func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[202] + mi := &file_openshell_proto_msgTypes[203] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15905,7 +15988,7 @@ func (x *UndoDraftChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkRequest.ProtoReflect.Descriptor instead. func (*UndoDraftChunkRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{202} + return file_openshell_proto_rawDescGZIP(), []int{203} } func (x *UndoDraftChunkRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -15948,7 +16031,7 @@ type UndoDraftChunkResponse struct { func (x *UndoDraftChunkResponse) Reset() { *x = UndoDraftChunkResponse{} - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[204] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15960,7 +16043,7 @@ func (x *UndoDraftChunkResponse) String() string { func (*UndoDraftChunkResponse) ProtoMessage() {} func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[203] + mi := &file_openshell_proto_msgTypes[204] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15973,7 +16056,7 @@ func (x *UndoDraftChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UndoDraftChunkResponse.ProtoReflect.Descriptor instead. func (*UndoDraftChunkResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{203} + return file_openshell_proto_rawDescGZIP(), []int{204} } func (x *UndoDraftChunkResponse) GetPolicyVersion() uint32 { @@ -16005,7 +16088,7 @@ type ClearDraftChunksRequest struct { func (x *ClearDraftChunksRequest) Reset() { *x = ClearDraftChunksRequest{} - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[205] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16017,7 +16100,7 @@ func (x *ClearDraftChunksRequest) String() string { func (*ClearDraftChunksRequest) ProtoMessage() {} func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[204] + mi := &file_openshell_proto_msgTypes[205] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16030,7 +16113,7 @@ func (x *ClearDraftChunksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksRequest.ProtoReflect.Descriptor instead. func (*ClearDraftChunksRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{204} + return file_openshell_proto_rawDescGZIP(), []int{205} } func (x *ClearDraftChunksRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16064,7 +16147,7 @@ type ClearDraftChunksResponse struct { func (x *ClearDraftChunksResponse) Reset() { *x = ClearDraftChunksResponse{} - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[206] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16076,7 +16159,7 @@ func (x *ClearDraftChunksResponse) String() string { func (*ClearDraftChunksResponse) ProtoMessage() {} func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[205] + mi := &file_openshell_proto_msgTypes[206] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16089,7 +16172,7 @@ func (x *ClearDraftChunksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ClearDraftChunksResponse.ProtoReflect.Descriptor instead. func (*ClearDraftChunksResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{205} + return file_openshell_proto_rawDescGZIP(), []int{206} } func (x *ClearDraftChunksResponse) GetChunksCleared() uint32 { @@ -16111,7 +16194,7 @@ type GetDraftHistoryRequest struct { func (x *GetDraftHistoryRequest) Reset() { *x = GetDraftHistoryRequest{} - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[207] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16123,7 +16206,7 @@ func (x *GetDraftHistoryRequest) String() string { func (*GetDraftHistoryRequest) ProtoMessage() {} func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[206] + mi := &file_openshell_proto_msgTypes[207] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16136,7 +16219,7 @@ func (x *GetDraftHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryRequest.ProtoReflect.Descriptor instead. func (*GetDraftHistoryRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{206} + return file_openshell_proto_rawDescGZIP(), []int{207} } func (x *GetDraftHistoryRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16170,7 +16253,7 @@ type DraftHistoryEntry struct { func (x *DraftHistoryEntry) Reset() { *x = DraftHistoryEntry{} - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[208] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16182,7 +16265,7 @@ func (x *DraftHistoryEntry) String() string { func (*DraftHistoryEntry) ProtoMessage() {} func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[207] + mi := &file_openshell_proto_msgTypes[208] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16195,7 +16278,7 @@ func (x *DraftHistoryEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use DraftHistoryEntry.ProtoReflect.Descriptor instead. func (*DraftHistoryEntry) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{207} + return file_openshell_proto_rawDescGZIP(), []int{208} } func (x *DraftHistoryEntry) GetEventTime() *timestamppb.Timestamp { @@ -16236,7 +16319,7 @@ type GetDraftHistoryResponse struct { func (x *GetDraftHistoryResponse) Reset() { *x = GetDraftHistoryResponse{} - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[209] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16248,7 +16331,7 @@ func (x *GetDraftHistoryResponse) String() string { func (*GetDraftHistoryResponse) ProtoMessage() {} func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[208] + mi := &file_openshell_proto_msgTypes[209] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16261,7 +16344,7 @@ func (x *GetDraftHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDraftHistoryResponse.ProtoReflect.Descriptor instead. func (*GetDraftHistoryResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{208} + return file_openshell_proto_rawDescGZIP(), []int{209} } func (x *GetDraftHistoryResponse) GetEntries() []*DraftHistoryEntry { @@ -16286,7 +16369,7 @@ type CreateWorkspaceRequest struct { func (x *CreateWorkspaceRequest) Reset() { *x = CreateWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[210] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16298,7 +16381,7 @@ func (x *CreateWorkspaceRequest) String() string { func (*CreateWorkspaceRequest) ProtoMessage() {} func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[209] + mi := &file_openshell_proto_msgTypes[210] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16311,7 +16394,7 @@ func (x *CreateWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceRequest.ProtoReflect.Descriptor instead. func (*CreateWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{209} + return file_openshell_proto_rawDescGZIP(), []int{210} } func (x *CreateWorkspaceRequest) GetName() string { @@ -16345,7 +16428,7 @@ type CreateWorkspaceResponse struct { func (x *CreateWorkspaceResponse) Reset() { *x = CreateWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[211] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16357,7 +16440,7 @@ func (x *CreateWorkspaceResponse) String() string { func (*CreateWorkspaceResponse) ProtoMessage() {} func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[210] + mi := &file_openshell_proto_msgTypes[211] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16370,7 +16453,7 @@ func (x *CreateWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkspaceResponse.ProtoReflect.Descriptor instead. func (*CreateWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{210} + return file_openshell_proto_rawDescGZIP(), []int{211} } func (x *CreateWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -16391,7 +16474,7 @@ type GetWorkspaceRequest struct { func (x *GetWorkspaceRequest) Reset() { *x = GetWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[212] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16403,7 +16486,7 @@ func (x *GetWorkspaceRequest) String() string { func (*GetWorkspaceRequest) ProtoMessage() {} func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[211] + mi := &file_openshell_proto_msgTypes[212] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16416,7 +16499,7 @@ func (x *GetWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceRequest.ProtoReflect.Descriptor instead. func (*GetWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{211} + return file_openshell_proto_rawDescGZIP(), []int{212} } func (x *GetWorkspaceRequest) GetName() string { @@ -16436,7 +16519,7 @@ type GetWorkspaceResponse struct { func (x *GetWorkspaceResponse) Reset() { *x = GetWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[213] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16448,7 +16531,7 @@ func (x *GetWorkspaceResponse) String() string { func (*GetWorkspaceResponse) ProtoMessage() {} func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[212] + mi := &file_openshell_proto_msgTypes[213] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16461,7 +16544,7 @@ func (x *GetWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkspaceResponse.ProtoReflect.Descriptor instead. func (*GetWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{212} + return file_openshell_proto_rawDescGZIP(), []int{213} } func (x *GetWorkspaceResponse) GetWorkspace() *datamodelv1.Workspace { @@ -16488,7 +16571,7 @@ type ListWorkspacesRequest struct { func (x *ListWorkspacesRequest) Reset() { *x = ListWorkspacesRequest{} - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[214] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16500,7 +16583,7 @@ func (x *ListWorkspacesRequest) String() string { func (*ListWorkspacesRequest) ProtoMessage() {} func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[213] + mi := &file_openshell_proto_msgTypes[214] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16513,7 +16596,7 @@ func (x *ListWorkspacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesRequest.ProtoReflect.Descriptor instead. func (*ListWorkspacesRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{213} + return file_openshell_proto_rawDescGZIP(), []int{214} } func (x *ListWorkspacesRequest) GetPageSize() int32 { @@ -16549,7 +16632,7 @@ type ListWorkspacesResponse struct { func (x *ListWorkspacesResponse) Reset() { *x = ListWorkspacesResponse{} - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[215] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16561,7 +16644,7 @@ func (x *ListWorkspacesResponse) String() string { func (*ListWorkspacesResponse) ProtoMessage() {} func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[214] + mi := &file_openshell_proto_msgTypes[215] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16574,7 +16657,7 @@ func (x *ListWorkspacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspacesResponse.ProtoReflect.Descriptor instead. func (*ListWorkspacesResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{214} + return file_openshell_proto_rawDescGZIP(), []int{215} } func (x *ListWorkspacesResponse) GetWorkspaces() []*datamodelv1.Workspace { @@ -16605,7 +16688,7 @@ type DeleteWorkspaceRequest struct { func (x *DeleteWorkspaceRequest) Reset() { *x = DeleteWorkspaceRequest{} - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[216] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16617,7 +16700,7 @@ func (x *DeleteWorkspaceRequest) String() string { func (*DeleteWorkspaceRequest) ProtoMessage() {} func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[215] + mi := &file_openshell_proto_msgTypes[216] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16630,7 +16713,7 @@ func (x *DeleteWorkspaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{215} + return file_openshell_proto_rawDescGZIP(), []int{216} } func (x *DeleteWorkspaceRequest) GetName() string { @@ -16664,7 +16747,7 @@ type DeleteWorkspaceResponse struct { func (x *DeleteWorkspaceResponse) Reset() { *x = DeleteWorkspaceResponse{} - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[217] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16676,7 +16759,7 @@ func (x *DeleteWorkspaceResponse) String() string { func (*DeleteWorkspaceResponse) ProtoMessage() {} func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[216] + mi := &file_openshell_proto_msgTypes[217] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16689,7 +16772,7 @@ func (x *DeleteWorkspaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkspaceResponse.ProtoReflect.Descriptor instead. func (*DeleteWorkspaceResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{216} + return file_openshell_proto_rawDescGZIP(), []int{217} } func (x *DeleteWorkspaceResponse) GetOutcome() DeletionOutcome { @@ -16713,7 +16796,7 @@ type WorkspaceMember struct { func (x *WorkspaceMember) Reset() { *x = WorkspaceMember{} - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[218] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16725,7 +16808,7 @@ func (x *WorkspaceMember) String() string { func (*WorkspaceMember) ProtoMessage() {} func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[217] + mi := &file_openshell_proto_msgTypes[218] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16738,7 +16821,7 @@ func (x *WorkspaceMember) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkspaceMember.ProtoReflect.Descriptor instead. func (*WorkspaceMember) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{217} + return file_openshell_proto_rawDescGZIP(), []int{218} } func (x *WorkspaceMember) GetMetadata() *datamodelv1.ObjectMeta { @@ -16779,7 +16862,7 @@ type AddWorkspaceMemberRequest struct { func (x *AddWorkspaceMemberRequest) Reset() { *x = AddWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[219] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16791,7 +16874,7 @@ func (x *AddWorkspaceMemberRequest) String() string { func (*AddWorkspaceMemberRequest) ProtoMessage() {} func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[218] + mi := &file_openshell_proto_msgTypes[219] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16804,7 +16887,7 @@ func (x *AddWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{218} + return file_openshell_proto_rawDescGZIP(), []int{219} } func (x *AddWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16845,7 +16928,7 @@ type AddWorkspaceMemberResponse struct { func (x *AddWorkspaceMemberResponse) Reset() { *x = AddWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[220] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16857,7 +16940,7 @@ func (x *AddWorkspaceMemberResponse) String() string { func (*AddWorkspaceMemberResponse) ProtoMessage() {} func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[219] + mi := &file_openshell_proto_msgTypes[220] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16870,7 +16953,7 @@ func (x *AddWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*AddWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{219} + return file_openshell_proto_rawDescGZIP(), []int{220} } func (x *AddWorkspaceMemberResponse) GetMember() *WorkspaceMember { @@ -16896,7 +16979,7 @@ type RemoveWorkspaceMemberRequest struct { func (x *RemoveWorkspaceMemberRequest) Reset() { *x = RemoveWorkspaceMemberRequest{} - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[221] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16908,7 +16991,7 @@ func (x *RemoveWorkspaceMemberRequest) String() string { func (*RemoveWorkspaceMemberRequest) ProtoMessage() {} func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[220] + mi := &file_openshell_proto_msgTypes[221] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16921,7 +17004,7 @@ func (x *RemoveWorkspaceMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberRequest.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{220} + return file_openshell_proto_rawDescGZIP(), []int{221} } func (x *RemoveWorkspaceMemberRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -16962,7 +17045,7 @@ type RemoveWorkspaceMemberResponse struct { func (x *RemoveWorkspaceMemberResponse) Reset() { *x = RemoveWorkspaceMemberResponse{} - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[222] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16974,7 +17057,7 @@ func (x *RemoveWorkspaceMemberResponse) String() string { func (*RemoveWorkspaceMemberResponse) ProtoMessage() {} func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[221] + mi := &file_openshell_proto_msgTypes[222] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16987,7 +17070,7 @@ func (x *RemoveWorkspaceMemberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveWorkspaceMemberResponse.ProtoReflect.Descriptor instead. func (*RemoveWorkspaceMemberResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{221} + return file_openshell_proto_rawDescGZIP(), []int{222} } func (x *RemoveWorkspaceMemberResponse) GetOutcome() DeletionOutcome { @@ -17014,7 +17097,7 @@ type ListWorkspaceMembersRequest struct { func (x *ListWorkspaceMembersRequest) Reset() { *x = ListWorkspaceMembersRequest{} - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[223] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17026,7 +17109,7 @@ func (x *ListWorkspaceMembersRequest) String() string { func (*ListWorkspaceMembersRequest) ProtoMessage() {} func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[222] + mi := &file_openshell_proto_msgTypes[223] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17039,7 +17122,7 @@ func (x *ListWorkspaceMembersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersRequest.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{222} + return file_openshell_proto_rawDescGZIP(), []int{223} } func (x *ListWorkspaceMembersRequest) GetWorkspaceScope() *datamodelv1.WorkspaceSelector { @@ -17075,7 +17158,7 @@ type ListWorkspaceMembersResponse struct { func (x *ListWorkspaceMembersResponse) Reset() { *x = ListWorkspaceMembersResponse{} - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[224] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17087,7 +17170,7 @@ func (x *ListWorkspaceMembersResponse) String() string { func (*ListWorkspaceMembersResponse) ProtoMessage() {} func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[223] + mi := &file_openshell_proto_msgTypes[224] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17100,7 +17183,7 @@ func (x *ListWorkspaceMembersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkspaceMembersResponse.ProtoReflect.Descriptor instead. func (*ListWorkspaceMembersResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{223} + return file_openshell_proto_rawDescGZIP(), []int{224} } func (x *ListWorkspaceMembersResponse) GetMembers() []*WorkspaceMember { @@ -17135,7 +17218,7 @@ type ExtensionServiceCredential struct { func (x *ExtensionServiceCredential) Reset() { *x = ExtensionServiceCredential{} - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[225] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17147,7 +17230,7 @@ func (x *ExtensionServiceCredential) String() string { func (*ExtensionServiceCredential) ProtoMessage() {} func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[224] + mi := &file_openshell_proto_msgTypes[225] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17160,7 +17243,7 @@ func (x *ExtensionServiceCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionServiceCredential.ProtoReflect.Descriptor instead. func (*ExtensionServiceCredential) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{224} + return file_openshell_proto_rawDescGZIP(), []int{225} } func (x *ExtensionServiceCredential) GetServiceName() string { @@ -17197,7 +17280,7 @@ type EndpointObservation struct { func (x *EndpointObservation) Reset() { *x = EndpointObservation{} - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[226] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17209,7 +17292,7 @@ func (x *EndpointObservation) String() string { func (*EndpointObservation) ProtoMessage() {} func (x *EndpointObservation) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[225] + mi := &file_openshell_proto_msgTypes[226] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17222,7 +17305,7 @@ func (x *EndpointObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointObservation.ProtoReflect.Descriptor instead. func (*EndpointObservation) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{225} + return file_openshell_proto_rawDescGZIP(), []int{226} } func (x *EndpointObservation) GetEndpointId() string { @@ -17265,7 +17348,7 @@ type ReportEndpointStatusRequest struct { func (x *ReportEndpointStatusRequest) Reset() { *x = ReportEndpointStatusRequest{} - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[227] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17277,7 +17360,7 @@ func (x *ReportEndpointStatusRequest) String() string { func (*ReportEndpointStatusRequest) ProtoMessage() {} func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[226] + mi := &file_openshell_proto_msgTypes[227] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17290,7 +17373,7 @@ func (x *ReportEndpointStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusRequest.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusRequest) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{226} + return file_openshell_proto_rawDescGZIP(), []int{227} } func (x *ReportEndpointStatusRequest) GetSandboxId() string { @@ -17351,7 +17434,7 @@ type ReportEndpointStatusResponse struct { func (x *ReportEndpointStatusResponse) Reset() { *x = ReportEndpointStatusResponse{} - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[228] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17363,7 +17446,7 @@ func (x *ReportEndpointStatusResponse) String() string { func (*ReportEndpointStatusResponse) ProtoMessage() {} func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[227] + mi := &file_openshell_proto_msgTypes[228] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17376,7 +17459,7 @@ func (x *ReportEndpointStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportEndpointStatusResponse.ProtoReflect.Descriptor instead. func (*ReportEndpointStatusResponse) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{227} + return file_openshell_proto_rawDescGZIP(), []int{228} } // A configured endpoint and its last accepted network result in one record. @@ -17405,7 +17488,7 @@ type EndpointStatus struct { func (x *EndpointStatus) Reset() { *x = EndpointStatus{} - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[229] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17417,7 +17500,7 @@ func (x *EndpointStatus) String() string { func (*EndpointStatus) ProtoMessage() {} func (x *EndpointStatus) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[228] + mi := &file_openshell_proto_msgTypes[229] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17430,7 +17513,7 @@ func (x *EndpointStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointStatus.ProtoReflect.Descriptor instead. func (*EndpointStatus) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{228} + return file_openshell_proto_rawDescGZIP(), []int{229} } func (x *EndpointStatus) GetEndpointId() string { @@ -17500,7 +17583,7 @@ type SandboxProvisioning struct { func (x *SandboxProvisioning) Reset() { *x = SandboxProvisioning{} - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[230] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17512,7 +17595,7 @@ func (x *SandboxProvisioning) String() string { func (*SandboxProvisioning) ProtoMessage() {} func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[229] + mi := &file_openshell_proto_msgTypes[230] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17525,7 +17608,7 @@ func (x *SandboxProvisioning) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxProvisioning.ProtoReflect.Descriptor instead. func (*SandboxProvisioning) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{229} + return file_openshell_proto_rawDescGZIP(), []int{230} } func (x *SandboxProvisioning) GetAttemptId() string { @@ -17618,7 +17701,7 @@ type SandboxServiceExposure struct { func (x *SandboxServiceExposure) Reset() { *x = SandboxServiceExposure{} - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[231] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17630,7 +17713,7 @@ func (x *SandboxServiceExposure) String() string { func (*SandboxServiceExposure) ProtoMessage() {} func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { - mi := &file_openshell_proto_msgTypes[230] + mi := &file_openshell_proto_msgTypes[231] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17643,7 +17726,7 @@ func (x *SandboxServiceExposure) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxServiceExposure.ProtoReflect.Descriptor instead. func (*SandboxServiceExposure) Descriptor() ([]byte, []int) { - return file_openshell_proto_rawDescGZIP(), []int{230} + return file_openshell_proto_rawDescGZIP(), []int{231} } func (x *SandboxServiceExposure) GetService() string { @@ -18381,7 +18464,7 @@ const file_openshell_proto_rawDesc = "" + "\n" + "request_id\x18\x06 \x01(\tR\trequestId\"g\n" + "\x1dDeleteProviderRefreshResponse\x127\n" + - "\aoutcome\x18\x02 \x01(\x0e2\x1d.openshell.v1.DeletionOutcomeR\aoutcomeJ\x04\b\x01\x10\x02R\adeleted\"\xd8\x05\n" + + "\aoutcome\x18\x02 \x01(\x0e2\x1d.openshell.v1.DeletionOutcomeR\aoutcomeJ\x04\b\x01\x10\x02R\adeleted\"\x91\x06\n" + "\x0fProviderProfile\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12!\n" + "\fdisplay_name\x18\x02 \x01(\tR\vdisplayName\x12 \n" + @@ -18396,10 +18479,15 @@ const file_openshell_proto_rawDesc = "" + " \x01(\x04R\x0fresourceVersion\x12P\n" + "\vannotations\x18\v \x03(\v2..openshell.v1.ProviderProfile.AnnotationsEntryR\vannotations\x12\x16\n" + "\x06source\x18\f \x01(\tR\x06source\x12\x14\n" + - "\x05scope\x18\r \x01(\tR\x05scope\x1a>\n" + + "\x05scope\x18\r \x01(\tR\x05scope\x127\n" + + "\x05files\x18\x0e \x03(\v2!.openshell.v1.ProviderProfileFileR\x05files\x1a>\n" + "\x10AnnotationsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"R\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\\\n" + + "\x13ProviderProfileFile\x12\x12\n" + + "\x04path\x18\x01 \x01(\tR\x04path\x12\x18\n" + + "\acontent\x18\x02 \x01(\tR\acontent\x12\x17\n" + + "\aenv_var\x18\x03 \x01(\tR\x06envVar\"R\n" + "\x17ProviderProfileResponse\x127\n" + "\aprofile\x18\x01 \x01(\v2\x1d.openshell.v1.ProviderProfileR\aprofile\"\x81\x01\n" + "\x1cListProviderProfilesResponse\x129\n" + @@ -18452,8 +18540,7 @@ const file_openshell_proto_rawDesc = "" + "\x17StaticCredentialBinding\x12K\n" + "\tendpoints\x18\x01 \x03(\v2-.openshell.v1.StaticCredentialEndpointBindingR\tendpoints\x12/\n" + "\x13credential_identity\x18\x02 \x01(\tR\x12credentialIdentity\x12<\n" + - "\x1aworkload_credential_handle\x18\x03 \x01(\tR\x18workloadCredentialHandle\"\x8a\n" + - "\n" + + "\x1aworkload_credential_handle\x18\x03 \x01(\tR\x18workloadCredentialHandle\"\x9a\v\n" + "%GetSandboxProviderEnvironmentResponse\x12l\n" + "\venvironment\x18\x01 \x03(\v2D.openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntryB\x04\x88\xb5\x18\x01R\venvironment\x122\n" + "\x15provider_env_revision\x18\x02 \x01(\x04R\x13providerEnvRevision\x12\x92\x01\n" + @@ -18464,7 +18551,9 @@ const file_openshell_proto_rawDesc = "" + "\x19provider_attachment_epoch\x18\a \x01(\tR\x17providerAttachmentEpoch\x12\x1f\n" + "\vpolicy_hash\x18\b \x01(\tR\n" + "policyHash\x12P\n" + - "\x10readiness_reason\x18\t \x01(\x0e2%.openshell.v1.ProviderReadinessReasonR\x0freadinessReason\x1a>\n" + + "\x10readiness_reason\x18\t \x01(\x0e2%.openshell.v1.ProviderReadinessReasonR\x0freadinessReason\x12T\n" + + "\x05files\x18\n" + + " \x03(\v2>.openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntryR\x05files\x1a>\n" + "\x10EnvironmentEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1ah\n" + @@ -18476,7 +18565,11 @@ const file_openshell_proto_rawDesc = "" + "\x05value\x18\x02 \x01(\v2'.openshell.v1.ProviderProfileCredentialR\x05value:\x028\x01\x1ar\n" + "\x1dStaticCredentialBindingsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12;\n" + - "\x05value\x18\x02 \x01(\v2%.openshell.v1.StaticCredentialBindingR\x05value:\x028\x01J\x04\b\x03\x10\x04R\x18credential_expires_at_ms\"\xbd\x01\n" + + "\x05value\x18\x02 \x01(\v2%.openshell.v1.StaticCredentialBindingR\x05value:\x028\x01\x1a8\n" + + "\n" + + "FilesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01J\x04\b\x03\x10\x04R\x18credential_expires_at_ms\"\xbd\x01\n" + "#ExchangeProviderSubjectTokenRequest\x12\x1d\n" + "\n" + "sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x1a\n" + @@ -19310,7 +19403,7 @@ func file_openshell_proto_rawDescGZIP() []byte { } var file_openshell_proto_enumTypes = make([]protoimpl.EnumInfo, 19) -var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 253) +var file_openshell_proto_msgTypes = make([]protoimpl.MessageInfo, 255) var file_openshell_proto_goTypes = []any{ (ExtensionKind)(0), // 0: openshell.v1.ExtensionKind (SandboxPhase)(0), // 1: openshell.v1.SandboxPhase @@ -19453,162 +19546,164 @@ var file_openshell_proto_goTypes = []any{ (*DeleteProviderRefreshRequest)(nil), // 138: openshell.v1.DeleteProviderRefreshRequest (*DeleteProviderRefreshResponse)(nil), // 139: openshell.v1.DeleteProviderRefreshResponse (*ProviderProfile)(nil), // 140: openshell.v1.ProviderProfile - (*ProviderProfileResponse)(nil), // 141: openshell.v1.ProviderProfileResponse - (*ListProviderProfilesResponse)(nil), // 142: openshell.v1.ListProviderProfilesResponse - (*ImportProviderProfilesRequest)(nil), // 143: openshell.v1.ImportProviderProfilesRequest - (*ImportProviderProfilesResponse)(nil), // 144: openshell.v1.ImportProviderProfilesResponse - (*UpdateProviderProfilesRequest)(nil), // 145: openshell.v1.UpdateProviderProfilesRequest - (*UpdateProviderProfilesResponse)(nil), // 146: openshell.v1.UpdateProviderProfilesResponse - (*LintProviderProfilesRequest)(nil), // 147: openshell.v1.LintProviderProfilesRequest - (*LintProviderProfilesResponse)(nil), // 148: openshell.v1.LintProviderProfilesResponse - (*DeleteProviderResponse)(nil), // 149: openshell.v1.DeleteProviderResponse - (*DeleteProviderProfileRequest)(nil), // 150: openshell.v1.DeleteProviderProfileRequest - (*DeleteProviderProfileResponse)(nil), // 151: openshell.v1.DeleteProviderProfileResponse - (*GetSandboxProviderEnvironmentRequest)(nil), // 152: openshell.v1.GetSandboxProviderEnvironmentRequest - (*StaticCredentialEndpointBinding)(nil), // 153: openshell.v1.StaticCredentialEndpointBinding - (*StaticCredentialBinding)(nil), // 154: openshell.v1.StaticCredentialBinding - (*GetSandboxProviderEnvironmentResponse)(nil), // 155: openshell.v1.GetSandboxProviderEnvironmentResponse - (*ExchangeProviderSubjectTokenRequest)(nil), // 156: openshell.v1.ExchangeProviderSubjectTokenRequest - (*ExchangeProviderSubjectTokenResponse)(nil), // 157: openshell.v1.ExchangeProviderSubjectTokenResponse - (*UpdateConfigRequest)(nil), // 158: openshell.v1.UpdateConfigRequest - (*PolicyMergeOperation)(nil), // 159: openshell.v1.PolicyMergeOperation - (*AddNetworkRule)(nil), // 160: openshell.v1.AddNetworkRule - (*RemoveNetworkEndpoint)(nil), // 161: openshell.v1.RemoveNetworkEndpoint - (*RemoveNetworkRule)(nil), // 162: openshell.v1.RemoveNetworkRule - (*L7RuleTarget)(nil), // 163: openshell.v1.L7RuleTarget - (*AddDenyRules)(nil), // 164: openshell.v1.AddDenyRules - (*AddAllowRules)(nil), // 165: openshell.v1.AddAllowRules - (*RemoveNetworkBinary)(nil), // 166: openshell.v1.RemoveNetworkBinary - (*UpdateConfigResponse)(nil), // 167: openshell.v1.UpdateConfigResponse - (*GetSandboxPolicyStatusRequest)(nil), // 168: openshell.v1.GetSandboxPolicyStatusRequest - (*GetSandboxPolicyStatusResponse)(nil), // 169: openshell.v1.GetSandboxPolicyStatusResponse - (*ListSandboxPoliciesRequest)(nil), // 170: openshell.v1.ListSandboxPoliciesRequest - (*ListSandboxPoliciesResponse)(nil), // 171: openshell.v1.ListSandboxPoliciesResponse - (*ReportPolicyStatusRequest)(nil), // 172: openshell.v1.ReportPolicyStatusRequest - (*ReportPolicyStatusResponse)(nil), // 173: openshell.v1.ReportPolicyStatusResponse - (*SandboxConfigurationAdmission)(nil), // 174: openshell.v1.SandboxConfigurationAdmission - (*ReportSandboxConfigurationRequest)(nil), // 175: openshell.v1.ReportSandboxConfigurationRequest - (*ReportSandboxConfigurationResponse)(nil), // 176: openshell.v1.ReportSandboxConfigurationResponse - (*SandboxPolicyRevision)(nil), // 177: openshell.v1.SandboxPolicyRevision - (*GetSandboxLogsRequest)(nil), // 178: openshell.v1.GetSandboxLogsRequest - (*PushSandboxLogsRequest)(nil), // 179: openshell.v1.PushSandboxLogsRequest - (*PushSandboxLogsResponse)(nil), // 180: openshell.v1.PushSandboxLogsResponse - (*GetSandboxLogsResponse)(nil), // 181: openshell.v1.GetSandboxLogsResponse - (*SupervisorMessage)(nil), // 182: openshell.v1.SupervisorMessage - (*GatewayMessage)(nil), // 183: openshell.v1.GatewayMessage - (*SupervisorHello)(nil), // 184: openshell.v1.SupervisorHello - (*SessionAccepted)(nil), // 185: openshell.v1.SessionAccepted - (*SessionRejected)(nil), // 186: openshell.v1.SessionRejected - (*SupervisorHeartbeat)(nil), // 187: openshell.v1.SupervisorHeartbeat - (*GatewayHeartbeat)(nil), // 188: openshell.v1.GatewayHeartbeat - (*ReportMainProcessExitRequest)(nil), // 189: openshell.v1.ReportMainProcessExitRequest - (*ReportMainProcessExitResponse)(nil), // 190: openshell.v1.ReportMainProcessExitResponse - (*FinalizeMainProcessExitRequest)(nil), // 191: openshell.v1.FinalizeMainProcessExitRequest - (*FinalizeMainProcessExitResponse)(nil), // 192: openshell.v1.FinalizeMainProcessExitResponse - (*RelayOpen)(nil), // 193: openshell.v1.RelayOpen - (*SshRelayTarget)(nil), // 194: openshell.v1.SshRelayTarget - (*TcpRelayTarget)(nil), // 195: openshell.v1.TcpRelayTarget - (*RelayInit)(nil), // 196: openshell.v1.RelayInit - (*RelayFrame)(nil), // 197: openshell.v1.RelayFrame - (*PeerRelayInit)(nil), // 198: openshell.v1.PeerRelayInit - (*PeerRelayFrame)(nil), // 199: openshell.v1.PeerRelayFrame - (*RelayOpenResult)(nil), // 200: openshell.v1.RelayOpenResult - (*RelayClose)(nil), // 201: openshell.v1.RelayClose - (*L7RequestSample)(nil), // 202: openshell.v1.L7RequestSample - (*DenialSummary)(nil), // 203: openshell.v1.DenialSummary - (*DenialGroupCount)(nil), // 204: openshell.v1.DenialGroupCount - (*NetworkActivitySummary)(nil), // 205: openshell.v1.NetworkActivitySummary - (*PolicyChunk)(nil), // 206: openshell.v1.PolicyChunk - (*DraftPolicyUpdate)(nil), // 207: openshell.v1.DraftPolicyUpdate - (*SubmitPolicyAnalysisRequest)(nil), // 208: openshell.v1.SubmitPolicyAnalysisRequest - (*SubmitPolicyAnalysisResponse)(nil), // 209: openshell.v1.SubmitPolicyAnalysisResponse - (*GetDraftPolicyRequest)(nil), // 210: openshell.v1.GetDraftPolicyRequest - (*GetDraftPolicyResponse)(nil), // 211: openshell.v1.GetDraftPolicyResponse - (*ApproveDraftChunkRequest)(nil), // 212: openshell.v1.ApproveDraftChunkRequest - (*ApproveDraftChunkResponse)(nil), // 213: openshell.v1.ApproveDraftChunkResponse - (*RejectDraftChunkRequest)(nil), // 214: openshell.v1.RejectDraftChunkRequest - (*RejectDraftChunkResponse)(nil), // 215: openshell.v1.RejectDraftChunkResponse - (*DraftChunkApproval)(nil), // 216: openshell.v1.DraftChunkApproval - (*ApproveAllDraftChunksRequest)(nil), // 217: openshell.v1.ApproveAllDraftChunksRequest - (*ApproveAllDraftChunksResponse)(nil), // 218: openshell.v1.ApproveAllDraftChunksResponse - (*EditDraftChunkRequest)(nil), // 219: openshell.v1.EditDraftChunkRequest - (*EditDraftChunkResponse)(nil), // 220: openshell.v1.EditDraftChunkResponse - (*UndoDraftChunkRequest)(nil), // 221: openshell.v1.UndoDraftChunkRequest - (*UndoDraftChunkResponse)(nil), // 222: openshell.v1.UndoDraftChunkResponse - (*ClearDraftChunksRequest)(nil), // 223: openshell.v1.ClearDraftChunksRequest - (*ClearDraftChunksResponse)(nil), // 224: openshell.v1.ClearDraftChunksResponse - (*GetDraftHistoryRequest)(nil), // 225: openshell.v1.GetDraftHistoryRequest - (*DraftHistoryEntry)(nil), // 226: openshell.v1.DraftHistoryEntry - (*GetDraftHistoryResponse)(nil), // 227: openshell.v1.GetDraftHistoryResponse - (*CreateWorkspaceRequest)(nil), // 228: openshell.v1.CreateWorkspaceRequest - (*CreateWorkspaceResponse)(nil), // 229: openshell.v1.CreateWorkspaceResponse - (*GetWorkspaceRequest)(nil), // 230: openshell.v1.GetWorkspaceRequest - (*GetWorkspaceResponse)(nil), // 231: openshell.v1.GetWorkspaceResponse - (*ListWorkspacesRequest)(nil), // 232: openshell.v1.ListWorkspacesRequest - (*ListWorkspacesResponse)(nil), // 233: openshell.v1.ListWorkspacesResponse - (*DeleteWorkspaceRequest)(nil), // 234: openshell.v1.DeleteWorkspaceRequest - (*DeleteWorkspaceResponse)(nil), // 235: openshell.v1.DeleteWorkspaceResponse - (*WorkspaceMember)(nil), // 236: openshell.v1.WorkspaceMember - (*AddWorkspaceMemberRequest)(nil), // 237: openshell.v1.AddWorkspaceMemberRequest - (*AddWorkspaceMemberResponse)(nil), // 238: openshell.v1.AddWorkspaceMemberResponse - (*RemoveWorkspaceMemberRequest)(nil), // 239: openshell.v1.RemoveWorkspaceMemberRequest - (*RemoveWorkspaceMemberResponse)(nil), // 240: openshell.v1.RemoveWorkspaceMemberResponse - (*ListWorkspaceMembersRequest)(nil), // 241: openshell.v1.ListWorkspaceMembersRequest - (*ListWorkspaceMembersResponse)(nil), // 242: openshell.v1.ListWorkspaceMembersResponse - (*ExtensionServiceCredential)(nil), // 243: openshell.v1.ExtensionServiceCredential - (*EndpointObservation)(nil), // 244: openshell.v1.EndpointObservation - (*ReportEndpointStatusRequest)(nil), // 245: openshell.v1.ReportEndpointStatusRequest - (*ReportEndpointStatusResponse)(nil), // 246: openshell.v1.ReportEndpointStatusResponse - (*EndpointStatus)(nil), // 247: openshell.v1.EndpointStatus - (*SandboxProvisioning)(nil), // 248: openshell.v1.SandboxProvisioning - (*SandboxServiceExposure)(nil), // 249: openshell.v1.SandboxServiceExposure - nil, // 250: openshell.v1.SandboxSpec.EnvironmentEntry - nil, // 251: openshell.v1.SandboxTemplate.LabelsEntry - nil, // 252: openshell.v1.SandboxTemplate.AnnotationsEntry - nil, // 253: openshell.v1.SandboxTemplate.EnvironmentEntry - nil, // 254: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry - nil, // 255: openshell.v1.PlatformEvent.MetadataEntry - nil, // 256: openshell.v1.CreateSandboxRequest.LabelsEntry - nil, // 257: openshell.v1.CreateSandboxRequest.AnnotationsEntry - nil, // 258: openshell.v1.SandboxResponse.ServiceUrlsEntry - nil, // 259: openshell.v1.ExecSandboxRequest.EnvironmentEntry - nil, // 260: openshell.v1.SandboxLogLine.FieldsEntry - nil, // 261: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - nil, // 262: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - nil, // 263: openshell.v1.ProviderProfile.AnnotationsEntry - nil, // 264: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - nil, // 265: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - nil, // 266: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - nil, // 267: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - nil, // 268: openshell.v1.UpdateConfigRequest.AnnotationsEntry - nil, // 269: openshell.v1.UpdateConfigResponse.AnnotationsEntry - nil, // 270: openshell.v1.SandboxPolicyRevision.ProvenanceEntry - nil, // 271: openshell.v1.CreateWorkspaceRequest.LabelsEntry - (*timestamppb.Timestamp)(nil), // 272: google.protobuf.Timestamp - (*datamodelv1.ObjectMeta)(nil), // 273: openshell.datamodel.v1.ObjectMeta - (*sandboxv1.SandboxPolicy)(nil), // 274: openshell.sandbox.v1.SandboxPolicy - (*structpb.Struct)(nil), // 275: google.protobuf.Struct - (*durationpb.Duration)(nil), // 276: google.protobuf.Duration - (*datamodelv1.WorkspaceSelector)(nil), // 277: openshell.datamodel.v1.WorkspaceSelector - (*datamodelv1.Provider)(nil), // 278: openshell.datamodel.v1.Provider - (sandboxv1.PolicySource)(0), // 279: openshell.sandbox.v1.PolicySource - (*sandboxv1.NetworkEndpoint)(nil), // 280: openshell.sandbox.v1.NetworkEndpoint - (*sandboxv1.NetworkBinary)(nil), // 281: openshell.sandbox.v1.NetworkBinary - (*sandboxv1.SettingValue)(nil), // 282: openshell.sandbox.v1.SettingValue - (*sandboxv1.NetworkPolicyRule)(nil), // 283: openshell.sandbox.v1.NetworkPolicyRule - (*sandboxv1.L7DenyRule)(nil), // 284: openshell.sandbox.v1.L7DenyRule - (*sandboxv1.L7Rule)(nil), // 285: openshell.sandbox.v1.L7Rule - (*datamodelv1.Workspace)(nil), // 286: openshell.datamodel.v1.Workspace - (*sandboxv1.GetSandboxConfigRequest)(nil), // 287: openshell.sandbox.v1.GetSandboxConfigRequest - (*sandboxv1.GetGatewayConfigRequest)(nil), // 288: openshell.sandbox.v1.GetGatewayConfigRequest - (*sandboxv1.GetSandboxConfigResponse)(nil), // 289: openshell.sandbox.v1.GetSandboxConfigResponse - (*sandboxv1.GetGatewayConfigResponse)(nil), // 290: openshell.sandbox.v1.GetGatewayConfigResponse + (*ProviderProfileFile)(nil), // 141: openshell.v1.ProviderProfileFile + (*ProviderProfileResponse)(nil), // 142: openshell.v1.ProviderProfileResponse + (*ListProviderProfilesResponse)(nil), // 143: openshell.v1.ListProviderProfilesResponse + (*ImportProviderProfilesRequest)(nil), // 144: openshell.v1.ImportProviderProfilesRequest + (*ImportProviderProfilesResponse)(nil), // 145: openshell.v1.ImportProviderProfilesResponse + (*UpdateProviderProfilesRequest)(nil), // 146: openshell.v1.UpdateProviderProfilesRequest + (*UpdateProviderProfilesResponse)(nil), // 147: openshell.v1.UpdateProviderProfilesResponse + (*LintProviderProfilesRequest)(nil), // 148: openshell.v1.LintProviderProfilesRequest + (*LintProviderProfilesResponse)(nil), // 149: openshell.v1.LintProviderProfilesResponse + (*DeleteProviderResponse)(nil), // 150: openshell.v1.DeleteProviderResponse + (*DeleteProviderProfileRequest)(nil), // 151: openshell.v1.DeleteProviderProfileRequest + (*DeleteProviderProfileResponse)(nil), // 152: openshell.v1.DeleteProviderProfileResponse + (*GetSandboxProviderEnvironmentRequest)(nil), // 153: openshell.v1.GetSandboxProviderEnvironmentRequest + (*StaticCredentialEndpointBinding)(nil), // 154: openshell.v1.StaticCredentialEndpointBinding + (*StaticCredentialBinding)(nil), // 155: openshell.v1.StaticCredentialBinding + (*GetSandboxProviderEnvironmentResponse)(nil), // 156: openshell.v1.GetSandboxProviderEnvironmentResponse + (*ExchangeProviderSubjectTokenRequest)(nil), // 157: openshell.v1.ExchangeProviderSubjectTokenRequest + (*ExchangeProviderSubjectTokenResponse)(nil), // 158: openshell.v1.ExchangeProviderSubjectTokenResponse + (*UpdateConfigRequest)(nil), // 159: openshell.v1.UpdateConfigRequest + (*PolicyMergeOperation)(nil), // 160: openshell.v1.PolicyMergeOperation + (*AddNetworkRule)(nil), // 161: openshell.v1.AddNetworkRule + (*RemoveNetworkEndpoint)(nil), // 162: openshell.v1.RemoveNetworkEndpoint + (*RemoveNetworkRule)(nil), // 163: openshell.v1.RemoveNetworkRule + (*L7RuleTarget)(nil), // 164: openshell.v1.L7RuleTarget + (*AddDenyRules)(nil), // 165: openshell.v1.AddDenyRules + (*AddAllowRules)(nil), // 166: openshell.v1.AddAllowRules + (*RemoveNetworkBinary)(nil), // 167: openshell.v1.RemoveNetworkBinary + (*UpdateConfigResponse)(nil), // 168: openshell.v1.UpdateConfigResponse + (*GetSandboxPolicyStatusRequest)(nil), // 169: openshell.v1.GetSandboxPolicyStatusRequest + (*GetSandboxPolicyStatusResponse)(nil), // 170: openshell.v1.GetSandboxPolicyStatusResponse + (*ListSandboxPoliciesRequest)(nil), // 171: openshell.v1.ListSandboxPoliciesRequest + (*ListSandboxPoliciesResponse)(nil), // 172: openshell.v1.ListSandboxPoliciesResponse + (*ReportPolicyStatusRequest)(nil), // 173: openshell.v1.ReportPolicyStatusRequest + (*ReportPolicyStatusResponse)(nil), // 174: openshell.v1.ReportPolicyStatusResponse + (*SandboxConfigurationAdmission)(nil), // 175: openshell.v1.SandboxConfigurationAdmission + (*ReportSandboxConfigurationRequest)(nil), // 176: openshell.v1.ReportSandboxConfigurationRequest + (*ReportSandboxConfigurationResponse)(nil), // 177: openshell.v1.ReportSandboxConfigurationResponse + (*SandboxPolicyRevision)(nil), // 178: openshell.v1.SandboxPolicyRevision + (*GetSandboxLogsRequest)(nil), // 179: openshell.v1.GetSandboxLogsRequest + (*PushSandboxLogsRequest)(nil), // 180: openshell.v1.PushSandboxLogsRequest + (*PushSandboxLogsResponse)(nil), // 181: openshell.v1.PushSandboxLogsResponse + (*GetSandboxLogsResponse)(nil), // 182: openshell.v1.GetSandboxLogsResponse + (*SupervisorMessage)(nil), // 183: openshell.v1.SupervisorMessage + (*GatewayMessage)(nil), // 184: openshell.v1.GatewayMessage + (*SupervisorHello)(nil), // 185: openshell.v1.SupervisorHello + (*SessionAccepted)(nil), // 186: openshell.v1.SessionAccepted + (*SessionRejected)(nil), // 187: openshell.v1.SessionRejected + (*SupervisorHeartbeat)(nil), // 188: openshell.v1.SupervisorHeartbeat + (*GatewayHeartbeat)(nil), // 189: openshell.v1.GatewayHeartbeat + (*ReportMainProcessExitRequest)(nil), // 190: openshell.v1.ReportMainProcessExitRequest + (*ReportMainProcessExitResponse)(nil), // 191: openshell.v1.ReportMainProcessExitResponse + (*FinalizeMainProcessExitRequest)(nil), // 192: openshell.v1.FinalizeMainProcessExitRequest + (*FinalizeMainProcessExitResponse)(nil), // 193: openshell.v1.FinalizeMainProcessExitResponse + (*RelayOpen)(nil), // 194: openshell.v1.RelayOpen + (*SshRelayTarget)(nil), // 195: openshell.v1.SshRelayTarget + (*TcpRelayTarget)(nil), // 196: openshell.v1.TcpRelayTarget + (*RelayInit)(nil), // 197: openshell.v1.RelayInit + (*RelayFrame)(nil), // 198: openshell.v1.RelayFrame + (*PeerRelayInit)(nil), // 199: openshell.v1.PeerRelayInit + (*PeerRelayFrame)(nil), // 200: openshell.v1.PeerRelayFrame + (*RelayOpenResult)(nil), // 201: openshell.v1.RelayOpenResult + (*RelayClose)(nil), // 202: openshell.v1.RelayClose + (*L7RequestSample)(nil), // 203: openshell.v1.L7RequestSample + (*DenialSummary)(nil), // 204: openshell.v1.DenialSummary + (*DenialGroupCount)(nil), // 205: openshell.v1.DenialGroupCount + (*NetworkActivitySummary)(nil), // 206: openshell.v1.NetworkActivitySummary + (*PolicyChunk)(nil), // 207: openshell.v1.PolicyChunk + (*DraftPolicyUpdate)(nil), // 208: openshell.v1.DraftPolicyUpdate + (*SubmitPolicyAnalysisRequest)(nil), // 209: openshell.v1.SubmitPolicyAnalysisRequest + (*SubmitPolicyAnalysisResponse)(nil), // 210: openshell.v1.SubmitPolicyAnalysisResponse + (*GetDraftPolicyRequest)(nil), // 211: openshell.v1.GetDraftPolicyRequest + (*GetDraftPolicyResponse)(nil), // 212: openshell.v1.GetDraftPolicyResponse + (*ApproveDraftChunkRequest)(nil), // 213: openshell.v1.ApproveDraftChunkRequest + (*ApproveDraftChunkResponse)(nil), // 214: openshell.v1.ApproveDraftChunkResponse + (*RejectDraftChunkRequest)(nil), // 215: openshell.v1.RejectDraftChunkRequest + (*RejectDraftChunkResponse)(nil), // 216: openshell.v1.RejectDraftChunkResponse + (*DraftChunkApproval)(nil), // 217: openshell.v1.DraftChunkApproval + (*ApproveAllDraftChunksRequest)(nil), // 218: openshell.v1.ApproveAllDraftChunksRequest + (*ApproveAllDraftChunksResponse)(nil), // 219: openshell.v1.ApproveAllDraftChunksResponse + (*EditDraftChunkRequest)(nil), // 220: openshell.v1.EditDraftChunkRequest + (*EditDraftChunkResponse)(nil), // 221: openshell.v1.EditDraftChunkResponse + (*UndoDraftChunkRequest)(nil), // 222: openshell.v1.UndoDraftChunkRequest + (*UndoDraftChunkResponse)(nil), // 223: openshell.v1.UndoDraftChunkResponse + (*ClearDraftChunksRequest)(nil), // 224: openshell.v1.ClearDraftChunksRequest + (*ClearDraftChunksResponse)(nil), // 225: openshell.v1.ClearDraftChunksResponse + (*GetDraftHistoryRequest)(nil), // 226: openshell.v1.GetDraftHistoryRequest + (*DraftHistoryEntry)(nil), // 227: openshell.v1.DraftHistoryEntry + (*GetDraftHistoryResponse)(nil), // 228: openshell.v1.GetDraftHistoryResponse + (*CreateWorkspaceRequest)(nil), // 229: openshell.v1.CreateWorkspaceRequest + (*CreateWorkspaceResponse)(nil), // 230: openshell.v1.CreateWorkspaceResponse + (*GetWorkspaceRequest)(nil), // 231: openshell.v1.GetWorkspaceRequest + (*GetWorkspaceResponse)(nil), // 232: openshell.v1.GetWorkspaceResponse + (*ListWorkspacesRequest)(nil), // 233: openshell.v1.ListWorkspacesRequest + (*ListWorkspacesResponse)(nil), // 234: openshell.v1.ListWorkspacesResponse + (*DeleteWorkspaceRequest)(nil), // 235: openshell.v1.DeleteWorkspaceRequest + (*DeleteWorkspaceResponse)(nil), // 236: openshell.v1.DeleteWorkspaceResponse + (*WorkspaceMember)(nil), // 237: openshell.v1.WorkspaceMember + (*AddWorkspaceMemberRequest)(nil), // 238: openshell.v1.AddWorkspaceMemberRequest + (*AddWorkspaceMemberResponse)(nil), // 239: openshell.v1.AddWorkspaceMemberResponse + (*RemoveWorkspaceMemberRequest)(nil), // 240: openshell.v1.RemoveWorkspaceMemberRequest + (*RemoveWorkspaceMemberResponse)(nil), // 241: openshell.v1.RemoveWorkspaceMemberResponse + (*ListWorkspaceMembersRequest)(nil), // 242: openshell.v1.ListWorkspaceMembersRequest + (*ListWorkspaceMembersResponse)(nil), // 243: openshell.v1.ListWorkspaceMembersResponse + (*ExtensionServiceCredential)(nil), // 244: openshell.v1.ExtensionServiceCredential + (*EndpointObservation)(nil), // 245: openshell.v1.EndpointObservation + (*ReportEndpointStatusRequest)(nil), // 246: openshell.v1.ReportEndpointStatusRequest + (*ReportEndpointStatusResponse)(nil), // 247: openshell.v1.ReportEndpointStatusResponse + (*EndpointStatus)(nil), // 248: openshell.v1.EndpointStatus + (*SandboxProvisioning)(nil), // 249: openshell.v1.SandboxProvisioning + (*SandboxServiceExposure)(nil), // 250: openshell.v1.SandboxServiceExposure + nil, // 251: openshell.v1.SandboxSpec.EnvironmentEntry + nil, // 252: openshell.v1.SandboxTemplate.LabelsEntry + nil, // 253: openshell.v1.SandboxTemplate.AnnotationsEntry + nil, // 254: openshell.v1.SandboxTemplate.EnvironmentEntry + nil, // 255: openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + nil, // 256: openshell.v1.PlatformEvent.MetadataEntry + nil, // 257: openshell.v1.CreateSandboxRequest.LabelsEntry + nil, // 258: openshell.v1.CreateSandboxRequest.AnnotationsEntry + nil, // 259: openshell.v1.SandboxResponse.ServiceUrlsEntry + nil, // 260: openshell.v1.ExecSandboxRequest.EnvironmentEntry + nil, // 261: openshell.v1.SandboxLogLine.FieldsEntry + nil, // 262: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + nil, // 263: openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + nil, // 264: openshell.v1.ProviderProfile.AnnotationsEntry + nil, // 265: openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + nil, // 266: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + nil, // 267: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + nil, // 268: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + nil, // 269: openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + nil, // 270: openshell.v1.UpdateConfigRequest.AnnotationsEntry + nil, // 271: openshell.v1.UpdateConfigResponse.AnnotationsEntry + nil, // 272: openshell.v1.SandboxPolicyRevision.ProvenanceEntry + nil, // 273: openshell.v1.CreateWorkspaceRequest.LabelsEntry + (*timestamppb.Timestamp)(nil), // 274: google.protobuf.Timestamp + (*datamodelv1.ObjectMeta)(nil), // 275: openshell.datamodel.v1.ObjectMeta + (*sandboxv1.SandboxPolicy)(nil), // 276: openshell.sandbox.v1.SandboxPolicy + (*structpb.Struct)(nil), // 277: google.protobuf.Struct + (*durationpb.Duration)(nil), // 278: google.protobuf.Duration + (*datamodelv1.WorkspaceSelector)(nil), // 279: openshell.datamodel.v1.WorkspaceSelector + (*datamodelv1.Provider)(nil), // 280: openshell.datamodel.v1.Provider + (sandboxv1.PolicySource)(0), // 281: openshell.sandbox.v1.PolicySource + (*sandboxv1.NetworkEndpoint)(nil), // 282: openshell.sandbox.v1.NetworkEndpoint + (*sandboxv1.NetworkBinary)(nil), // 283: openshell.sandbox.v1.NetworkBinary + (*sandboxv1.SettingValue)(nil), // 284: openshell.sandbox.v1.SettingValue + (*sandboxv1.NetworkPolicyRule)(nil), // 285: openshell.sandbox.v1.NetworkPolicyRule + (*sandboxv1.L7DenyRule)(nil), // 286: openshell.sandbox.v1.L7DenyRule + (*sandboxv1.L7Rule)(nil), // 287: openshell.sandbox.v1.L7Rule + (*datamodelv1.Workspace)(nil), // 288: openshell.datamodel.v1.Workspace + (*sandboxv1.GetSandboxConfigRequest)(nil), // 289: openshell.sandbox.v1.GetSandboxConfigRequest + (*sandboxv1.GetGatewayConfigRequest)(nil), // 290: openshell.sandbox.v1.GetGatewayConfigRequest + (*sandboxv1.GetSandboxConfigResponse)(nil), // 291: openshell.sandbox.v1.GetSandboxConfigResponse + (*sandboxv1.GetGatewayConfigResponse)(nil), // 292: openshell.sandbox.v1.GetGatewayConfigResponse } var file_openshell_proto_depIdxs = []int32{ - 272, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 272, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp - 243, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential - 272, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp + 274, // 0: openshell.v1.IssueSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 274, // 1: openshell.v1.RefreshSandboxTokenResponse.expiration_time:type_name -> google.protobuf.Timestamp + 244, // 2: openshell.v1.RefreshSandboxTokenResponse.extension_credentials:type_name -> openshell.v1.ExtensionServiceCredential + 274, // 3: openshell.v1.RefreshSandboxTokenResponse.sandbox_expiration_time:type_name -> google.protobuf.Timestamp 13, // 4: openshell.v1.HealthResponse.status:type_name -> openshell.v1.ServiceStatus 13, // 5: openshell.v1.GetGatewayInfoResponse.status:type_name -> openshell.v1.ServiceStatus 30, // 6: openshell.v1.GetGatewayInfoResponse.compute_drivers:type_name -> openshell.v1.ComputeDriverInfo @@ -19619,480 +19714,482 @@ var file_openshell_proto_depIdxs = []int32{ 33, // 11: openshell.v1.ResourceCapabilities.cpu:type_name -> openshell.v1.CpuResourceCapabilities 34, // 12: openshell.v1.ResourceCapabilities.memory:type_name -> openshell.v1.MemoryResourceCapabilities 35, // 13: openshell.v1.ResourceCapabilities.gpu:type_name -> openshell.v1.GpuResourceCapabilities - 273, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 275, // 14: openshell.v1.Sandbox.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 37, // 15: openshell.v1.Sandbox.spec:type_name -> openshell.v1.SandboxSpec 48, // 16: openshell.v1.Sandbox.status:type_name -> openshell.v1.SandboxStatus 47, // 17: openshell.v1.Sandbox.created_from_workload_template:type_name -> openshell.v1.SandboxWorkloadTemplateProvenance - 250, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry + 251, // 18: openshell.v1.SandboxSpec.environment:type_name -> openshell.v1.SandboxSpec.EnvironmentEntry 40, // 19: openshell.v1.SandboxSpec.template:type_name -> openshell.v1.SandboxTemplate - 274, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 276, // 20: openshell.v1.SandboxSpec.policy:type_name -> openshell.sandbox.v1.SandboxPolicy 38, // 21: openshell.v1.SandboxSpec.resource_requirements:type_name -> openshell.v1.ResourceRequirements 16, // 22: openshell.v1.SandboxSpec.restart_policy:type_name -> openshell.v1.SandboxRestartPolicy 39, // 23: openshell.v1.ResourceRequirements.gpu:type_name -> openshell.v1.GpuResourceRequirements - 251, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry - 252, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry - 253, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry - 275, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct - 275, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct - 273, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 252, // 24: openshell.v1.SandboxTemplate.labels:type_name -> openshell.v1.SandboxTemplate.LabelsEntry + 253, // 25: openshell.v1.SandboxTemplate.annotations:type_name -> openshell.v1.SandboxTemplate.AnnotationsEntry + 254, // 26: openshell.v1.SandboxTemplate.environment:type_name -> openshell.v1.SandboxTemplate.EnvironmentEntry + 277, // 27: openshell.v1.SandboxTemplate.resources:type_name -> google.protobuf.Struct + 277, // 28: openshell.v1.SandboxTemplate.driver_config:type_name -> google.protobuf.Struct + 275, // 29: openshell.v1.SandboxWorkloadTemplate.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 42, // 30: openshell.v1.SandboxWorkloadTemplate.spec:type_name -> openshell.v1.SandboxWorkloadTemplateSpec 43, // 31: openshell.v1.SandboxWorkloadTemplateSpec.workload:type_name -> openshell.v1.SandboxWorkloadConfig - 275, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct + 277, // 32: openshell.v1.SandboxWorkloadTemplateSpec.driver_config:type_name -> google.protobuf.Struct 45, // 33: openshell.v1.SandboxWorkloadTemplateSpec.desired_service_level:type_name -> openshell.v1.SandboxServiceLevel - 254, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry + 255, // 34: openshell.v1.SandboxWorkloadConfig.environment:type_name -> openshell.v1.SandboxWorkloadConfig.EnvironmentEntry 44, // 35: openshell.v1.SandboxWorkloadConfig.resources:type_name -> openshell.v1.SandboxResources 39, // 36: openshell.v1.SandboxResources.gpu:type_name -> openshell.v1.GpuResourceRequirements 46, // 37: openshell.v1.SandboxServiceLevel.startup:type_name -> openshell.v1.SandboxStartup - 276, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration + 278, // 38: openshell.v1.SandboxStartup.ready_within:type_name -> google.protobuf.Duration 49, // 39: openshell.v1.SandboxStatus.conditions:type_name -> openshell.v1.SandboxCondition 1, // 40: openshell.v1.SandboxStatus.phase:type_name -> openshell.v1.SandboxPhase - 247, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus - 174, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 248, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning - 272, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp - 272, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp - 272, // 46: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp - 272, // 47: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp - 255, // 48: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry - 277, // 49: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 248, // 41: openshell.v1.SandboxStatus.endpoint_statuses:type_name -> openshell.v1.EndpointStatus + 175, // 42: openshell.v1.SandboxStatus.configuration_admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 249, // 43: openshell.v1.SandboxStatus.provisioning:type_name -> openshell.v1.SandboxProvisioning + 274, // 44: openshell.v1.SandboxStatus.next_restart_time:type_name -> google.protobuf.Timestamp + 274, // 45: openshell.v1.SandboxStatus.main_process_started_time:type_name -> google.protobuf.Timestamp + 274, // 46: openshell.v1.SandboxCondition.transition_time:type_name -> google.protobuf.Timestamp + 274, // 47: openshell.v1.PlatformEvent.event_time:type_name -> google.protobuf.Timestamp + 256, // 48: openshell.v1.PlatformEvent.metadata:type_name -> openshell.v1.PlatformEvent.MetadataEntry + 279, // 49: openshell.v1.CreateSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 37, // 50: openshell.v1.CreateSandboxRequest.spec:type_name -> openshell.v1.SandboxSpec - 256, // 51: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry - 257, // 52: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry - 249, // 53: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure - 277, // 54: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 257, // 51: openshell.v1.CreateSandboxRequest.labels:type_name -> openshell.v1.CreateSandboxRequest.LabelsEntry + 258, // 52: openshell.v1.CreateSandboxRequest.annotations:type_name -> openshell.v1.CreateSandboxRequest.AnnotationsEntry + 250, // 53: openshell.v1.CreateSandboxRequest.service_exposures:type_name -> openshell.v1.SandboxServiceExposure + 279, // 54: openshell.v1.CreateSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 41, // 55: openshell.v1.CreateSandboxTemplateRequest.template:type_name -> openshell.v1.SandboxWorkloadTemplate - 277, // 56: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 57: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 58: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 56: openshell.v1.GetSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 57: openshell.v1.ListSandboxTemplatesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 58: openshell.v1.DeleteSandboxTemplateRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 41, // 59: openshell.v1.SandboxTemplateResponse.template:type_name -> openshell.v1.SandboxWorkloadTemplate 41, // 60: openshell.v1.ListSandboxTemplatesResponse.templates:type_name -> openshell.v1.SandboxWorkloadTemplate 17, // 61: openshell.v1.DeleteSandboxTemplateResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 277, // 62: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 272, // 63: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp - 277, // 64: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 65: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 66: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 67: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 68: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 69: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 70: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 71: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 62: openshell.v1.BeginRootfsTarStagingRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 274, // 63: openshell.v1.BeginRootfsTarStagingResponse.expiration_time:type_name -> google.protobuf.Timestamp + 279, // 64: openshell.v1.GetSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 65: openshell.v1.ListSandboxesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 66: openshell.v1.ListSandboxProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 67: openshell.v1.AttachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 68: openshell.v1.DetachSandboxProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 69: openshell.v1.DeleteSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 70: openshell.v1.StopSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 71: openshell.v1.StartSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 36, // 72: openshell.v1.SandboxResponse.sandbox:type_name -> openshell.v1.Sandbox - 258, // 73: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry + 259, // 73: openshell.v1.SandboxResponse.service_urls:type_name -> openshell.v1.SandboxResponse.ServiceUrlsEntry 36, // 74: openshell.v1.ListSandboxesResponse.sandboxes:type_name -> openshell.v1.Sandbox - 278, // 75: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 280, // 75: openshell.v1.ListSandboxProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider 36, // 76: openshell.v1.AttachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox 78, // 77: openshell.v1.AttachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt 36, // 78: openshell.v1.DetachSandboxProviderResponse.sandbox:type_name -> openshell.v1.Sandbox 78, // 79: openshell.v1.DetachSandboxProviderResponse.receipt:type_name -> openshell.v1.ProviderMutationReceipt 76, // 80: openshell.v1.ConfigSnapshotRevision.sandbox_config:type_name -> openshell.v1.SandboxConfigRevision 74, // 81: openshell.v1.ConfigSnapshotRevision.provider_target:type_name -> openshell.v1.ProviderDesiredIdentity - 279, // 82: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource + 281, // 82: openshell.v1.SandboxConfigRevision.policy_source:type_name -> openshell.sandbox.v1.PolicySource 5, // 83: openshell.v1.ConfigUpdateOperation.component:type_name -> openshell.v1.ConfigComponent 75, // 84: openshell.v1.ConfigUpdateOperation.target_revision:type_name -> openshell.v1.ConfigSnapshotRevision 7, // 85: openshell.v1.ConfigUpdateOperation.state:type_name -> openshell.v1.ConfigUpdateOperationState 6, // 86: openshell.v1.ConfigUpdateOperation.outcome:type_name -> openshell.v1.ConfigApplyOutcome - 272, // 87: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp - 272, // 88: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp - 272, // 89: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp + 274, // 87: openshell.v1.ConfigUpdateOperation.created_time:type_name -> google.protobuf.Timestamp + 274, // 88: openshell.v1.ConfigUpdateOperation.updated_time:type_name -> google.protobuf.Timestamp + 274, // 89: openshell.v1.ConfigUpdateOperation.completed_time:type_name -> google.protobuf.Timestamp 2, // 90: openshell.v1.ProviderMutationReceipt.kind:type_name -> openshell.v1.ProviderMutationKind 74, // 91: openshell.v1.ProviderMutationReceipt.desired:type_name -> openshell.v1.ProviderDesiredIdentity - 272, // 92: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp + 274, // 92: openshell.v1.ProviderMutationReceipt.persisted_time:type_name -> google.protobuf.Timestamp 4, // 93: openshell.v1.ProviderReadinessObservation.reason:type_name -> openshell.v1.ProviderReadinessReason 78, // 94: openshell.v1.ProviderReadinessStatus.receipt:type_name -> openshell.v1.ProviderMutationReceipt 3, // 95: openshell.v1.ProviderReadinessStatus.state:type_name -> openshell.v1.ProviderReadinessState 4, // 96: openshell.v1.ProviderReadinessStatus.reason:type_name -> openshell.v1.ProviderReadinessReason 79, // 97: openshell.v1.ProviderReadinessStatus.observed:type_name -> openshell.v1.ProviderReadinessObservation - 272, // 98: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp - 272, // 99: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp + 274, // 98: openshell.v1.ProviderReadinessStatus.observed_time:type_name -> google.protobuf.Timestamp + 274, // 99: openshell.v1.ProviderReadinessStatus.evaluated_time:type_name -> google.protobuf.Timestamp 77, // 100: openshell.v1.ProviderReadinessStatus.operation:type_name -> openshell.v1.ConfigUpdateOperation - 277, // 101: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 101: openshell.v1.GetSandboxProviderStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 80, // 102: openshell.v1.GetSandboxProviderStatusResponse.status:type_name -> openshell.v1.ProviderReadinessStatus 79, // 103: openshell.v1.ReportProviderReadinessRequest.observation:type_name -> openshell.v1.ProviderReadinessObservation - 276, // 104: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration - 276, // 105: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration + 278, // 104: openshell.v1.ReportProviderReadinessResponse.report_interval:type_name -> google.protobuf.Duration + 278, // 105: openshell.v1.ReportProviderReadinessResponse.observation_ttl:type_name -> google.protobuf.Duration 17, // 106: openshell.v1.DeleteSandboxResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 277, // 107: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 272, // 108: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp - 277, // 109: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 110: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 111: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 107: openshell.v1.CreateSshSessionRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 274, // 108: openshell.v1.CreateSshSessionResponse.expiration_time:type_name -> google.protobuf.Timestamp + 279, // 109: openshell.v1.ExposeServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 110: openshell.v1.GetServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 111: openshell.v1.ListServicesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 95, // 112: openshell.v1.ListServicesResponse.services:type_name -> openshell.v1.ServiceEndpointResponse - 277, // 113: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 113: openshell.v1.DeleteServiceRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 17, // 114: openshell.v1.DeleteServiceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 273, // 115: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 275, // 115: openshell.v1.ServiceEndpoint.metadata:type_name -> openshell.datamodel.v1.ObjectMeta 94, // 116: openshell.v1.ServiceEndpointResponse.endpoint:type_name -> openshell.v1.ServiceEndpoint 17, // 117: openshell.v1.RevokeSshSessionResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 277, // 118: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 259, // 119: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry - 276, // 120: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration + 279, // 118: openshell.v1.ExecSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 260, // 119: openshell.v1.ExecSandboxRequest.environment:type_name -> openshell.v1.ExecSandboxRequest.EnvironmentEntry + 278, // 120: openshell.v1.ExecSandboxRequest.execution_timeout:type_name -> google.protobuf.Duration 99, // 121: openshell.v1.ExecSandboxEvent.stdout:type_name -> openshell.v1.ExecSandboxStdout 100, // 122: openshell.v1.ExecSandboxEvent.stderr:type_name -> openshell.v1.ExecSandboxStderr 101, // 123: openshell.v1.ExecSandboxEvent.exit:type_name -> openshell.v1.ExecSandboxExit - 194, // 124: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget - 195, // 125: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget + 195, // 124: openshell.v1.TcpForwardInit.ssh:type_name -> openshell.v1.SshRelayTarget + 196, // 125: openshell.v1.TcpForwardInit.tcp:type_name -> openshell.v1.TcpRelayTarget 103, // 126: openshell.v1.TcpForwardFrame.init:type_name -> openshell.v1.TcpForwardInit 98, // 127: openshell.v1.ExecSandboxInput.start:type_name -> openshell.v1.ExecSandboxRequest 106, // 128: openshell.v1.ExecSandboxInput.resize:type_name -> openshell.v1.ExecSandboxWindowResize - 273, // 129: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 272, // 130: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp - 277, // 131: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 272, // 132: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp + 275, // 129: openshell.v1.SshSession.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 274, // 130: openshell.v1.SshSession.expiration_time:type_name -> google.protobuf.Timestamp + 279, // 131: openshell.v1.WatchSandboxRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 274, // 132: openshell.v1.WatchSandboxRequest.since_time:type_name -> google.protobuf.Timestamp 36, // 133: openshell.v1.SandboxStreamEvent.sandbox:type_name -> openshell.v1.Sandbox 110, // 134: openshell.v1.SandboxStreamEvent.log:type_name -> openshell.v1.SandboxLogLine 50, // 135: openshell.v1.SandboxStreamEvent.event:type_name -> openshell.v1.PlatformEvent 111, // 136: openshell.v1.SandboxStreamEvent.warning:type_name -> openshell.v1.SandboxStreamWarning - 207, // 137: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate - 272, // 138: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp - 260, // 139: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry - 277, // 140: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 278, // 141: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 277, // 142: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 143: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 144: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 278, // 145: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider - 261, // 146: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry - 277, // 147: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 278, // 148: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider + 208, // 137: openshell.v1.SandboxStreamEvent.draft_policy_update:type_name -> openshell.v1.DraftPolicyUpdate + 274, // 138: openshell.v1.SandboxLogLine.event_time:type_name -> google.protobuf.Timestamp + 261, // 139: openshell.v1.SandboxLogLine.fields:type_name -> openshell.v1.SandboxLogLine.FieldsEntry + 279, // 140: openshell.v1.CreateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 141: openshell.v1.CreateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 279, // 142: openshell.v1.GetProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 143: openshell.v1.ListProvidersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 144: openshell.v1.UpdateProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 145: openshell.v1.UpdateProviderRequest.provider:type_name -> openshell.datamodel.v1.Provider + 262, // 146: openshell.v1.UpdateProviderRequest.credential_expiration_times:type_name -> openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry + 279, // 147: openshell.v1.DeleteProviderRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 148: openshell.v1.ProviderResponse.provider:type_name -> openshell.datamodel.v1.Provider 78, // 149: openshell.v1.ProviderResponse.target_receipts:type_name -> openshell.v1.ProviderMutationReceipt - 278, // 150: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider - 277, // 151: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 152: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 280, // 150: openshell.v1.ListProvidersResponse.providers:type_name -> openshell.datamodel.v1.Provider + 279, // 151: openshell.v1.ListProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 152: openshell.v1.GetProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 140, // 153: openshell.v1.ProviderProfileImportItem.profile:type_name -> openshell.v1.ProviderProfile - 276, // 154: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration + 278, // 154: openshell.v1.ProviderCredentialTokenGrant.cache_ttl:type_name -> google.protobuf.Duration 123, // 155: openshell.v1.ProviderCredentialTokenGrant.audience_overrides:type_name -> openshell.v1.ProviderCredentialTokenGrantAudienceOverride 8, // 156: openshell.v1.ProviderCredentialTokenGrant.grant_type:type_name -> openshell.v1.ProviderCredentialTokenGrantType 124, // 157: openshell.v1.ProviderCredentialTokenGrant.subject_token:type_name -> openshell.v1.ProviderCredentialTokenGrantSubjectToken 129, // 158: openshell.v1.ProviderProfileCredential.refresh:type_name -> openshell.v1.ProviderCredentialRefresh 125, // 159: openshell.v1.ProviderProfileCredential.token_grant:type_name -> openshell.v1.ProviderCredentialTokenGrant 9, // 160: openshell.v1.ProviderCredentialRefresh.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 276, // 161: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration - 276, // 162: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration + 278, // 161: openshell.v1.ProviderCredentialRefresh.refresh_before:type_name -> google.protobuf.Duration + 278, // 162: openshell.v1.ProviderCredentialRefresh.max_lifetime:type_name -> google.protobuf.Duration 127, // 163: openshell.v1.ProviderCredentialRefresh.material:type_name -> openshell.v1.ProviderCredentialRefreshMaterial 128, // 164: openshell.v1.ProviderCredentialRefresh.additional_outputs:type_name -> openshell.v1.ProviderCredentialRefreshOutput 9, // 165: openshell.v1.ProviderCredentialRefreshStatus.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 272, // 166: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp - 272, // 167: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp - 272, // 168: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp + 274, // 166: openshell.v1.ProviderCredentialRefreshStatus.expiration_time:type_name -> google.protobuf.Timestamp + 274, // 167: openshell.v1.ProviderCredentialRefreshStatus.next_refresh_time:type_name -> google.protobuf.Timestamp + 274, // 168: openshell.v1.ProviderCredentialRefreshStatus.last_refresh_time:type_name -> google.protobuf.Timestamp 15, // 169: openshell.v1.ProviderCredentialRefreshStatus.recovery_action:type_name -> openshell.v1.ProviderCredentialRefreshRecoveryAction - 272, // 170: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp - 277, // 171: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 274, // 170: openshell.v1.ProviderCredentialRefreshStatus.last_error_time:type_name -> google.protobuf.Timestamp + 279, // 171: openshell.v1.GetProviderRefreshStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 130, // 172: openshell.v1.GetProviderRefreshStatusResponse.credentials:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 277, // 173: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 173: openshell.v1.ConfigureProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 9, // 174: openshell.v1.ConfigureProviderRefreshRequest.strategy:type_name -> openshell.v1.ProviderCredentialRefreshStrategy - 262, // 175: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry - 272, // 176: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp + 263, // 175: openshell.v1.ConfigureProviderRefreshRequest.material:type_name -> openshell.v1.ConfigureProviderRefreshRequest.MaterialEntry + 274, // 176: openshell.v1.ConfigureProviderRefreshRequest.expiration_time:type_name -> google.protobuf.Timestamp 130, // 177: openshell.v1.ConfigureProviderRefreshResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 277, // 178: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 178: openshell.v1.RotateProviderCredentialRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 130, // 179: openshell.v1.RotateProviderCredentialResponse.status:type_name -> openshell.v1.ProviderCredentialRefreshStatus - 277, // 180: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 180: openshell.v1.DeleteProviderRefreshRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector 17, // 181: openshell.v1.DeleteProviderRefreshResponse.outcome:type_name -> openshell.v1.DeletionOutcome 10, // 182: openshell.v1.ProviderProfile.category:type_name -> openshell.v1.ProviderProfileCategory 126, // 183: openshell.v1.ProviderProfile.credentials:type_name -> openshell.v1.ProviderProfileCredential - 280, // 184: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint - 281, // 185: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 282, // 184: openshell.v1.ProviderProfile.endpoints:type_name -> openshell.sandbox.v1.NetworkEndpoint + 283, // 185: openshell.v1.ProviderProfile.binaries:type_name -> openshell.sandbox.v1.NetworkBinary 131, // 186: openshell.v1.ProviderProfile.discovery:type_name -> openshell.v1.ProviderProfileDiscovery - 263, // 187: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry - 140, // 188: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile - 140, // 189: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 277, // 190: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 121, // 191: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 122, // 192: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 140, // 193: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile - 277, // 194: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 121, // 195: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem - 122, // 196: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 140, // 197: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile - 277, // 198: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 121, // 199: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem - 122, // 200: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic - 17, // 201: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 277, // 202: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 17, // 203: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 153, // 204: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding - 264, // 205: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry - 265, // 206: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry - 266, // 207: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry - 267, // 208: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry - 4, // 209: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason - 276, // 210: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration - 277, // 211: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 274, // 212: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 282, // 213: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue - 159, // 214: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation - 268, // 215: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry - 160, // 216: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule - 161, // 217: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint - 162, // 218: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule - 164, // 219: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules - 165, // 220: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules - 166, // 221: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary - 283, // 222: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 281, // 223: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary - 284, // 224: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule - 163, // 225: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget - 285, // 226: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule - 163, // 227: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget - 269, // 228: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry - 277, // 229: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 177, // 230: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision - 277, // 231: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 177, // 232: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision - 12, // 233: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus - 11, // 234: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState - 174, // 235: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission - 12, // 236: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus - 272, // 237: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp - 272, // 238: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp - 274, // 239: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 270, // 240: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry - 277, // 241: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 272, // 242: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp - 110, // 243: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine - 110, // 244: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine - 184, // 245: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello - 187, // 246: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat - 200, // 247: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult - 201, // 248: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose - 185, // 249: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted - 186, // 250: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected - 188, // 251: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat - 193, // 252: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen - 201, // 253: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose - 276, // 254: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration - 194, // 255: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget - 195, // 256: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget - 196, // 257: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit - 193, // 258: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen - 198, // 259: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit - 272, // 260: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp - 272, // 261: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp - 202, // 262: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample - 204, // 263: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount - 283, // 264: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 272, // 265: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp - 272, // 266: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp - 272, // 267: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp - 272, // 268: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp - 274, // 269: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 274, // 270: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy - 277, // 271: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 203, // 272: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary - 206, // 273: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk - 205, // 274: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary - 277, // 275: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 206, // 276: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk - 272, // 277: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp - 277, // 278: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 279: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 280: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 216, // 281: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval - 277, // 282: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 283, // 283: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule - 277, // 284: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 285: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 277, // 286: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 272, // 287: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp - 226, // 288: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry - 271, // 289: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry - 286, // 290: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 286, // 291: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace - 286, // 292: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace - 17, // 293: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 273, // 294: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta - 14, // 295: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole - 277, // 296: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 14, // 297: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole - 236, // 298: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember - 277, // 299: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 17, // 300: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome - 277, // 301: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector - 236, // 302: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember - 272, // 303: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp - 18, // 304: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult - 244, // 305: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation - 18, // 306: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult - 272, // 307: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp - 272, // 308: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp - 272, // 309: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp - 272, // 310: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp - 272, // 311: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp - 272, // 312: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp - 272, // 313: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp - 272, // 314: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp - 272, // 315: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 272, // 316: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp - 126, // 317: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential - 154, // 318: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding - 23, // 319: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest - 25, // 320: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest - 27, // 321: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest - 51, // 322: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest - 59, // 323: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest - 61, // 324: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest - 62, // 325: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest - 52, // 326: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest - 53, // 327: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest - 54, // 328: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest - 55, // 329: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest - 63, // 330: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest - 64, // 331: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest - 65, // 332: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest - 81, // 333: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 66, // 334: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest - 67, // 335: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest - 68, // 336: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest - 86, // 337: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest - 88, // 338: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest - 89, // 339: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest - 90, // 340: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest - 92, // 341: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest - 96, // 342: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest - 98, // 343: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest - 104, // 344: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame - 105, // 345: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput - 112, // 346: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest - 113, // 347: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest - 114, // 348: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest - 119, // 349: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest - 120, // 350: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest - 143, // 351: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest - 145, // 352: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest - 147, // 353: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest - 115, // 354: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest - 132, // 355: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest - 134, // 356: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest - 136, // 357: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest - 138, // 358: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest - 116, // 359: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest - 150, // 360: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest - 287, // 361: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest - 288, // 362: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest - 158, // 363: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest - 168, // 364: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest - 170, // 365: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest - 172, // 366: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest - 245, // 367: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 83, // 368: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 175, // 369: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest - 152, // 370: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest - 156, // 371: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest - 178, // 372: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest - 179, // 373: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest - 182, // 374: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage - 189, // 375: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest - 191, // 376: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest - 197, // 377: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame - 199, // 378: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame - 83, // 379: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest - 245, // 380: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest - 81, // 381: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest - 108, // 382: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest - 208, // 383: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest - 210, // 384: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest - 212, // 385: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest - 214, // 386: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest - 217, // 387: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest - 219, // 388: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest - 221, // 389: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest - 223, // 390: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest - 225, // 391: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest - 19, // 392: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest - 21, // 393: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest - 228, // 394: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest - 230, // 395: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest - 232, // 396: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest - 234, // 397: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest - 237, // 398: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest - 239, // 399: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest - 241, // 400: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest - 24, // 401: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse - 26, // 402: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse - 28, // 403: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse - 69, // 404: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse - 60, // 405: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse - 69, // 406: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse - 70, // 407: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse - 56, // 408: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 56, // 409: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse - 57, // 410: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse - 58, // 411: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse - 71, // 412: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse - 72, // 413: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse - 73, // 414: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse - 82, // 415: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 85, // 416: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse - 69, // 417: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse - 69, // 418: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse - 87, // 419: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse - 95, // 420: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse - 95, // 421: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse - 91, // 422: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse - 93, // 423: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse - 97, // 424: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse - 102, // 425: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent - 104, // 426: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame - 102, // 427: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent - 117, // 428: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse - 117, // 429: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse - 118, // 430: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse - 142, // 431: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse - 141, // 432: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse - 144, // 433: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse - 146, // 434: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse - 148, // 435: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse - 117, // 436: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse - 133, // 437: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse - 135, // 438: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse - 137, // 439: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse - 139, // 440: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse - 149, // 441: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse - 151, // 442: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse - 289, // 443: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse - 290, // 444: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse - 167, // 445: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse - 169, // 446: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse - 171, // 447: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse - 173, // 448: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse - 246, // 449: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 84, // 450: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 176, // 451: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse - 155, // 452: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse - 157, // 453: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse - 181, // 454: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse - 180, // 455: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse - 183, // 456: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage - 190, // 457: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse - 192, // 458: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse - 197, // 459: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame - 199, // 460: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame - 84, // 461: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse - 246, // 462: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse - 82, // 463: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse - 109, // 464: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent - 209, // 465: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse - 211, // 466: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse - 213, // 467: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse - 215, // 468: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse - 218, // 469: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse - 220, // 470: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse - 222, // 471: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse - 224, // 472: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse - 227, // 473: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse - 20, // 474: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse - 22, // 475: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse - 229, // 476: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse - 231, // 477: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse - 233, // 478: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse - 235, // 479: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse - 238, // 480: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse - 240, // 481: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse - 242, // 482: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse - 401, // [401:483] is the sub-list for method output_type - 319, // [319:401] is the sub-list for method input_type - 319, // [319:319] is the sub-list for extension type_name - 319, // [319:319] is the sub-list for extension extendee - 0, // [0:319] is the sub-list for field type_name + 264, // 187: openshell.v1.ProviderProfile.annotations:type_name -> openshell.v1.ProviderProfile.AnnotationsEntry + 141, // 188: openshell.v1.ProviderProfile.files:type_name -> openshell.v1.ProviderProfileFile + 140, // 189: openshell.v1.ProviderProfileResponse.profile:type_name -> openshell.v1.ProviderProfile + 140, // 190: openshell.v1.ListProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 279, // 191: openshell.v1.ImportProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 121, // 192: openshell.v1.ImportProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 122, // 193: openshell.v1.ImportProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 140, // 194: openshell.v1.ImportProviderProfilesResponse.profiles:type_name -> openshell.v1.ProviderProfile + 279, // 195: openshell.v1.UpdateProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 121, // 196: openshell.v1.UpdateProviderProfilesRequest.profile:type_name -> openshell.v1.ProviderProfileImportItem + 122, // 197: openshell.v1.UpdateProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 140, // 198: openshell.v1.UpdateProviderProfilesResponse.profile:type_name -> openshell.v1.ProviderProfile + 279, // 199: openshell.v1.LintProviderProfilesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 121, // 200: openshell.v1.LintProviderProfilesRequest.profiles:type_name -> openshell.v1.ProviderProfileImportItem + 122, // 201: openshell.v1.LintProviderProfilesResponse.diagnostics:type_name -> openshell.v1.ProviderProfileDiagnostic + 17, // 202: openshell.v1.DeleteProviderResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 279, // 203: openshell.v1.DeleteProviderProfileRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 17, // 204: openshell.v1.DeleteProviderProfileResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 154, // 205: openshell.v1.StaticCredentialBinding.endpoints:type_name -> openshell.v1.StaticCredentialEndpointBinding + 265, // 206: openshell.v1.GetSandboxProviderEnvironmentResponse.environment:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.EnvironmentEntry + 266, // 207: openshell.v1.GetSandboxProviderEnvironmentResponse.credential_expiration_times:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry + 267, // 208: openshell.v1.GetSandboxProviderEnvironmentResponse.dynamic_credentials:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry + 268, // 209: openshell.v1.GetSandboxProviderEnvironmentResponse.static_credential_bindings:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry + 4, // 210: openshell.v1.GetSandboxProviderEnvironmentResponse.readiness_reason:type_name -> openshell.v1.ProviderReadinessReason + 269, // 211: openshell.v1.GetSandboxProviderEnvironmentResponse.files:type_name -> openshell.v1.GetSandboxProviderEnvironmentResponse.FilesEntry + 278, // 212: openshell.v1.ExchangeProviderSubjectTokenResponse.expires_after:type_name -> google.protobuf.Duration + 279, // 213: openshell.v1.UpdateConfigRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 276, // 214: openshell.v1.UpdateConfigRequest.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 284, // 215: openshell.v1.UpdateConfigRequest.setting_value:type_name -> openshell.sandbox.v1.SettingValue + 160, // 216: openshell.v1.UpdateConfigRequest.merge_operations:type_name -> openshell.v1.PolicyMergeOperation + 270, // 217: openshell.v1.UpdateConfigRequest.annotations:type_name -> openshell.v1.UpdateConfigRequest.AnnotationsEntry + 161, // 218: openshell.v1.PolicyMergeOperation.add_rule:type_name -> openshell.v1.AddNetworkRule + 162, // 219: openshell.v1.PolicyMergeOperation.remove_endpoint:type_name -> openshell.v1.RemoveNetworkEndpoint + 163, // 220: openshell.v1.PolicyMergeOperation.remove_rule:type_name -> openshell.v1.RemoveNetworkRule + 165, // 221: openshell.v1.PolicyMergeOperation.add_deny_rules:type_name -> openshell.v1.AddDenyRules + 166, // 222: openshell.v1.PolicyMergeOperation.add_allow_rules:type_name -> openshell.v1.AddAllowRules + 167, // 223: openshell.v1.PolicyMergeOperation.remove_binary:type_name -> openshell.v1.RemoveNetworkBinary + 285, // 224: openshell.v1.AddNetworkRule.rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 283, // 225: openshell.v1.L7RuleTarget.binaries:type_name -> openshell.sandbox.v1.NetworkBinary + 286, // 226: openshell.v1.AddDenyRules.deny_rules:type_name -> openshell.sandbox.v1.L7DenyRule + 164, // 227: openshell.v1.AddDenyRules.target:type_name -> openshell.v1.L7RuleTarget + 287, // 228: openshell.v1.AddAllowRules.rules:type_name -> openshell.sandbox.v1.L7Rule + 164, // 229: openshell.v1.AddAllowRules.target:type_name -> openshell.v1.L7RuleTarget + 271, // 230: openshell.v1.UpdateConfigResponse.annotations:type_name -> openshell.v1.UpdateConfigResponse.AnnotationsEntry + 279, // 231: openshell.v1.GetSandboxPolicyStatusRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 178, // 232: openshell.v1.GetSandboxPolicyStatusResponse.revision:type_name -> openshell.v1.SandboxPolicyRevision + 279, // 233: openshell.v1.ListSandboxPoliciesRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 178, // 234: openshell.v1.ListSandboxPoliciesResponse.revisions:type_name -> openshell.v1.SandboxPolicyRevision + 12, // 235: openshell.v1.ReportPolicyStatusRequest.status:type_name -> openshell.v1.PolicyStatus + 11, // 236: openshell.v1.SandboxConfigurationAdmission.state:type_name -> openshell.v1.ConfigurationAdmissionState + 175, // 237: openshell.v1.ReportSandboxConfigurationRequest.admission:type_name -> openshell.v1.SandboxConfigurationAdmission + 12, // 238: openshell.v1.SandboxPolicyRevision.status:type_name -> openshell.v1.PolicyStatus + 274, // 239: openshell.v1.SandboxPolicyRevision.created_time:type_name -> google.protobuf.Timestamp + 274, // 240: openshell.v1.SandboxPolicyRevision.loaded_time:type_name -> google.protobuf.Timestamp + 276, // 241: openshell.v1.SandboxPolicyRevision.policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 272, // 242: openshell.v1.SandboxPolicyRevision.provenance:type_name -> openshell.v1.SandboxPolicyRevision.ProvenanceEntry + 279, // 243: openshell.v1.GetSandboxLogsRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 274, // 244: openshell.v1.GetSandboxLogsRequest.since_time:type_name -> google.protobuf.Timestamp + 110, // 245: openshell.v1.PushSandboxLogsRequest.logs:type_name -> openshell.v1.SandboxLogLine + 110, // 246: openshell.v1.GetSandboxLogsResponse.logs:type_name -> openshell.v1.SandboxLogLine + 185, // 247: openshell.v1.SupervisorMessage.hello:type_name -> openshell.v1.SupervisorHello + 188, // 248: openshell.v1.SupervisorMessage.heartbeat:type_name -> openshell.v1.SupervisorHeartbeat + 201, // 249: openshell.v1.SupervisorMessage.relay_open_result:type_name -> openshell.v1.RelayOpenResult + 202, // 250: openshell.v1.SupervisorMessage.relay_close:type_name -> openshell.v1.RelayClose + 186, // 251: openshell.v1.GatewayMessage.session_accepted:type_name -> openshell.v1.SessionAccepted + 187, // 252: openshell.v1.GatewayMessage.session_rejected:type_name -> openshell.v1.SessionRejected + 189, // 253: openshell.v1.GatewayMessage.heartbeat:type_name -> openshell.v1.GatewayHeartbeat + 194, // 254: openshell.v1.GatewayMessage.relay_open:type_name -> openshell.v1.RelayOpen + 202, // 255: openshell.v1.GatewayMessage.relay_close:type_name -> openshell.v1.RelayClose + 278, // 256: openshell.v1.SessionAccepted.heartbeat_interval:type_name -> google.protobuf.Duration + 195, // 257: openshell.v1.RelayOpen.ssh:type_name -> openshell.v1.SshRelayTarget + 196, // 258: openshell.v1.RelayOpen.tcp:type_name -> openshell.v1.TcpRelayTarget + 197, // 259: openshell.v1.RelayFrame.init:type_name -> openshell.v1.RelayInit + 194, // 260: openshell.v1.PeerRelayInit.relay_open:type_name -> openshell.v1.RelayOpen + 199, // 261: openshell.v1.PeerRelayFrame.init:type_name -> openshell.v1.PeerRelayInit + 274, // 262: openshell.v1.DenialSummary.first_seen_time:type_name -> google.protobuf.Timestamp + 274, // 263: openshell.v1.DenialSummary.last_seen_time:type_name -> google.protobuf.Timestamp + 203, // 264: openshell.v1.DenialSummary.l7_request_samples:type_name -> openshell.v1.L7RequestSample + 205, // 265: openshell.v1.NetworkActivitySummary.denials_by_group:type_name -> openshell.v1.DenialGroupCount + 285, // 266: openshell.v1.PolicyChunk.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 274, // 267: openshell.v1.PolicyChunk.created_time:type_name -> google.protobuf.Timestamp + 274, // 268: openshell.v1.PolicyChunk.decided_time:type_name -> google.protobuf.Timestamp + 274, // 269: openshell.v1.PolicyChunk.first_seen_time:type_name -> google.protobuf.Timestamp + 274, // 270: openshell.v1.PolicyChunk.last_seen_time:type_name -> google.protobuf.Timestamp + 276, // 271: openshell.v1.PolicyChunk.current_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 276, // 272: openshell.v1.PolicyChunk.candidate_effective_policy:type_name -> openshell.sandbox.v1.SandboxPolicy + 279, // 273: openshell.v1.SubmitPolicyAnalysisRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 204, // 274: openshell.v1.SubmitPolicyAnalysisRequest.summaries:type_name -> openshell.v1.DenialSummary + 207, // 275: openshell.v1.SubmitPolicyAnalysisRequest.proposed_chunks:type_name -> openshell.v1.PolicyChunk + 206, // 276: openshell.v1.SubmitPolicyAnalysisRequest.network_activity_summaries:type_name -> openshell.v1.NetworkActivitySummary + 279, // 277: openshell.v1.GetDraftPolicyRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 207, // 278: openshell.v1.GetDraftPolicyResponse.chunks:type_name -> openshell.v1.PolicyChunk + 274, // 279: openshell.v1.GetDraftPolicyResponse.last_analyzed_time:type_name -> google.protobuf.Timestamp + 279, // 280: openshell.v1.ApproveDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 281: openshell.v1.RejectDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 282: openshell.v1.ApproveAllDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 217, // 283: openshell.v1.ApproveAllDraftChunksRequest.approvals:type_name -> openshell.v1.DraftChunkApproval + 279, // 284: openshell.v1.EditDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 285, // 285: openshell.v1.EditDraftChunkRequest.proposed_rule:type_name -> openshell.sandbox.v1.NetworkPolicyRule + 279, // 286: openshell.v1.UndoDraftChunkRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 287: openshell.v1.ClearDraftChunksRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 279, // 288: openshell.v1.GetDraftHistoryRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 274, // 289: openshell.v1.DraftHistoryEntry.event_time:type_name -> google.protobuf.Timestamp + 227, // 290: openshell.v1.GetDraftHistoryResponse.entries:type_name -> openshell.v1.DraftHistoryEntry + 273, // 291: openshell.v1.CreateWorkspaceRequest.labels:type_name -> openshell.v1.CreateWorkspaceRequest.LabelsEntry + 288, // 292: openshell.v1.CreateWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 288, // 293: openshell.v1.GetWorkspaceResponse.workspace:type_name -> openshell.datamodel.v1.Workspace + 288, // 294: openshell.v1.ListWorkspacesResponse.workspaces:type_name -> openshell.datamodel.v1.Workspace + 17, // 295: openshell.v1.DeleteWorkspaceResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 275, // 296: openshell.v1.WorkspaceMember.metadata:type_name -> openshell.datamodel.v1.ObjectMeta + 14, // 297: openshell.v1.WorkspaceMember.role:type_name -> openshell.v1.WorkspaceRole + 279, // 298: openshell.v1.AddWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 14, // 299: openshell.v1.AddWorkspaceMemberRequest.role:type_name -> openshell.v1.WorkspaceRole + 237, // 300: openshell.v1.AddWorkspaceMemberResponse.member:type_name -> openshell.v1.WorkspaceMember + 279, // 301: openshell.v1.RemoveWorkspaceMemberRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 17, // 302: openshell.v1.RemoveWorkspaceMemberResponse.outcome:type_name -> openshell.v1.DeletionOutcome + 279, // 303: openshell.v1.ListWorkspaceMembersRequest.workspace_scope:type_name -> openshell.datamodel.v1.WorkspaceSelector + 237, // 304: openshell.v1.ListWorkspaceMembersResponse.members:type_name -> openshell.v1.WorkspaceMember + 274, // 305: openshell.v1.ExtensionServiceCredential.expiration_time:type_name -> google.protobuf.Timestamp + 18, // 306: openshell.v1.EndpointObservation.result:type_name -> openshell.v1.EndpointResult + 245, // 307: openshell.v1.ReportEndpointStatusRequest.observations:type_name -> openshell.v1.EndpointObservation + 18, // 308: openshell.v1.EndpointStatus.last_result:type_name -> openshell.v1.EndpointResult + 274, // 309: openshell.v1.EndpointStatus.last_reported_time:type_name -> google.protobuf.Timestamp + 274, // 310: openshell.v1.SandboxProvisioning.configuration_change_time:type_name -> google.protobuf.Timestamp + 274, // 311: openshell.v1.SandboxProvisioning.first_rejection_time:type_name -> google.protobuf.Timestamp + 274, // 312: openshell.v1.SandboxProvisioning.deadline:type_name -> google.protobuf.Timestamp + 274, // 313: openshell.v1.SandboxProvisioning.timeout_time:type_name -> google.protobuf.Timestamp + 274, // 314: openshell.v1.SandboxProvisioning.cleanup_completed_time:type_name -> google.protobuf.Timestamp + 274, // 315: openshell.v1.SandboxProvisioning.cleanup_retry_time:type_name -> google.protobuf.Timestamp + 274, // 316: openshell.v1.SandboxProvisioning.attachment_change_time:type_name -> google.protobuf.Timestamp + 274, // 317: openshell.v1.UpdateProviderRequest.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 274, // 318: openshell.v1.GetSandboxProviderEnvironmentResponse.CredentialExpirationTimesEntry.value:type_name -> google.protobuf.Timestamp + 126, // 319: openshell.v1.GetSandboxProviderEnvironmentResponse.DynamicCredentialsEntry.value:type_name -> openshell.v1.ProviderProfileCredential + 155, // 320: openshell.v1.GetSandboxProviderEnvironmentResponse.StaticCredentialBindingsEntry.value:type_name -> openshell.v1.StaticCredentialBinding + 23, // 321: openshell.v1.OpenShell.Health:input_type -> openshell.v1.HealthRequest + 25, // 322: openshell.v1.OpenShell.GetCurrentUser:input_type -> openshell.v1.GetCurrentUserRequest + 27, // 323: openshell.v1.OpenShell.GetGatewayInfo:input_type -> openshell.v1.GetGatewayInfoRequest + 51, // 324: openshell.v1.OpenShell.CreateSandbox:input_type -> openshell.v1.CreateSandboxRequest + 59, // 325: openshell.v1.OpenShell.BeginRootfsTarStaging:input_type -> openshell.v1.BeginRootfsTarStagingRequest + 61, // 326: openshell.v1.OpenShell.GetSandbox:input_type -> openshell.v1.GetSandboxRequest + 62, // 327: openshell.v1.OpenShell.ListSandboxes:input_type -> openshell.v1.ListSandboxesRequest + 52, // 328: openshell.v1.OpenShell.CreateSandboxTemplate:input_type -> openshell.v1.CreateSandboxTemplateRequest + 53, // 329: openshell.v1.OpenShell.GetSandboxTemplate:input_type -> openshell.v1.GetSandboxTemplateRequest + 54, // 330: openshell.v1.OpenShell.ListSandboxTemplates:input_type -> openshell.v1.ListSandboxTemplatesRequest + 55, // 331: openshell.v1.OpenShell.DeleteSandboxTemplate:input_type -> openshell.v1.DeleteSandboxTemplateRequest + 63, // 332: openshell.v1.OpenShell.ListSandboxProviders:input_type -> openshell.v1.ListSandboxProvidersRequest + 64, // 333: openshell.v1.OpenShell.AttachSandboxProvider:input_type -> openshell.v1.AttachSandboxProviderRequest + 65, // 334: openshell.v1.OpenShell.DetachSandboxProvider:input_type -> openshell.v1.DetachSandboxProviderRequest + 81, // 335: openshell.v1.OpenShell.GetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 66, // 336: openshell.v1.OpenShell.DeleteSandbox:input_type -> openshell.v1.DeleteSandboxRequest + 67, // 337: openshell.v1.OpenShell.StopSandbox:input_type -> openshell.v1.StopSandboxRequest + 68, // 338: openshell.v1.OpenShell.StartSandbox:input_type -> openshell.v1.StartSandboxRequest + 86, // 339: openshell.v1.OpenShell.CreateSshSession:input_type -> openshell.v1.CreateSshSessionRequest + 88, // 340: openshell.v1.OpenShell.ExposeService:input_type -> openshell.v1.ExposeServiceRequest + 89, // 341: openshell.v1.OpenShell.GetService:input_type -> openshell.v1.GetServiceRequest + 90, // 342: openshell.v1.OpenShell.ListServices:input_type -> openshell.v1.ListServicesRequest + 92, // 343: openshell.v1.OpenShell.DeleteService:input_type -> openshell.v1.DeleteServiceRequest + 96, // 344: openshell.v1.OpenShell.RevokeSshSession:input_type -> openshell.v1.RevokeSshSessionRequest + 98, // 345: openshell.v1.OpenShell.ExecSandbox:input_type -> openshell.v1.ExecSandboxRequest + 104, // 346: openshell.v1.OpenShell.ForwardTcp:input_type -> openshell.v1.TcpForwardFrame + 105, // 347: openshell.v1.OpenShell.ExecSandboxInteractive:input_type -> openshell.v1.ExecSandboxInput + 112, // 348: openshell.v1.OpenShell.CreateProvider:input_type -> openshell.v1.CreateProviderRequest + 113, // 349: openshell.v1.OpenShell.GetProvider:input_type -> openshell.v1.GetProviderRequest + 114, // 350: openshell.v1.OpenShell.ListProviders:input_type -> openshell.v1.ListProvidersRequest + 119, // 351: openshell.v1.OpenShell.ListProviderProfiles:input_type -> openshell.v1.ListProviderProfilesRequest + 120, // 352: openshell.v1.OpenShell.GetProviderProfile:input_type -> openshell.v1.GetProviderProfileRequest + 144, // 353: openshell.v1.OpenShell.ImportProviderProfiles:input_type -> openshell.v1.ImportProviderProfilesRequest + 146, // 354: openshell.v1.OpenShell.UpdateProviderProfiles:input_type -> openshell.v1.UpdateProviderProfilesRequest + 148, // 355: openshell.v1.OpenShell.LintProviderProfiles:input_type -> openshell.v1.LintProviderProfilesRequest + 115, // 356: openshell.v1.OpenShell.UpdateProvider:input_type -> openshell.v1.UpdateProviderRequest + 132, // 357: openshell.v1.OpenShell.GetProviderRefreshStatus:input_type -> openshell.v1.GetProviderRefreshStatusRequest + 134, // 358: openshell.v1.OpenShell.ConfigureProviderRefresh:input_type -> openshell.v1.ConfigureProviderRefreshRequest + 136, // 359: openshell.v1.OpenShell.RotateProviderCredential:input_type -> openshell.v1.RotateProviderCredentialRequest + 138, // 360: openshell.v1.OpenShell.DeleteProviderRefresh:input_type -> openshell.v1.DeleteProviderRefreshRequest + 116, // 361: openshell.v1.OpenShell.DeleteProvider:input_type -> openshell.v1.DeleteProviderRequest + 151, // 362: openshell.v1.OpenShell.DeleteProviderProfile:input_type -> openshell.v1.DeleteProviderProfileRequest + 289, // 363: openshell.v1.OpenShell.GetSandboxConfig:input_type -> openshell.sandbox.v1.GetSandboxConfigRequest + 290, // 364: openshell.v1.OpenShell.GetGatewayConfig:input_type -> openshell.sandbox.v1.GetGatewayConfigRequest + 159, // 365: openshell.v1.OpenShell.UpdateConfig:input_type -> openshell.v1.UpdateConfigRequest + 169, // 366: openshell.v1.OpenShell.GetSandboxPolicyStatus:input_type -> openshell.v1.GetSandboxPolicyStatusRequest + 171, // 367: openshell.v1.OpenShell.ListSandboxPolicies:input_type -> openshell.v1.ListSandboxPoliciesRequest + 173, // 368: openshell.v1.OpenShell.ReportPolicyStatus:input_type -> openshell.v1.ReportPolicyStatusRequest + 246, // 369: openshell.v1.OpenShell.ReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 83, // 370: openshell.v1.OpenShell.ReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 176, // 371: openshell.v1.OpenShell.ReportSandboxConfiguration:input_type -> openshell.v1.ReportSandboxConfigurationRequest + 153, // 372: openshell.v1.OpenShell.GetSandboxProviderEnvironment:input_type -> openshell.v1.GetSandboxProviderEnvironmentRequest + 157, // 373: openshell.v1.OpenShell.ExchangeProviderSubjectToken:input_type -> openshell.v1.ExchangeProviderSubjectTokenRequest + 179, // 374: openshell.v1.OpenShell.GetSandboxLogs:input_type -> openshell.v1.GetSandboxLogsRequest + 180, // 375: openshell.v1.OpenShell.PushSandboxLogs:input_type -> openshell.v1.PushSandboxLogsRequest + 183, // 376: openshell.v1.OpenShell.ConnectSupervisor:input_type -> openshell.v1.SupervisorMessage + 190, // 377: openshell.v1.OpenShell.ReportMainProcessExit:input_type -> openshell.v1.ReportMainProcessExitRequest + 192, // 378: openshell.v1.OpenShell.FinalizeMainProcessExit:input_type -> openshell.v1.FinalizeMainProcessExitRequest + 198, // 379: openshell.v1.OpenShell.RelayStream:input_type -> openshell.v1.RelayFrame + 200, // 380: openshell.v1.OpenShell.PeerRelay:input_type -> openshell.v1.PeerRelayFrame + 83, // 381: openshell.v1.OpenShell.PeerReportProviderReadiness:input_type -> openshell.v1.ReportProviderReadinessRequest + 246, // 382: openshell.v1.OpenShell.PeerReportEndpointStatus:input_type -> openshell.v1.ReportEndpointStatusRequest + 81, // 383: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:input_type -> openshell.v1.GetSandboxProviderStatusRequest + 108, // 384: openshell.v1.OpenShell.WatchSandbox:input_type -> openshell.v1.WatchSandboxRequest + 209, // 385: openshell.v1.OpenShell.SubmitPolicyAnalysis:input_type -> openshell.v1.SubmitPolicyAnalysisRequest + 211, // 386: openshell.v1.OpenShell.GetDraftPolicy:input_type -> openshell.v1.GetDraftPolicyRequest + 213, // 387: openshell.v1.OpenShell.ApproveDraftChunk:input_type -> openshell.v1.ApproveDraftChunkRequest + 215, // 388: openshell.v1.OpenShell.RejectDraftChunk:input_type -> openshell.v1.RejectDraftChunkRequest + 218, // 389: openshell.v1.OpenShell.ApproveAllDraftChunks:input_type -> openshell.v1.ApproveAllDraftChunksRequest + 220, // 390: openshell.v1.OpenShell.EditDraftChunk:input_type -> openshell.v1.EditDraftChunkRequest + 222, // 391: openshell.v1.OpenShell.UndoDraftChunk:input_type -> openshell.v1.UndoDraftChunkRequest + 224, // 392: openshell.v1.OpenShell.ClearDraftChunks:input_type -> openshell.v1.ClearDraftChunksRequest + 226, // 393: openshell.v1.OpenShell.GetDraftHistory:input_type -> openshell.v1.GetDraftHistoryRequest + 19, // 394: openshell.v1.OpenShell.IssueSandboxToken:input_type -> openshell.v1.IssueSandboxTokenRequest + 21, // 395: openshell.v1.OpenShell.RefreshSandboxToken:input_type -> openshell.v1.RefreshSandboxTokenRequest + 229, // 396: openshell.v1.OpenShell.CreateWorkspace:input_type -> openshell.v1.CreateWorkspaceRequest + 231, // 397: openshell.v1.OpenShell.GetWorkspace:input_type -> openshell.v1.GetWorkspaceRequest + 233, // 398: openshell.v1.OpenShell.ListWorkspaces:input_type -> openshell.v1.ListWorkspacesRequest + 235, // 399: openshell.v1.OpenShell.DeleteWorkspace:input_type -> openshell.v1.DeleteWorkspaceRequest + 238, // 400: openshell.v1.OpenShell.AddWorkspaceMember:input_type -> openshell.v1.AddWorkspaceMemberRequest + 240, // 401: openshell.v1.OpenShell.RemoveWorkspaceMember:input_type -> openshell.v1.RemoveWorkspaceMemberRequest + 242, // 402: openshell.v1.OpenShell.ListWorkspaceMembers:input_type -> openshell.v1.ListWorkspaceMembersRequest + 24, // 403: openshell.v1.OpenShell.Health:output_type -> openshell.v1.HealthResponse + 26, // 404: openshell.v1.OpenShell.GetCurrentUser:output_type -> openshell.v1.GetCurrentUserResponse + 28, // 405: openshell.v1.OpenShell.GetGatewayInfo:output_type -> openshell.v1.GetGatewayInfoResponse + 69, // 406: openshell.v1.OpenShell.CreateSandbox:output_type -> openshell.v1.SandboxResponse + 60, // 407: openshell.v1.OpenShell.BeginRootfsTarStaging:output_type -> openshell.v1.BeginRootfsTarStagingResponse + 69, // 408: openshell.v1.OpenShell.GetSandbox:output_type -> openshell.v1.SandboxResponse + 70, // 409: openshell.v1.OpenShell.ListSandboxes:output_type -> openshell.v1.ListSandboxesResponse + 56, // 410: openshell.v1.OpenShell.CreateSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 56, // 411: openshell.v1.OpenShell.GetSandboxTemplate:output_type -> openshell.v1.SandboxTemplateResponse + 57, // 412: openshell.v1.OpenShell.ListSandboxTemplates:output_type -> openshell.v1.ListSandboxTemplatesResponse + 58, // 413: openshell.v1.OpenShell.DeleteSandboxTemplate:output_type -> openshell.v1.DeleteSandboxTemplateResponse + 71, // 414: openshell.v1.OpenShell.ListSandboxProviders:output_type -> openshell.v1.ListSandboxProvidersResponse + 72, // 415: openshell.v1.OpenShell.AttachSandboxProvider:output_type -> openshell.v1.AttachSandboxProviderResponse + 73, // 416: openshell.v1.OpenShell.DetachSandboxProvider:output_type -> openshell.v1.DetachSandboxProviderResponse + 82, // 417: openshell.v1.OpenShell.GetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 85, // 418: openshell.v1.OpenShell.DeleteSandbox:output_type -> openshell.v1.DeleteSandboxResponse + 69, // 419: openshell.v1.OpenShell.StopSandbox:output_type -> openshell.v1.SandboxResponse + 69, // 420: openshell.v1.OpenShell.StartSandbox:output_type -> openshell.v1.SandboxResponse + 87, // 421: openshell.v1.OpenShell.CreateSshSession:output_type -> openshell.v1.CreateSshSessionResponse + 95, // 422: openshell.v1.OpenShell.ExposeService:output_type -> openshell.v1.ServiceEndpointResponse + 95, // 423: openshell.v1.OpenShell.GetService:output_type -> openshell.v1.ServiceEndpointResponse + 91, // 424: openshell.v1.OpenShell.ListServices:output_type -> openshell.v1.ListServicesResponse + 93, // 425: openshell.v1.OpenShell.DeleteService:output_type -> openshell.v1.DeleteServiceResponse + 97, // 426: openshell.v1.OpenShell.RevokeSshSession:output_type -> openshell.v1.RevokeSshSessionResponse + 102, // 427: openshell.v1.OpenShell.ExecSandbox:output_type -> openshell.v1.ExecSandboxEvent + 104, // 428: openshell.v1.OpenShell.ForwardTcp:output_type -> openshell.v1.TcpForwardFrame + 102, // 429: openshell.v1.OpenShell.ExecSandboxInteractive:output_type -> openshell.v1.ExecSandboxEvent + 117, // 430: openshell.v1.OpenShell.CreateProvider:output_type -> openshell.v1.ProviderResponse + 117, // 431: openshell.v1.OpenShell.GetProvider:output_type -> openshell.v1.ProviderResponse + 118, // 432: openshell.v1.OpenShell.ListProviders:output_type -> openshell.v1.ListProvidersResponse + 143, // 433: openshell.v1.OpenShell.ListProviderProfiles:output_type -> openshell.v1.ListProviderProfilesResponse + 142, // 434: openshell.v1.OpenShell.GetProviderProfile:output_type -> openshell.v1.ProviderProfileResponse + 145, // 435: openshell.v1.OpenShell.ImportProviderProfiles:output_type -> openshell.v1.ImportProviderProfilesResponse + 147, // 436: openshell.v1.OpenShell.UpdateProviderProfiles:output_type -> openshell.v1.UpdateProviderProfilesResponse + 149, // 437: openshell.v1.OpenShell.LintProviderProfiles:output_type -> openshell.v1.LintProviderProfilesResponse + 117, // 438: openshell.v1.OpenShell.UpdateProvider:output_type -> openshell.v1.ProviderResponse + 133, // 439: openshell.v1.OpenShell.GetProviderRefreshStatus:output_type -> openshell.v1.GetProviderRefreshStatusResponse + 135, // 440: openshell.v1.OpenShell.ConfigureProviderRefresh:output_type -> openshell.v1.ConfigureProviderRefreshResponse + 137, // 441: openshell.v1.OpenShell.RotateProviderCredential:output_type -> openshell.v1.RotateProviderCredentialResponse + 139, // 442: openshell.v1.OpenShell.DeleteProviderRefresh:output_type -> openshell.v1.DeleteProviderRefreshResponse + 150, // 443: openshell.v1.OpenShell.DeleteProvider:output_type -> openshell.v1.DeleteProviderResponse + 152, // 444: openshell.v1.OpenShell.DeleteProviderProfile:output_type -> openshell.v1.DeleteProviderProfileResponse + 291, // 445: openshell.v1.OpenShell.GetSandboxConfig:output_type -> openshell.sandbox.v1.GetSandboxConfigResponse + 292, // 446: openshell.v1.OpenShell.GetGatewayConfig:output_type -> openshell.sandbox.v1.GetGatewayConfigResponse + 168, // 447: openshell.v1.OpenShell.UpdateConfig:output_type -> openshell.v1.UpdateConfigResponse + 170, // 448: openshell.v1.OpenShell.GetSandboxPolicyStatus:output_type -> openshell.v1.GetSandboxPolicyStatusResponse + 172, // 449: openshell.v1.OpenShell.ListSandboxPolicies:output_type -> openshell.v1.ListSandboxPoliciesResponse + 174, // 450: openshell.v1.OpenShell.ReportPolicyStatus:output_type -> openshell.v1.ReportPolicyStatusResponse + 247, // 451: openshell.v1.OpenShell.ReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 84, // 452: openshell.v1.OpenShell.ReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 177, // 453: openshell.v1.OpenShell.ReportSandboxConfiguration:output_type -> openshell.v1.ReportSandboxConfigurationResponse + 156, // 454: openshell.v1.OpenShell.GetSandboxProviderEnvironment:output_type -> openshell.v1.GetSandboxProviderEnvironmentResponse + 158, // 455: openshell.v1.OpenShell.ExchangeProviderSubjectToken:output_type -> openshell.v1.ExchangeProviderSubjectTokenResponse + 182, // 456: openshell.v1.OpenShell.GetSandboxLogs:output_type -> openshell.v1.GetSandboxLogsResponse + 181, // 457: openshell.v1.OpenShell.PushSandboxLogs:output_type -> openshell.v1.PushSandboxLogsResponse + 184, // 458: openshell.v1.OpenShell.ConnectSupervisor:output_type -> openshell.v1.GatewayMessage + 191, // 459: openshell.v1.OpenShell.ReportMainProcessExit:output_type -> openshell.v1.ReportMainProcessExitResponse + 193, // 460: openshell.v1.OpenShell.FinalizeMainProcessExit:output_type -> openshell.v1.FinalizeMainProcessExitResponse + 198, // 461: openshell.v1.OpenShell.RelayStream:output_type -> openshell.v1.RelayFrame + 200, // 462: openshell.v1.OpenShell.PeerRelay:output_type -> openshell.v1.PeerRelayFrame + 84, // 463: openshell.v1.OpenShell.PeerReportProviderReadiness:output_type -> openshell.v1.ReportProviderReadinessResponse + 247, // 464: openshell.v1.OpenShell.PeerReportEndpointStatus:output_type -> openshell.v1.ReportEndpointStatusResponse + 82, // 465: openshell.v1.OpenShell.PeerGetSandboxProviderStatus:output_type -> openshell.v1.GetSandboxProviderStatusResponse + 109, // 466: openshell.v1.OpenShell.WatchSandbox:output_type -> openshell.v1.SandboxStreamEvent + 210, // 467: openshell.v1.OpenShell.SubmitPolicyAnalysis:output_type -> openshell.v1.SubmitPolicyAnalysisResponse + 212, // 468: openshell.v1.OpenShell.GetDraftPolicy:output_type -> openshell.v1.GetDraftPolicyResponse + 214, // 469: openshell.v1.OpenShell.ApproveDraftChunk:output_type -> openshell.v1.ApproveDraftChunkResponse + 216, // 470: openshell.v1.OpenShell.RejectDraftChunk:output_type -> openshell.v1.RejectDraftChunkResponse + 219, // 471: openshell.v1.OpenShell.ApproveAllDraftChunks:output_type -> openshell.v1.ApproveAllDraftChunksResponse + 221, // 472: openshell.v1.OpenShell.EditDraftChunk:output_type -> openshell.v1.EditDraftChunkResponse + 223, // 473: openshell.v1.OpenShell.UndoDraftChunk:output_type -> openshell.v1.UndoDraftChunkResponse + 225, // 474: openshell.v1.OpenShell.ClearDraftChunks:output_type -> openshell.v1.ClearDraftChunksResponse + 228, // 475: openshell.v1.OpenShell.GetDraftHistory:output_type -> openshell.v1.GetDraftHistoryResponse + 20, // 476: openshell.v1.OpenShell.IssueSandboxToken:output_type -> openshell.v1.IssueSandboxTokenResponse + 22, // 477: openshell.v1.OpenShell.RefreshSandboxToken:output_type -> openshell.v1.RefreshSandboxTokenResponse + 230, // 478: openshell.v1.OpenShell.CreateWorkspace:output_type -> openshell.v1.CreateWorkspaceResponse + 232, // 479: openshell.v1.OpenShell.GetWorkspace:output_type -> openshell.v1.GetWorkspaceResponse + 234, // 480: openshell.v1.OpenShell.ListWorkspaces:output_type -> openshell.v1.ListWorkspacesResponse + 236, // 481: openshell.v1.OpenShell.DeleteWorkspace:output_type -> openshell.v1.DeleteWorkspaceResponse + 239, // 482: openshell.v1.OpenShell.AddWorkspaceMember:output_type -> openshell.v1.AddWorkspaceMemberResponse + 241, // 483: openshell.v1.OpenShell.RemoveWorkspaceMember:output_type -> openshell.v1.RemoveWorkspaceMemberResponse + 243, // 484: openshell.v1.OpenShell.ListWorkspaceMembers:output_type -> openshell.v1.ListWorkspaceMembersResponse + 403, // [403:485] is the sub-list for method output_type + 321, // [321:403] is the sub-list for method input_type + 321, // [321:321] is the sub-list for extension type_name + 321, // [321:321] is the sub-list for extension extendee + 0, // [0:321] is the sub-list for field type_name } func init() { file_openshell_proto_init() } @@ -20133,7 +20230,7 @@ func file_openshell_proto_init() { (*SandboxStreamEvent_Warning)(nil), (*SandboxStreamEvent_DraftPolicyUpdate)(nil), } - file_openshell_proto_msgTypes[140].OneofWrappers = []any{ + file_openshell_proto_msgTypes[141].OneofWrappers = []any{ (*PolicyMergeOperation_AddRule)(nil), (*PolicyMergeOperation_RemoveEndpoint)(nil), (*PolicyMergeOperation_RemoveRule)(nil), @@ -20141,29 +20238,29 @@ func file_openshell_proto_init() { (*PolicyMergeOperation_AddAllowRules)(nil), (*PolicyMergeOperation_RemoveBinary)(nil), } - file_openshell_proto_msgTypes[144].OneofWrappers = []any{} - file_openshell_proto_msgTypes[163].OneofWrappers = []any{ + file_openshell_proto_msgTypes[145].OneofWrappers = []any{} + file_openshell_proto_msgTypes[164].OneofWrappers = []any{ (*SupervisorMessage_Hello)(nil), (*SupervisorMessage_Heartbeat)(nil), (*SupervisorMessage_RelayOpenResult)(nil), (*SupervisorMessage_RelayClose)(nil), } - file_openshell_proto_msgTypes[164].OneofWrappers = []any{ + file_openshell_proto_msgTypes[165].OneofWrappers = []any{ (*GatewayMessage_SessionAccepted)(nil), (*GatewayMessage_SessionRejected)(nil), (*GatewayMessage_Heartbeat)(nil), (*GatewayMessage_RelayOpen)(nil), (*GatewayMessage_RelayClose)(nil), } - file_openshell_proto_msgTypes[174].OneofWrappers = []any{ + file_openshell_proto_msgTypes[175].OneofWrappers = []any{ (*RelayOpen_Ssh)(nil), (*RelayOpen_Tcp)(nil), } - file_openshell_proto_msgTypes[178].OneofWrappers = []any{ + file_openshell_proto_msgTypes[179].OneofWrappers = []any{ (*RelayFrame_Init)(nil), (*RelayFrame_Data)(nil), } - file_openshell_proto_msgTypes[180].OneofWrappers = []any{ + file_openshell_proto_msgTypes[181].OneofWrappers = []any{ (*PeerRelayFrame_Init)(nil), (*PeerRelayFrame_Data)(nil), } @@ -20173,7 +20270,7 @@ func file_openshell_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_openshell_proto_rawDesc), len(file_openshell_proto_rawDesc)), NumEnums: 19, - NumMessages: 253, + NumMessages: 255, NumExtensions: 0, NumServices: 1, }, diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index 4db30ebac0..c9440dfaad 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -377,6 +377,8 @@ attachments running. Configure VS Code Remote-SSH with: openshell sandbox ssh-config my-sandbox >> ~/.ssh/config ``` +A writable attachment that finds another attachment holding stdin reports `attached read-only; retry input after the owner disconnects`. Automatic recovery can hit this when it reattaches before the supervisor closes the dead connection. The supervisor closes a connection 60 seconds after it last received bytes from it, which can be later than 60 seconds after the network failed if the relay buffered data. After the old owner disconnects or times out, send the input you meant to type next. If stdin is free, the attachment prints `input enabled` and forwards that input to the process, so do not probe with Enter or a prompt answer such as `y`. If nothing prints, the old connection still holds stdin. Input sent while the attachment was read-only never reaches the process, so send it again later. `Ctrl-C`, `Ctrl-D`, and `Ctrl-P` then `Ctrl-Q` still exit a read-only attachment instead of enabling input; enable input first if you need `Ctrl-C` to interrupt the process. Recovery never takes stdin from a healthy owner, and an explicitly read-only attachment stays read-only. + If `connect` reports `canonical main process already finished`, inspect the result with `sandbox get`. A pending foreground attachment can still retrieve retained output in `Completed` or `Error`; phase alone does not determine