use std::{collections::HashMap, path::PathBuf, str::FromStr};
use serde::{Deserialize, Serialize};
use crate::entities::{
logger::{LogConfig, LogLevel, StdioLogMode},
Timelength,
};
use super::{empty_or_redacted, DockerRegistry, GitProvider};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Env {
#[serde(default = "default_config_path")]
pub komodo_config_path: String,
pub komodo_title: Option<String>,
pub komodo_host: Option<String>,
pub komodo_port: Option<u16>,
pub komodo_passkey: Option<String>,
pub komodo_passkey_file: Option<PathBuf>,
pub komodo_first_server: Option<String>,
pub komodo_frontend_path: Option<String>,
pub komodo_jwt_secret: Option<String>,
pub komodo_jwt_secret_file: Option<PathBuf>,
pub komodo_jwt_ttl: Option<Timelength>,
pub komodo_sync_directory: Option<PathBuf>,
pub komodo_repo_directory: Option<PathBuf>,
pub komodo_action_directory: Option<PathBuf>,
pub komodo_resource_poll_interval: Option<Timelength>,
pub komodo_monitoring_interval: Option<Timelength>,
pub komodo_keep_stats_for_days: Option<u64>,
pub komodo_keep_alerts_for_days: Option<u64>,
pub komodo_webhook_secret: Option<String>,
pub komodo_webhook_secret_file: Option<PathBuf>,
pub komodo_webhook_base_url: Option<String>,
pub komodo_logging_level: Option<LogLevel>,
pub komodo_logging_stdio: Option<StdioLogMode>,
pub komodo_logging_otlp_endpoint: Option<String>,
pub komodo_logging_opentelemetry_service_name: Option<String>,
pub komodo_transparent_mode: Option<bool>,
pub komodo_ui_write_disabled: Option<bool>,
pub komodo_enable_new_users: Option<bool>,
pub komodo_disable_user_registration: Option<bool>,
pub komodo_disable_confirm_dialog: Option<bool>,
pub komodo_disable_non_admin_create: Option<bool>,
pub komodo_local_auth: Option<bool>,
pub komodo_oidc_enabled: Option<bool>,
pub komodo_oidc_provider: Option<String>,
pub komodo_oidc_redirect: Option<String>,
pub komodo_oidc_client_id: Option<String>,
pub komodo_oidc_client_id_file: Option<PathBuf>,
pub komodo_oidc_client_secret: Option<String>,
pub komodo_oidc_client_secret_file: Option<PathBuf>,
pub komodo_oidc_use_full_email: Option<bool>,
pub komodo_oidc_additional_audiences: Option<Vec<String>>,
pub komodo_oidc_additional_audiences_file: Option<PathBuf>,
pub komodo_google_oauth_enabled: Option<bool>,
pub komodo_google_oauth_id: Option<String>,
pub komodo_google_oauth_id_file: Option<PathBuf>,
pub komodo_google_oauth_secret: Option<String>,
pub komodo_google_oauth_secret_file: Option<PathBuf>,
pub komodo_github_oauth_enabled: Option<bool>,
pub komodo_github_oauth_id: Option<String>,
pub komodo_github_oauth_id_file: Option<PathBuf>,
pub komodo_github_oauth_secret: Option<String>,
pub komodo_github_oauth_secret_file: Option<PathBuf>,
pub komodo_github_webhook_app_app_id: Option<i64>,
pub komodo_github_webhook_app_app_id_file: Option<PathBuf>,
pub komodo_github_webhook_app_installations_ids: Option<Vec<i64>>,
pub komodo_github_webhook_app_installations_ids_file:
Option<PathBuf>,
pub komodo_github_webhook_app_installations_namespaces:
Option<Vec<String>>,
pub komodo_github_webhook_app_pk_path: Option<String>,
#[serde(alias = "komodo_mongo_uri")]
pub komodo_database_uri: Option<String>,
#[serde(alias = "komodo_mongo_uri_file")]
pub komodo_database_uri_file: Option<PathBuf>,
#[serde(alias = "komodo_mongo_address")]
pub komodo_database_address: Option<String>,
#[serde(alias = "komodo_mongo_username")]
pub komodo_database_username: Option<String>,
#[serde(alias = "komodo_mongo_username_file")]
pub komodo_database_username_file: Option<PathBuf>,
#[serde(alias = "komodo_mongo_password")]
pub komodo_database_password: Option<String>,
#[serde(alias = "komodo_mongo_password_file")]
pub komodo_database_password_file: Option<PathBuf>,
#[serde(alias = "komodo_mongo_app_name")]
pub komodo_database_app_name: Option<String>,
#[serde(alias = "komodo_mongo_db_name")]
pub komodo_database_db_name: Option<String>,
pub komodo_aws_access_key_id: Option<String>,
pub komodo_aws_access_key_id_file: Option<PathBuf>,
pub komodo_aws_secret_access_key: Option<String>,
pub komodo_aws_secret_access_key_file: Option<PathBuf>,
pub komodo_hetzner_token: Option<String>,
pub komodo_hetzner_token_file: Option<PathBuf>,
pub komodo_ssl_enabled: Option<bool>,
pub komodo_ssl_key_file: Option<PathBuf>,
pub komodo_ssl_cert_file: Option<PathBuf>,
}
fn default_config_path() -> String {
"/config/config.toml".to_string()
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoreConfig {
#[serde(default = "default_title")]
pub title: String,
#[serde(default)]
pub host: String,
#[serde(default = "default_core_port")]
pub port: u16,
pub passkey: String,
#[serde(default)]
pub ui_write_disabled: bool,
#[serde(default)]
pub disable_confirm_dialog: bool,
#[serde(default)]
pub first_server: String,
#[serde(default = "default_frontend_path")]
pub frontend_path: String,
#[serde(alias = "mongo")]
pub database: DatabaseConfig,
#[serde(default)]
pub local_auth: bool,
#[serde(default)]
pub transparent_mode: bool,
#[serde(default)]
pub enable_new_users: bool,
#[serde(default)]
pub disable_user_registration: bool,
#[serde(default)]
pub disable_non_admin_create: bool,
#[serde(default)]
pub jwt_secret: String,
#[serde(default = "default_jwt_ttl")]
pub jwt_ttl: Timelength,
#[serde(default)]
pub oidc_enabled: bool,
#[serde(default)]
pub oidc_provider: String,
#[serde(default)]
pub oidc_redirect: String,
#[serde(default)]
pub oidc_client_id: String,
#[serde(default)]
pub oidc_client_secret: String,
#[serde(default)]
pub oidc_use_full_email: bool,
#[serde(default)]
pub oidc_additional_audiences: Vec<String>,
#[serde(default)]
pub google_oauth: OauthCredentials,
#[serde(default)]
pub github_oauth: OauthCredentials,
#[serde(default)]
pub webhook_secret: String,
#[serde(default)]
pub webhook_base_url: String,
#[serde(default)]
pub github_webhook_app: GithubWebhookAppConfig,
#[serde(default)]
pub logging: LogConfig,
#[serde(default = "default_prune_days")]
pub keep_stats_for_days: u64,
#[serde(default = "default_prune_days")]
pub keep_alerts_for_days: u64,
#[serde(default = "default_poll_interval")]
pub resource_poll_interval: Timelength,
#[serde(default = "default_monitoring_interval")]
pub monitoring_interval: Timelength,
#[serde(default)]
pub aws: AwsCredentials,
#[serde(default)]
pub hetzner: HetznerCredentials,
#[serde(default, alias = "git_provider")]
pub git_providers: Vec<GitProvider>,
#[serde(default, alias = "docker_registry")]
pub docker_registries: Vec<DockerRegistry>,
#[serde(default)]
pub secrets: HashMap<String, String>,
#[serde(default)]
pub ssl_enabled: bool,
#[serde(default = "default_ssl_key_file")]
pub ssl_key_file: PathBuf,
#[serde(default = "default_ssl_cert_file")]
pub ssl_cert_file: PathBuf,
#[serde(default = "default_sync_directory")]
pub sync_directory: PathBuf,
#[serde(default = "default_repo_directory")]
pub repo_directory: PathBuf,
#[serde(default = "default_action_directory")]
pub action_directory: PathBuf,
}
fn default_title() -> String {
String::from("Komodo")
}
fn default_core_port() -> u16 {
9120
}
fn default_frontend_path() -> String {
"/app/frontend".to_string()
}
fn default_jwt_ttl() -> Timelength {
Timelength::OneDay
}
fn default_sync_directory() -> PathBuf {
PathBuf::from_str("/syncs").unwrap()
}
fn default_repo_directory() -> PathBuf {
PathBuf::from_str("/repo-cache").unwrap()
}
fn default_action_directory() -> PathBuf {
PathBuf::from_str("/action-cache").unwrap()
}
fn default_prune_days() -> u64 {
14
}
fn default_poll_interval() -> Timelength {
Timelength::FiveMinutes
}
fn default_monitoring_interval() -> Timelength {
Timelength::FifteenSeconds
}
fn default_ssl_key_file() -> PathBuf {
"/config/ssl/key.pem".parse().unwrap()
}
fn default_ssl_cert_file() -> PathBuf {
"/config/ssl/cert.pem".parse().unwrap()
}
impl CoreConfig {
pub fn sanitized(&self) -> CoreConfig {
let config = self.clone();
CoreConfig {
title: config.title,
host: config.host,
port: config.port,
passkey: empty_or_redacted(&config.passkey),
first_server: config.first_server,
frontend_path: config.frontend_path,
jwt_secret: empty_or_redacted(&config.jwt_secret),
jwt_ttl: config.jwt_ttl,
repo_directory: config.repo_directory,
action_directory: config.action_directory,
sync_directory: config.sync_directory,
resource_poll_interval: config.resource_poll_interval,
monitoring_interval: config.monitoring_interval,
keep_stats_for_days: config.keep_stats_for_days,
keep_alerts_for_days: config.keep_alerts_for_days,
logging: config.logging,
transparent_mode: config.transparent_mode,
ui_write_disabled: config.ui_write_disabled,
disable_confirm_dialog: config.disable_confirm_dialog,
enable_new_users: config.enable_new_users,
disable_user_registration: config.disable_user_registration,
disable_non_admin_create: config.disable_non_admin_create,
local_auth: config.local_auth,
oidc_enabled: config.oidc_enabled,
oidc_provider: config.oidc_provider,
oidc_redirect: config.oidc_redirect,
oidc_client_id: empty_or_redacted(&config.oidc_client_id),
oidc_client_secret: empty_or_redacted(
&config.oidc_client_secret,
),
oidc_use_full_email: config.oidc_use_full_email,
oidc_additional_audiences: config
.oidc_additional_audiences
.iter()
.map(|aud| empty_or_redacted(aud))
.collect(),
google_oauth: OauthCredentials {
enabled: config.google_oauth.enabled,
id: empty_or_redacted(&config.google_oauth.id),
secret: empty_or_redacted(&config.google_oauth.id),
},
github_oauth: OauthCredentials {
enabled: config.github_oauth.enabled,
id: empty_or_redacted(&config.github_oauth.id),
secret: empty_or_redacted(&config.github_oauth.id),
},
webhook_secret: empty_or_redacted(&config.webhook_secret),
webhook_base_url: config.webhook_base_url,
github_webhook_app: config.github_webhook_app,
database: DatabaseConfig {
uri: empty_or_redacted(&config.database.uri),
address: config.database.address,
username: empty_or_redacted(&config.database.username),
password: empty_or_redacted(&config.database.password),
app_name: config.database.app_name,
db_name: config.database.db_name,
},
aws: AwsCredentials {
access_key_id: empty_or_redacted(&config.aws.access_key_id),
secret_access_key: empty_or_redacted(
&config.aws.secret_access_key,
),
},
hetzner: HetznerCredentials {
token: empty_or_redacted(&config.hetzner.token),
},
secrets: config
.secrets
.into_iter()
.map(|(id, secret)| (id, empty_or_redacted(&secret)))
.collect(),
git_providers: config
.git_providers
.into_iter()
.map(|mut provider| {
provider.accounts.iter_mut().for_each(|account| {
account.token = empty_or_redacted(&account.token);
});
provider
})
.collect(),
docker_registries: config
.docker_registries
.into_iter()
.map(|mut provider| {
provider.accounts.iter_mut().for_each(|account| {
account.token = empty_or_redacted(&account.token);
});
provider
})
.collect(),
ssl_enabled: config.ssl_enabled,
ssl_key_file: config.ssl_key_file,
ssl_cert_file: config.ssl_cert_file,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OauthCredentials {
#[serde(default)]
pub enabled: bool,
#[serde(default)]
pub id: String,
#[serde(default)]
pub secret: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
#[serde(default)]
pub uri: String,
#[serde(default = "default_database_address")]
pub address: String,
#[serde(default)]
pub username: String,
#[serde(default)]
pub password: String,
#[serde(default = "default_database_app_name")]
pub app_name: String,
#[serde(default = "default_database_db_name")]
pub db_name: String,
}
fn default_database_address() -> String {
String::from("localhost:27017")
}
fn default_database_app_name() -> String {
"komodo_core".to_string()
}
fn default_database_db_name() -> String {
"komodo".to_string()
}
impl Default for DatabaseConfig {
fn default() -> Self {
Self {
uri: Default::default(),
address: default_database_address(),
username: Default::default(),
password: Default::default(),
app_name: default_database_app_name(),
db_name: default_database_db_name(),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AwsCredentials {
pub access_key_id: String,
pub secret_access_key: String,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct HetznerCredentials {
pub token: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GithubWebhookAppConfig {
pub app_id: i64,
pub installations: Vec<GithubWebhookAppInstallationConfig>,
#[serde(default = "default_private_key_path")]
pub pk_path: String,
}
fn default_private_key_path() -> String {
String::from("/github/private-key.pem")
}
impl Default for GithubWebhookAppConfig {
fn default() -> Self {
GithubWebhookAppConfig {
app_id: 0,
installations: Default::default(),
pk_path: default_private_key_path(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GithubWebhookAppInstallationConfig {
pub id: i64,
pub namespace: String,
}