// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 use openshell_core::proto::SandboxPolicy; use openshell_supervisor_middleware::MiddlewareRegistry; use tonic::Status; /// Validate implementation-owned middleware config before accepting a policy. pub async fn validate_policy( registry: &MiddlewareRegistry, policy: &SandboxPolicy, ) -> Result<(), Status> { registry .validate_policy_configs(policy) .await .map_err(|error| { Status::invalid_argument(format!("policy middleware validation failed: {error}")) }) } #[cfg(test)] mod tests { use super::*; use openshell_core::proto::NetworkMiddlewareConfig; #[tokio::test] async fn unregistered_external_middleware_is_rejected_before_admission() { let policy = SandboxPolicy { network_middlewares: std::collections::HashMap::from([( "guard".into(), NetworkMiddlewareConfig { middleware: "example/content-guard".into(), ..Default::default() }, )]), ..Default::default() }; let error = validate_policy(&MiddlewareRegistry::default(), &policy) .await .expect_err("unregistered middleware must fail"); assert_eq!(error.code(), tonic::Code::InvalidArgument); assert!(error.message().contains("not registered")); } #[tokio::test] async fn invalid_builtin_config_is_rejected_by_implementation() { let registry = MiddlewareRegistry::connect_services( openshell_supervisor_middleware_builtins::services(), Vec::new(), ) .await .expect("built-in registry"); let policy = SandboxPolicy { network_middlewares: std::collections::HashMap::from([( "redactor".into(), NetworkMiddlewareConfig { middleware: openshell_supervisor_middleware_builtins::BUILTIN_REGEX.into(), config: Some(prost_types::Struct { fields: std::iter::once(( "mode".into(), prost_types::Value { kind: Some(prost_types::value::Kind::StringValue("allow".into())), }, )) .collect(), }), ..Default::default() }, )]), ..Default::default() }; let error = validate_policy(®istry, &policy) .await .expect_err("invalid built-in config must fail admission"); assert_eq!(error.code(), tonic::Code::InvalidArgument); assert!(error.message().contains("supports only mode: redact")); } }