pdk-core 1.7.0-alpha.0

PDK Core
Documentation
// Copyright (c) 2025, Salesforce, Inc.,
// All rights reserved.
// For full license text, see the LICENSE.txt file

//! Data types that exposes metadata for the policy.

use crate::policy_context::metadata::{Api, EnvironmentContext};
use crate::policy_context::static_policy_context_cache::StaticPolicyContextCache;
use classy::extract::context::ConfigureContext;
use classy::extract::FromContext;
use classy::hl::Service;
use std::convert::Infallible;

#[derive(Clone, Debug)]
/// Metadata about the API and the policy.
pub struct Metadata {
    /// Metadata regarding the flex instance where the policy is running.
    pub flex_metadata: FlexMetadata,
    /// Metadata regarding the policy.
    pub policy_metadata: PolicyMetadata,
    /// Metadata regarding the api where the policy is applied.
    pub api_metadata: ApiMetadata,
    /// Metadata regarding the management plane.
    pub platform_metadata: PlatformMetadata,
}

#[derive(Clone, Debug)]
/// Information about the Flex Gateway where the policy is running.
pub struct FlexMetadata {
    /// Name of the flex instance
    pub flex_name: String,
    /// Version of the flex instance
    pub flex_version: String,
}

#[derive(Clone, Debug)]
/// Metadata regarding the policy.
pub struct PolicyMetadata {
    /// Name of the policy.
    pub policy_name: String,
    /// Namespace of the policy.
    pub policy_namespace: String,
    #[cfg(feature = "experimental_filter_name")]
    /// The name of the filter.
    pub filter_name: String,
}

#[derive(Clone, Debug)]
/// Metadata regarding the api where the policy is applied.
pub struct ApiMetadata {
    /// The ID of the API.
    pub id: Option<String>,
    /// The name of the API.
    pub name: Option<String>,
    /// The version of the API.
    pub version: Option<String>,
    /// The base_path of the API.
    pub base_path: Option<String>,
    /// The slas associated to the API.
    pub slas: Option<Vec<ApiSla>>,
    #[cfg(feature = "experimental")]
    /// The asset associated to the API.
    pub asset: Option<ApiAsset>,
}

#[derive(Clone, Debug, Default)]
/// Metadata regarding the management plane.
pub struct PlatformMetadata {
    /// Organization ID
    pub organization_id: String,
    /// Environment ID
    pub environment_id: String,
    /// The root organization ID
    pub root_organization_id: String,
}

#[derive(Clone, Debug)]
/// The SLA associated to the API.
pub struct ApiSla {
    /// The id of the SLA.
    pub id: String,
    /// The tiers associated to the SLA.
    pub tiers: Vec<Tier>,
}

#[derive(Clone, Debug)]
/// The limits associated to a [`ApiSla`]
pub struct Tier {
    /// Number of requests allowed on a given time.
    pub requests: u64,
    /// Time in which the requests are tracked.
    pub period_in_millis: u64,
}

#[derive(Clone, Debug)]
/// The asset associated to the API.
pub struct ApiAsset {
    /// The [`Service`] to use to download the schema.
    pub service: Service,
}

impl From<&crate::policy_context::metadata::PolicyMetadata> for Metadata {
    fn from(value: &crate::policy_context::metadata::PolicyMetadata) -> Self {
        Metadata {
            flex_metadata: value.into(),
            policy_metadata: value.into(),
            api_metadata: value.into(),
            platform_metadata: value.into(),
        }
    }
}

impl From<&crate::policy_context::metadata::PolicyMetadata> for FlexMetadata {
    fn from(value: &crate::policy_context::metadata::PolicyMetadata) -> Self {
        FlexMetadata {
            flex_name: value.flex_name().to_string(),
            flex_version: value
                .anypoint_environment()
                .and_then(EnvironmentContext::flex_version)
                .map(str::to_string)
                // Will always be set since min flex version is 1.6.1
                .unwrap_or_default(),
        }
    }
}

impl From<&crate::policy_context::metadata::PolicyMetadata> for PolicyMetadata {
    fn from(value: &crate::policy_context::metadata::PolicyMetadata) -> Self {
        PolicyMetadata {
            policy_name: value.policy_id().to_string(),
            policy_namespace: value.policy_namespace().to_string(),
            #[cfg(feature = "experimental_filter_name")]
            filter_name: value.filter_name().to_string(),
        }
    }
}

impl From<&crate::policy_context::metadata::PolicyMetadata> for ApiMetadata {
    fn from(value: &crate::policy_context::metadata::PolicyMetadata) -> Self {
        ApiMetadata {
            id: value.api_info().map(Api::id).map(str::to_string),
            name: value.api_info().map(Api::name).map(str::to_string),
            version: value.api_info().map(Api::version).map(str::to_string),
            base_path: value
                .api_info()
                .and_then(Api::base_path)
                .map(str::to_string),
            slas: value
                .api_tiers()
                .map(|slas| slas.iter().map(|sla| sla.into()).collect()),
            #[cfg(feature = "experimental")]
            asset: value
                .api_info()
                .and_then(Api::exchange)
                .map(|exchange| ApiAsset {
                    service: exchange.service(),
                }),
        }
    }
}

impl From<&crate::policy_context::metadata::ApiSla> for ApiSla {
    fn from(value: &crate::policy_context::metadata::ApiSla) -> Self {
        ApiSla {
            id: value.id().to_string(),
            tiers: value.tiers().iter().map(|s| s.into()).collect(),
        }
    }
}

impl From<&crate::policy_context::metadata::Tier> for Tier {
    fn from(value: &crate::policy_context::metadata::Tier) -> Self {
        Tier {
            requests: value.requests(),
            period_in_millis: value.period_in_millis(),
        }
    }
}

impl From<&crate::policy_context::metadata::PolicyMetadata> for PlatformMetadata {
    fn from(value: &crate::policy_context::metadata::PolicyMetadata) -> Self {
        // PlatformMetadata should always be set since it is read from the registration yaml.
        value
            .anypoint_environment()
            .map(|env| PlatformMetadata {
                organization_id: env.organization_id().to_string(),
                environment_id: env.environment_id().to_string(),
                root_organization_id: env.master_organization_id().to_string(),
            })
            .unwrap_or_default()
    }
}

impl FromContext<ConfigureContext> for Metadata {
    type Error = Infallible;

    fn from_context(_context: &ConfigureContext) -> Result<Self, Self::Error> {
        Ok(Metadata::new())
    }
}

impl Metadata {
    pub fn new() -> Metadata {
        let context = StaticPolicyContextCache::read_metadata();
        Metadata::from(context.as_ref())
    }
}

impl Default for Metadata {
    fn default() -> Self {
        Metadata::new()
    }
}