Skip to main content

authz_resolver/
module.rs

1//! `AuthZ` resolver module.
2
3use std::sync::{Arc, OnceLock};
4
5use async_trait::async_trait;
6use authz_resolver_sdk::{AuthZResolverClient, AuthZResolverPluginSpecV1};
7use modkit::Module;
8use modkit::context::ModuleCtx;
9use tracing::info;
10use types_registry_sdk::{RegisterResult, TypesRegistryClient};
11
12use crate::config::AuthZResolverConfig;
13use crate::domain::{AuthZResolverLocalClient, Service};
14
15/// `AuthZ` Resolver module.
16///
17/// This module:
18/// 1. Registers the plugin schema in types-registry
19/// 2. Discovers plugin instances via types-registry
20/// 3. Routes requests to the selected plugin based on vendor configuration
21///
22/// Plugin discovery is lazy: happens on first API call after types-registry
23/// is ready.
24#[modkit::module(
25    name = "authz-resolver",
26    deps = ["types-registry"],
27    capabilities = []
28)]
29pub(crate) struct AuthZResolver {
30    service: OnceLock<Arc<Service>>,
31}
32
33impl Default for AuthZResolver {
34    fn default() -> Self {
35        Self {
36            service: OnceLock::new(),
37        }
38    }
39}
40
41#[async_trait]
42impl Module for AuthZResolver {
43    #[tracing::instrument(skip_all, fields(vendor))]
44    async fn init(&self, ctx: &ModuleCtx) -> anyhow::Result<()> {
45        let cfg: AuthZResolverConfig = ctx.config()?;
46        tracing::Span::current().record("vendor", cfg.vendor.as_str());
47        info!(vendor = %cfg.vendor, "Initializing authz_resolver");
48
49        // Register plugin schema in types-registry
50        let registry = ctx.client_hub().get::<dyn TypesRegistryClient>()?;
51        let schema_str = AuthZResolverPluginSpecV1::gts_schema_with_refs_as_string();
52        let schema_json: serde_json::Value = serde_json::from_str(&schema_str)?;
53        let results = registry.register(vec![schema_json]).await?;
54        RegisterResult::ensure_all_ok(&results)?;
55        info!(
56            schema_id = %AuthZResolverPluginSpecV1::gts_schema_id(),
57            "Registered plugin schema in types-registry"
58        );
59
60        // Create service
61        let hub = ctx.client_hub();
62        let svc = Arc::new(Service::new(hub, cfg.vendor));
63
64        // Register client in ClientHub
65        let api: Arc<dyn AuthZResolverClient> =
66            Arc::new(AuthZResolverLocalClient::new(svc.clone()));
67        ctx.client_hub().register::<dyn AuthZResolverClient>(api);
68
69        self.service
70            .set(svc)
71            .map_err(|_| anyhow::anyhow!("Service already initialized"))?;
72
73        Ok(())
74    }
75}