Skip to main content

soma_openapi/
config.rs

1use std::path::PathBuf;
2
3pub const RESERVED_NAMESPACES: [&str; 3] = ["state", "git", "openapi"];
4
5#[derive(Clone)]
6pub enum SpecSource {
7    Url(url::Url),
8    Path(PathBuf),
9}
10
11impl std::fmt::Debug for SpecSource {
12    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13        match self {
14            Self::Url(url) => f
15                .debug_tuple("Url")
16                .field(&crate::ssrf::redact_url(url.as_str()))
17                .finish(),
18            Self::Path(path) => f.debug_tuple("Path").field(path).finish(),
19        }
20    }
21}
22
23#[derive(Clone)]
24pub enum OpenApiCredential {
25    ApiKey { header: String, value: String },
26    BearerToken(String),
27}
28
29impl OpenApiCredential {
30    #[must_use]
31    pub fn api_key(header: impl Into<String>, value: impl Into<String>) -> Self {
32        Self::ApiKey {
33            header: header.into(),
34            value: value.into(),
35        }
36    }
37
38    #[must_use]
39    pub fn bearer_token(value: impl Into<String>) -> Self {
40        Self::BearerToken(value.into())
41    }
42}
43
44impl std::fmt::Debug for OpenApiCredential {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        match self {
47            Self::ApiKey { header, .. } => f
48                .debug_struct("ApiKey")
49                .field("header", header)
50                .field("value", &"<redacted>")
51                .finish(),
52            Self::BearerToken(_) => f.debug_tuple("BearerToken").field(&"<redacted>").finish(),
53        }
54    }
55}
56
57impl serde::Serialize for OpenApiCredential {
58    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
59    where
60        S: serde::Serializer,
61    {
62        use serde::ser::SerializeMap;
63
64        match self {
65            Self::ApiKey { header, .. } => {
66                let mut map = serializer.serialize_map(Some(3))?;
67                map.serialize_entry("type", "api_key")?;
68                map.serialize_entry("header", header)?;
69                map.serialize_entry("value", "<redacted>")?;
70                map.end()
71            }
72            Self::BearerToken(_) => {
73                let mut map = serializer.serialize_map(Some(2))?;
74                map.serialize_entry("type", "bearer_token")?;
75                map.serialize_entry("value", "<redacted>")?;
76                map.end()
77            }
78        }
79    }
80}
81
82#[derive(Debug, Clone)]
83pub struct OpenApiSpecConfig {
84    pub label: String,
85    pub spec_source: SpecSource,
86    pub base_url: url::Url,
87    pub allowed_operations: Vec<String>,
88    pub credential: Option<OpenApiCredential>,
89}
90
91impl OpenApiSpecConfig {
92    #[must_use]
93    pub fn is_reserved_label(&self) -> bool {
94        RESERVED_NAMESPACES.contains(&self.label.as_str())
95    }
96}
97
98#[derive(Debug, Clone, Default)]
99pub struct OpenApiConfig {
100    pub specs: Vec<OpenApiSpecConfig>,
101}
102
103impl OpenApiConfig {
104    #[must_use]
105    pub fn empty() -> Self {
106        Self { specs: Vec::new() }
107    }
108}