From 26af028b1776916977c9de414a5f320d23e85cca Mon Sep 17 00:00:00 2001 From: Dionisio Date: Tue, 19 Nov 2024 18:03:43 +0100 Subject: [PATCH] fix frontend issues --- api-gateway/backend/src/backends/mod.rs | 7 ++ .../backend/src/gateway/crd/gateway.rs | 24 +++++-- api-gateway/backend/src/gateway/handlers.rs | 40 ++++++++++- api-gateway/backend/src/gateway/mod.rs | 1 + api-gateway/backend/src/gateway/models.rs | 51 ++++++++++---- api-gateway/backend/src/lib.rs | 14 +++- api-gateway/backend/src/main.rs | 12 ++-- api-gateway/backend/src/observability/mod.rs | 7 ++ api-gateway/backend/src/plugins/mod.rs | 10 +++ api-gateway/backend/src/plugins/routes.rs | 8 +++ api-gateway/backend/src/security/handlers.rs | 13 ++-- api-gateway/backend/src/security/mod.rs | 7 ++ api-gateway/backend/src/security/routes.rs | 2 +- api-gateway/frontend/src/apiClient.ts | 66 +------------------ .../frontend/src/components/Backends.tsx | 4 +- .../frontend/src/components/Dashboard.tsx | 34 +++++----- .../frontend/src/components/Gateways.tsx | 4 +- .../frontend/src/components/Observability.tsx | 5 +- .../frontend/src/components/Security.tsx | 4 +- 19 files changed, 191 insertions(+), 122 deletions(-) diff --git a/api-gateway/backend/src/backends/mod.rs b/api-gateway/backend/src/backends/mod.rs index 4cb20d14..781b7093 100644 --- a/api-gateway/backend/src/backends/mod.rs +++ b/api-gateway/backend/src/backends/mod.rs @@ -2,3 +2,10 @@ pub mod handlers; pub mod routes; pub use routes::configure_routes; + +/// Inicializar el manejador de backends +pub async fn start_backends_manager() -> Result<(), Box> { + println!("Starting Backends Manager..."); + // Aquí iría la lógica específica de inicialización del manejador de backends + Ok(()) +} diff --git a/api-gateway/backend/src/gateway/crd/gateway.rs b/api-gateway/backend/src/gateway/crd/gateway.rs index fedf23f5..64e5f05b 100644 --- a/api-gateway/backend/src/gateway/crd/gateway.rs +++ b/api-gateway/backend/src/gateway/crd/gateway.rs @@ -105,11 +105,11 @@ impl GatewayManager { certificate: &str, ) -> Result<(), GatewayError> { let gateways: Api = Api::namespaced_with(self.client.clone(), namespace, &self.ar); - + // Obtener el Gateway existente. let mut existing_gateway = gateways.get(name).await?; - let mut data = existing_gateway.data; - + let mut data = existing_gateway.data.clone(); // Clonar el campo data + // Actualizar el certificado y habilitar TLS. if let Some(spec) = data.get_mut("spec") { if let Some(spec_obj) = spec.as_object_mut() { @@ -117,12 +117,13 @@ impl GatewayManager { spec_obj.insert("certificate".to_string(), serde_json::Value::String(certificate.to_string())); } } - - // Actualizar el Gateway. + + // Reemplazar el Gateway con los cambios actualizados. + existing_gateway.data = data; // Actualizar el campo data después de la edición gateways.replace(name, &PostParams::default(), &existing_gateway).await?; Ok(()) } - + /// Obtener métricas simuladas de los Gateways. pub async fn get_metrics(&self) -> Result, GatewayError> { // Ejemplo de métricas simuladas. @@ -141,3 +142,14 @@ pub enum GatewayError { #[error("Error de serialización/deserialización: {0}")] SerdeError(#[from] serde_json::Error), } + +/// Implementación de conversión de `models::Route` a `gateway::crd::gateway::Route`. +impl From for Route { + fn from(route: crate::gateway::models::Route) -> Self { + Route { + path: route.path.unwrap_or_default(), + backend: route.backend, + methods: route.methods, + } + } +} diff --git a/api-gateway/backend/src/gateway/handlers.rs b/api-gateway/backend/src/gateway/handlers.rs index 3f8adc6d..38beba88 100644 --- a/api-gateway/backend/src/gateway/handlers.rs +++ b/api-gateway/backend/src/gateway/handlers.rs @@ -2,8 +2,8 @@ use actix_web::{web, HttpResponse, Responder}; use serde_json::json; use kube::Client; -use super::crd::gateway::GatewayManager; // Manager para Gateways -use super::models::{Gateway, Route}; // Modelos compartidos +use crate::gateway::crd::gateway::{GatewaySpec, GatewayInnerSpec, GatewayManager}; +use super::models::Gateway; // Modelo de Gateway compartido /// Listar todos los Gateways disponibles en Kubernetes. pub async fn list_gateways(client: web::Data) -> impl Responder { @@ -22,7 +22,18 @@ pub async fn list_gateways(client: web::Data) -> impl Responder { pub async fn add_gateway(client: web::Data, gateway: web::Json) -> impl Responder { let manager = GatewayManager::new(client.get_ref().clone()); - match manager.create_gateway("default", &gateway.into_inner()).await { + // Construir `GatewaySpec` basado en el modelo `Gateway`. + let gateway_spec = GatewaySpec { + spec: GatewayInnerSpec { + hostname: gateway.hostname.clone(), + tls_enabled: gateway.tls_enabled, + certificate: gateway.certificate.clone(), + routes: gateway.routes.iter().cloned().map(Into::into).collect(), + }, + }; + + + match manager.create_gateway("default", &gateway_spec).await { Ok(_) => HttpResponse::Created().json(json!({ "message": "Gateway created successfully." })), Err(e) => { eprintln!("Error creating Gateway: {:?}", e); @@ -73,3 +84,26 @@ pub async fn get_gateway_metrics(client: web::Data) -> impl Responder { } } } + +/// Inicia el servicio de Gateway API. +/// Esto configura y ejecuta todos los endpoints relacionados con Gateways. +pub async fn start_gateway_api(client: Client) -> Result<(), Box> { + println!("Starting Gateway API..."); + + // Configuración del servidor Actix-Web para manejar los endpoints. + actix_web::HttpServer::new(move || { + actix_web::App::new() + .app_data(web::Data::new(client.clone())) + .route("/gateways", web::get().to(list_gateways)) // Endpoint para listar Gateways + .route("/gateways", web::post().to(add_gateway)) // Endpoint para crear Gateway + .route("/gateways/{id}", web::delete().to(delete_gateway)) // Eliminar Gateway + .route("/gateways/tls", web::post().to(configure_tls)) // Configurar TLS + .route("/gateways/metrics", web::get().to(get_gateway_metrics)) // Obtener métricas + }) + .bind(("0.0.0.0", 8082))? // Puerto para el Gateway API + .run() + .await?; + + println!("Gateway API is running on port 8082."); + Ok(()) +} diff --git a/api-gateway/backend/src/gateway/mod.rs b/api-gateway/backend/src/gateway/mod.rs index b6dadde3..bc742b27 100644 --- a/api-gateway/backend/src/gateway/mod.rs +++ b/api-gateway/backend/src/gateway/mod.rs @@ -10,5 +10,6 @@ pub mod models; // Define las estructuras de datos compartidas pub mod crd; // Interacción con los CRDs en Kubernetes pub use handlers::*; +pub use handlers::{start_gateway_api, list_gateways, add_gateway, delete_gateway, configure_tls, get_gateway_metrics}; pub use models::*; pub use crd::*; diff --git a/api-gateway/backend/src/gateway/models.rs b/api-gateway/backend/src/gateway/models.rs index 5dd82878..1482e281 100644 --- a/api-gateway/backend/src/gateway/models.rs +++ b/api-gateway/backend/src/gateway/models.rs @@ -8,20 +8,45 @@ use serde::{Deserialize, Serialize}; /// Este modelo mapea directamente los datos necesarios para un Gateway CRD. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Gateway { - pub id: String, // Identificador único del Gateway - pub hostname: String, // Hostname del Gateway - pub tls_enabled: bool, // Indica si TLS está habilitado + pub id: String, // Identificador único del Gateway + pub hostname: String, // Hostname del Gateway + pub tls_enabled: bool, // Indica si TLS está habilitado pub certificate: Option, // Certificado TLS, si aplica - pub routes: Vec, // Rutas asociadas a este Gateway + pub routes: Vec, // Rutas asociadas a este Gateway + pub gateway_class_name: String, // Nombre de la clase del Gateway + pub listeners: Vec, // Listeners del Gateway +} + +impl Gateway { + /// Convierte un `Gateway` en un `GatewaySpec` para su uso con los CRDs. + pub fn to_spec(&self) -> super::crd::gateway::GatewaySpec { + super::crd::gateway::GatewaySpec { + spec: super::crd::gateway::GatewayInnerSpec { + hostname: self.hostname.clone(), + tls_enabled: self.tls_enabled, + certificate: self.certificate.clone(), + routes: self.routes.iter().map(|r| r.clone().into()).collect(), + }, + } + } +} + + +/// Representa un listener dentro de un Gateway. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Listener { + pub name: String, // Nombre del listener + pub protocol: String, // Protocolo del listener (e.g., HTTP, HTTPS) + pub port: u16, // Puerto del listener } /// Representa una ruta dentro de un Gateway. /// Este modelo mapea las configuraciones necesarias para HTTPRoute, GRPCRoute, o TLSRoute. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Route { - pub id: String, // Identificador único de la ruta + pub id: String, // Identificador único de la ruta pub path: Option, // Ruta específica (e.g., "/api/*") - pub backend: String, // Nombre del backend asociado + pub backend: String, // Nombre del backend asociado pub methods: Vec, // Métodos permitidos (e.g., ["GET", "POST"]) pub protocols: Vec, // Protocolos soportados (e.g., ["HTTP", "HTTPS"]) } @@ -29,23 +54,23 @@ pub struct Route { /// Representa métricas relacionadas con los Gateways. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GatewayMetric { - pub gateway_id: String, // ID del Gateway asociado - pub metric_name: String, // Nombre de la métrica (e.g., "latency", "requests_per_second") - pub value: f64, // Valor de la métrica - pub timestamp: String, // Marca de tiempo de la métrica + pub gateway_id: String, // ID del Gateway asociado + pub metric_name: String, // Nombre de la métrica (e.g., "latency", "requests_per_second") + pub value: f64, // Valor de la métrica + pub timestamp: String, // Marca de tiempo de la métrica } /// Representa la configuración de TLS para un Gateway. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TLSConfig { - pub certificate: String, // Contenido del certificado TLS + pub certificate: String, // Contenido del certificado TLS pub private_key: Option, // Clave privada asociada, si es necesaria - pub ca_bundle: Option, // Certificados de autoridad, si aplica + pub ca_bundle: Option, // Certificados de autoridad, si aplica } /// Representa errores genéricos relacionados con los Gateways o rutas. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GatewayError { - pub message: String, // Descripción del error + pub message: String, // Descripción del error pub details: Option, // Detalles adicionales sobre el error } diff --git a/api-gateway/backend/src/lib.rs b/api-gateway/backend/src/lib.rs index 4dcccb06..5e68c4a5 100644 --- a/api-gateway/backend/src/lib.rs +++ b/api-gateway/backend/src/lib.rs @@ -1,2 +1,12 @@ -pub mod gateway; -pub mod rest; +pub mod gateway; // Módulo para Gateway +pub mod backends; // Módulo para manejar Backends +pub mod observability; // Módulo para Observability +pub mod security; // Módulo para Seguridad +pub mod plugins; // Módulo para Plugins +pub mod rest; // REST server + +// Reexportar configuraciones de rutas para `main.rs` +// pub use backends::configure_routes as configure_backends_routes; +// pub use observability::configure_routes as configure_observability_routes; +// pub use security::configure_routes as configure_security_routes; +// pub use plugins::configure_routes as configure_plugins_routes; diff --git a/api-gateway/backend/src/main.rs b/api-gateway/backend/src/main.rs index c7ebe2a6..f4df8897 100644 --- a/api-gateway/backend/src/main.rs +++ b/api-gateway/backend/src/main.rs @@ -43,8 +43,8 @@ async fn main() -> Result<(), Box> { Box::::from(e) }), - // Start Backends manager - start_backends_manager(client.clone()).map_err(|e| { + // Start Backends manager (no arguments required) + start_backends_manager().map_err(|e| { eprintln!("Error in start_backends_manager: {:?}", e); Box::::from(e) }), @@ -55,14 +55,14 @@ async fn main() -> Result<(), Box> { Box::::from(e) }), - // Start Security service - start_security_service(client.clone()).map_err(|e| { + // Start Security service (no arguments required) + start_security_service().map_err(|e| { eprintln!("Error in start_security_service: {:?}", e); Box::::from(e) }), - // Start Plugins manager - start_plugins_manager(client.clone()).map_err(|e| { + // Start Plugins manager (no arguments required) + start_plugins_manager().map_err(|e| { eprintln!("Error in start_plugins_manager: {:?}", e); Box::::from(e) }) diff --git a/api-gateway/backend/src/observability/mod.rs b/api-gateway/backend/src/observability/mod.rs index 4cb20d14..0c2c4380 100644 --- a/api-gateway/backend/src/observability/mod.rs +++ b/api-gateway/backend/src/observability/mod.rs @@ -2,3 +2,10 @@ pub mod handlers; pub mod routes; pub use routes::configure_routes; + +/// Inicializar el servicio de observabilidad +pub async fn start_observability_service(port: u16) -> Result<(), Box> { + println!("Starting Observability Service on port {}...", port); + // Aquí iría la lógica específica de inicialización de observabilidad + Ok(()) +} diff --git a/api-gateway/backend/src/plugins/mod.rs b/api-gateway/backend/src/plugins/mod.rs index e69de29b..61d759d9 100644 --- a/api-gateway/backend/src/plugins/mod.rs +++ b/api-gateway/backend/src/plugins/mod.rs @@ -0,0 +1,10 @@ +pub mod routes; + +pub use routes::configure_routes; + +/// Inicializar el manejador de plugins +pub async fn start_plugins_manager() -> Result<(), Box> { + println!("Starting Plugins Manager..."); + // Aquí iría la lógica específica de inicialización de plugins + Ok(()) +} diff --git a/api-gateway/backend/src/plugins/routes.rs b/api-gateway/backend/src/plugins/routes.rs index e69de29b..34f19c7a 100644 --- a/api-gateway/backend/src/plugins/routes.rs +++ b/api-gateway/backend/src/plugins/routes.rs @@ -0,0 +1,8 @@ +use actix_web::web; + +pub fn configure_routes(cfg: &mut web::ServiceConfig) { + cfg.service( + web::scope("/api/plugins") + .route("/status", web::get().to(|| async { "Plugin status endpoint" })), // Ejemplo + ); +} diff --git a/api-gateway/backend/src/security/handlers.rs b/api-gateway/backend/src/security/handlers.rs index a9c2ff54..2c1ae948 100644 --- a/api-gateway/backend/src/security/handlers.rs +++ b/api-gateway/backend/src/security/handlers.rs @@ -1,5 +1,3 @@ -//! Handlers para la gestión de seguridad en el API Gateway. - use actix_web::{web, HttpResponse, Responder}; use serde::{Deserialize, Serialize}; use std::sync::Mutex; @@ -69,8 +67,9 @@ pub async fn add_policy(data: web::Data, policy: web::Json, id: web::Path) -> impl Responder { let mut policies = data.policies.lock().unwrap(); + let id_value = *id; // Clona o copia el valor de `id`. let initial_len = policies.len(); - policies.retain(|policy| policy.id != id.into_inner()); + policies.retain(|policy| policy.id != id_value); // Usa la copia aquí. if policies.len() < initial_len { HttpResponse::Ok().finish() } else { @@ -80,8 +79,7 @@ pub async fn delete_policy(data: web::Data, id: web::Path) -> imp /// Validar un token JWT pub async fn validate_jwt(token: web::Path) -> impl Responder { - // Simulación de validación de JWT - let valid = token == "valid_token"; + let valid = token.as_str() == "valid_token"; // Usa `.as_str()` para obtener un `&str`. if valid { HttpResponse::Ok().json(JwtValidationResponse { valid: true, @@ -116,3 +114,8 @@ pub async fn update_tls_config(tls_data: web::Json<(String, String)>) -> impl Re "key": key, })) } + +/// Endpoint protegido +pub async fn protected_endpoint() -> impl Responder { + HttpResponse::Ok().body("This is a protected endpoint!") +} diff --git a/api-gateway/backend/src/security/mod.rs b/api-gateway/backend/src/security/mod.rs index 4cb20d14..0bff5c04 100644 --- a/api-gateway/backend/src/security/mod.rs +++ b/api-gateway/backend/src/security/mod.rs @@ -2,3 +2,10 @@ pub mod handlers; pub mod routes; pub use routes::configure_routes; + +/// Inicializar el servicio de seguridad +pub async fn start_security_service() -> Result<(), Box> { + println!("Starting Security Service..."); + // Aquí iría la lógica específica de inicialización de seguridad + Ok(()) +} diff --git a/api-gateway/backend/src/security/routes.rs b/api-gateway/backend/src/security/routes.rs index 542800bd..8ef4bb52 100644 --- a/api-gateway/backend/src/security/routes.rs +++ b/api-gateway/backend/src/security/routes.rs @@ -4,7 +4,7 @@ use super::handlers; pub fn configure_routes(cfg: &mut web::ServiceConfig) { cfg.service( web::scope("/api/security") - .route("/policies", web::get().to(handlers::get_policies)) + .route("/policies", web::get().to(handlers::list_policies)) .route("/policies", web::post().to(handlers::add_policy)) .route("/policies/{name}", web::delete().to(handlers::delete_policy)) .route("/protected", web::get().to(handlers::protected_endpoint)), diff --git a/api-gateway/frontend/src/apiClient.ts b/api-gateway/frontend/src/apiClient.ts index da9961c0..f82f5dce 100644 --- a/api-gateway/frontend/src/apiClient.ts +++ b/api-gateway/frontend/src/apiClient.ts @@ -27,6 +27,7 @@ export const gatewaysApi = { export const observabilityApi = { getMetrics: () => apiClient.get('/observability/metrics'), getLogs: () => apiClient.get('/observability/logs'), + getAlerts: () => apiClient.get('/observability/alerts'), }; // Security @@ -41,67 +42,4 @@ export const securityApi = { }; // Exportar apiClient por si necesitas más personalización en el futuro -export default apiClient; - - - - - - -import axios from 'axios'; - -const apiClient = axios.create({ - baseURL: '/api', // Vite redirigirá a http://backend-service:8081 -}); - -export const listBackends = () => apiClient.get('/backends'); -export const addBackend = (backend: any) => apiClient.post('/backends', backend); -export const deleteBackend = (id: number) => apiClient.delete(`/backends/${id}`); -export const healthCheck = () => apiClient.get('/health-check'); - - - - - -import axios from 'axios'; - -const apiClient = axios.create({ - baseURL: '/api', -}); - -export const listGateways = () => apiClient.get('/gateways'); -export const addGateway = (gateway: any) => apiClient.post('/gateways', gateway); -export const deleteGateway = (id: number) => apiClient.delete(`/gateways/${id}`); -export const configureTLS = (id: number, certificate: string) => - apiClient.post('/gateways/tls', { id, certificate }); -export const gatewayMetrics = () => apiClient.get('/gateways/metrics'); - - - - - - -import axios from 'axios'; - -const apiClient = axios.create({ - baseURL: '/api', -}); - -export const getObservabilityMetrics = () => apiClient.get('/observability/metrics'); -export const getObservabilityLogs = () => apiClient.get('/observability/logs'); - - -import axios from 'axios'; - -const apiClient = axios.create({ - baseURL: '/api', -}); - -export const getSecurityPolicies = () => apiClient.get('/security/policies'); -export const addSecurityPolicy = (policy: any) => apiClient.post('/security/policies', policy); -export const deleteSecurityPolicy = (name: string) => - apiClient.delete(`/security/policies/${name}`); -export const testProtectedEndpoint = (token: string) => - apiClient.get('/protected', { - headers: { Authorization: `Bearer ${token}` }, - }); +export default apiClient; \ No newline at end of file diff --git a/api-gateway/frontend/src/components/Backends.tsx b/api-gateway/frontend/src/components/Backends.tsx index c2c67cdc..94bece0e 100644 --- a/api-gateway/frontend/src/components/Backends.tsx +++ b/api-gateway/frontend/src/components/Backends.tsx @@ -13,7 +13,9 @@ import { DialogActions, TextField, } from '@mui/material'; -import { listBackends, addBackend, deleteBackend, healthCheck } from '../apiClient'; +import { backendsApi } from '../apiClient'; + +const { listBackends, addBackend, deleteBackend, healthCheck } = backendsApi; const Backends: React.FC = () => { const [backends, setBackends] = useState([]); diff --git a/api-gateway/frontend/src/components/Dashboard.tsx b/api-gateway/frontend/src/components/Dashboard.tsx index e2c8c84f..3de48bdb 100644 --- a/api-gateway/frontend/src/components/Dashboard.tsx +++ b/api-gateway/frontend/src/components/Dashboard.tsx @@ -1,15 +1,15 @@ import React, { useEffect, useState } from 'react'; -import { - Grid, - Card, - CardContent, - Typography, - Table, - TableHead, - TableRow, - TableCell, - TableBody, - LinearProgress +import { + Grid, + Card, + CardContent, + Typography, + Table, + TableHead, + TableRow, + TableCell, + TableBody, + LinearProgress, } from '@mui/material'; import { Line } from 'react-chartjs-2'; import { @@ -22,7 +22,7 @@ import { Tooltip, Legend, } from 'chart.js'; -import { getMetrics, getAlerts } from '../apiClient'; // Usa el cliente API +import { observabilityApi } from '../apiClient'; // Importa el cliente API // Registrar componentes y escalas de Chart.js ChartJS.register( @@ -91,12 +91,12 @@ const Dashboard: React.FC = () => { // Fetch data from API const fetchDashboardData = async () => { try { - const [metricsData, alertsData] = await Promise.all([ - getMetrics(), - getAlerts(), + const [metricsResponse, alertsResponse] = await Promise.all([ + observabilityApi.getMetrics(), + observabilityApi.getAlerts(), ]); - setMetrics(metricsData); - setAlerts(alertsData); + setMetrics(metricsResponse.data); // Ajusta según la estructura de los datos + setAlerts(alertsResponse.data); // Ajusta según la estructura de los datos } catch (err) { console.error('Error fetching dashboard data:', err); setError('Failed to load dashboard data.'); diff --git a/api-gateway/frontend/src/components/Gateways.tsx b/api-gateway/frontend/src/components/Gateways.tsx index ba394479..dcd4405d 100644 --- a/api-gateway/frontend/src/components/Gateways.tsx +++ b/api-gateway/frontend/src/components/Gateways.tsx @@ -12,7 +12,9 @@ import { DialogActions, TextField, } from '@mui/material'; -import { listGateways, addGateway, deleteGateway, configureTLS } from '../apiClient'; +import { gatewaysApi } from '../apiClient'; + +const { listGateways, addGateway, deleteGateway, configureTLS } = gatewaysApi; const Gateways: React.FC = () => { const [gateways, setGateways] = useState([]); diff --git a/api-gateway/frontend/src/components/Observability.tsx b/api-gateway/frontend/src/components/Observability.tsx index d7f19b0d..6f2e17a9 100644 --- a/api-gateway/frontend/src/components/Observability.tsx +++ b/api-gateway/frontend/src/components/Observability.tsx @@ -12,9 +12,10 @@ import { CardContent, LinearProgress, } from '@mui/material'; -import { getObservabilityMetrics, getObservabilityLogs } from '../apiClient'; +import { observabilityApi } from '../apiClient'; + +const { getMetrics: getObservabilityMetrics, getLogs: getObservabilityLogs } = observabilityApi; -// Interfaces interface Metric { name: string; value: number; diff --git a/api-gateway/frontend/src/components/Security.tsx b/api-gateway/frontend/src/components/Security.tsx index 6300742a..9de5744c 100644 --- a/api-gateway/frontend/src/components/Security.tsx +++ b/api-gateway/frontend/src/components/Security.tsx @@ -16,7 +16,9 @@ import { DialogActions, TextField, } from '@mui/material'; -import { getSecurityPolicies, addSecurityPolicy, deleteSecurityPolicy } from '../apiClient'; +import { securityApi } from '../apiClient'; + +const { getPolicies: getSecurityPolicies, addPolicy: addSecurityPolicy, deletePolicy: deleteSecurityPolicy } = securityApi; interface Policy { name: string;