diff --git a/.gitignore b/.gitignore index 4d8e13d2..3d3f43e9 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ nb-configuration.xml secrets.env /docker/dev/docker/ mi6/export +kubernetes/.idea diff --git a/kubernetes/orctl b/kubernetes/orctl new file mode 100755 index 00000000..898a67df --- /dev/null +++ b/kubernetes/orctl @@ -0,0 +1,7 @@ +#!/bin/bash + +if [[ -f ../orctl/target/debug/orctl ]]; then + ../orctl/target/debug/orctl "$@" +else + echo "Please build orctl, consult the README.md in ../orctl" +fi diff --git a/orctl/.gitignore b/orctl/.gitignore new file mode 100644 index 00000000..290f8c57 --- /dev/null +++ b/orctl/.gitignore @@ -0,0 +1,21 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# RustRover +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.idea/ diff --git a/orctl/Cargo.toml b/orctl/Cargo.toml new file mode 100644 index 00000000..3b1960e5 --- /dev/null +++ b/orctl/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "orctl" +version = "0.1.0" +edition = "2021" + +[dependencies] +clap={version="4", features=["derive"]} +serde_yaml={version="0.9.34"} +base64={version="0.22.1"} +colored={version="2.1.0"} +thiserror = "1.0" +dotenv = "0.15.0" diff --git a/orctl/README.md b/orctl/README.md new file mode 100644 index 00000000..e7bfd527 --- /dev/null +++ b/orctl/README.md @@ -0,0 +1,19 @@ +# ORCTL +## Orchestration Control + +### Installation + +- visit https://www.rust-lang.org/tools/install for full instructions + +TL;DR for Linux and macOS + +```shell +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +### Build code + +```shell +cargo build +``` + diff --git a/orctl/src/commands/commands.rs b/orctl/src/commands/commands.rs new file mode 100644 index 00000000..6137c138 --- /dev/null +++ b/orctl/src/commands/commands.rs @@ -0,0 +1,48 @@ +use clap::{Subcommand, ValueEnum}; +use crate::models::secret_files::SecretFiles; + +#[derive(Subcommand)] +pub(crate) enum Commands { + /// get the status of a deployment + Status { + #[arg(short, long)] + pod: bool, + #[arg(short, long)] + svc: bool, + }, + /// get secret values for a deployment + Secrets { + #[command(subcommand)] + command: SecretCommand, + }, +} + +#[derive(Subcommand)] +pub(crate) enum SecretCommand { + /// Decrypt + Decrypt { + /// What secret file to operate on + #[arg(value_enum)] + file: SecretFiles, + }, + /// Encrypt + Encrypt { + /// What secret file to operate on + #[arg(value_enum)] + file: SecretFiles, + + /// What key to operate on + key: String, + + /// If decrypt what value to encode + value: String, + }, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub(crate) enum Operation { + /// Decrypt + Decrypt, + /// Encrypt + Encrypt, +} diff --git a/orctl/src/commands/mod.rs b/orctl/src/commands/mod.rs new file mode 100644 index 00000000..a7e4301b --- /dev/null +++ b/orctl/src/commands/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod commands; +pub(crate) mod status; +pub(crate) mod secrets; diff --git a/orctl/src/commands/secrets.rs b/orctl/src/commands/secrets.rs new file mode 100644 index 00000000..94b3e086 --- /dev/null +++ b/orctl/src/commands/secrets.rs @@ -0,0 +1,51 @@ +use std::io; +use thiserror::Error; +use crate::commands::commands::SecretCommand; +use crate::config::verbosity::Verbosity; +use crate::models::deployment_environment::Environment; + +mod common; +mod decrypt; +mod encrypt; + +#[derive(Error, Debug)] +pub(crate) enum OperateOnSecretsError { + #[error("Failed to decrypt (file {file:?})")] + FailedToDecrypt { file: String, }, + #[error("Failed to decrypt (file {file:?})")] + FailedToEncrypt { file: String, }, + #[error("Failed to convert from utf8 (file {file:?})")] + FailedToConvertFileFromUtf8 { file: String, }, + #[error("Failed to convert file contents to yaml")] + FailedToConvertFileToYaml(), + + #[error("YAML file missing 'data' section")] + MissingDataSection(), + #[error("YAML file missing specified key: {key:?}")] + MissingKeySection { key: String }, + + #[error("File error: {error:?}")] + FileError{ error: io::Error }, + #[error("Writing Yaml error: {error:?}")] + WriteYaml{ error: serde_yaml::Error }, + + #[error("Value missing")] + ValueMissing(), + #[error("Value failed to decode from base64)")] + ValueFailedToDecodeBase64(), + #[error("Value failed to decode from base64 (utf8 step)")] + ValueFailedToDecodeBase64Utf8(), + #[error("Key missing")] + KeyMissing(), +} + +pub(crate) fn operate_on_secrets(commands: &SecretCommand, env: Environment, verbosity: Verbosity) -> Result<(), OperateOnSecretsError> { + match commands { + SecretCommand::Decrypt { file } => { + decrypt::get_secrets(env, verbosity, file) + } + SecretCommand::Encrypt { file, key, value } => { + encrypt::put_secret(env, verbosity, file, key, value) + } + } +} diff --git a/orctl/src/commands/secrets/common.rs b/orctl/src/commands/secrets/common.rs new file mode 100644 index 00000000..8034fb57 --- /dev/null +++ b/orctl/src/commands/secrets/common.rs @@ -0,0 +1,94 @@ +use std::collections::HashMap; +use std::env::VarError; +use std::process::Command; +use std::{env, io}; +use std::io::Write; +use std::string::ToString; +use serde_yaml::Value; +use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; +use base64::Engine; +use crate::commands::secrets::OperateOnSecretsError; +use crate::config::verbosity::Verbosity; +use crate::models::secret_files::SecretFile; + +pub(crate) const AGE_PUBLIC_KEY: &str = "AGE_PUBLIC_KEY"; +const SOPS_AGE_KEY_FILE: &str = "SOPS_AGE_KEY_FILE"; + +pub(crate) fn age_env_vars() -> HashMap { + let mut env_vars: HashMap = HashMap::new(); + env_vars.insert(AGE_PUBLIC_KEY.to_string(), get_env_value(AGE_PUBLIC_KEY)); + env_vars.insert(SOPS_AGE_KEY_FILE.to_string(), get_env_value(SOPS_AGE_KEY_FILE)); + env_vars +} + +pub(crate) fn get_env_value(key: &str) -> String { + match env::var(key) { + Ok(value) => value, + Err(VarError::NotPresent) | Err(VarError::NotUnicode(_)) => { + panic!("Environment Variable {} is missing", key); + }, + } +} + +fn decrypt_file(enc_file_name: String, env_vars: HashMap, verbosity: Verbosity) -> Result { + if verbosity >= Verbosity::TRACE { + println!("decrypting file: {}", enc_file_name.clone()); + } + let output = Command::new("sops") + .arg("--decrypt") + .arg(enc_file_name.clone()) + .envs(&env_vars) + .output() + .expect("failed to execute"); + + if output.status.success() { + let file_contents = std::str::from_utf8(&output.stdout); + if file_contents.is_err() { + return Err(OperateOnSecretsError::FailedToConvertFileFromUtf8 { file: enc_file_name}); + } + + Ok(file_contents.unwrap().to_owned()) + } else { + io::stderr().write_all(&output.stderr).unwrap(); + return Err(OperateOnSecretsError::FailedToDecrypt { file: enc_file_name}); + } +} + +pub(crate) fn decode_row(key: &Value, value: &Value) -> Result<(String, String), OperateOnSecretsError> { + let val_base64 = value.as_str(); + if val_base64.is_none() { return Err(OperateOnSecretsError::ValueMissing()) } + let val_base64 = val_base64.unwrap().to_string(); + + let val_decoded_from_base_64 = + BASE64_STANDARD.decode(val_base64); + if val_decoded_from_base_64.is_err() { return Err(OperateOnSecretsError::ValueFailedToDecodeBase64()) } + let val_decoded_from_base_64 = &val_decoded_from_base_64.unwrap(); + + let val_decoded = std::str::from_utf8(val_decoded_from_base_64); + if val_decoded.is_err() { return Err(OperateOnSecretsError::ValueFailedToDecodeBase64Utf8()) } + let value = val_decoded.unwrap().to_string(); + + let key = key.as_str(); + if key.is_none() { return Err(OperateOnSecretsError::KeyMissing()) } + let key = key.unwrap().to_string(); + + Ok((key, value)) +} + +fn read_yaml(file_contents: String, verbosity: Verbosity) -> Result { + if verbosity >= Verbosity::TRACE { + println!("Reading yaml"); + } + let secret_contents: Result = + serde_yaml::from_str(&*file_contents); + if secret_contents.is_err() { + return Err(OperateOnSecretsError::FailedToConvertFileToYaml()); + } + Ok(secret_contents.unwrap()) +} + +pub(crate) fn get_yaml_contents_from_file(path: &str, file: SecretFile, verbosity: Verbosity) -> Result { + let enc_file_name = format!("{0}{1}{2}", path, file.folder, file.enc_name); + let file_contents = decrypt_file(enc_file_name, age_env_vars(), verbosity)?; + read_yaml(file_contents, verbosity) +} \ No newline at end of file diff --git a/orctl/src/commands/secrets/decrypt.rs b/orctl/src/commands/secrets/decrypt.rs new file mode 100644 index 00000000..7a3a2dfe --- /dev/null +++ b/orctl/src/commands/secrets/decrypt.rs @@ -0,0 +1,45 @@ +use serde_yaml::Value; +use colored::Colorize; +use crate::commands::secrets::{common, OperateOnSecretsError}; +use crate::config::verbosity::Verbosity; +use crate::models::deployment_environment::Environment; +use crate::models::secret_files::{SecretFile, SecretFiles}; + +pub(crate) fn get_secrets(env: Environment, verbosity: Verbosity, file_type: &SecretFiles) -> Result<(), OperateOnSecretsError> { + let file = SecretFile::by_type(file_type); + if verbosity >= Verbosity::INFO { + println!("Secrets op:decrypt, file:{}", file.dec_name); + } + let yaml_content = common::get_yaml_contents_from_file(env.secrets_path, file, verbosity)?; + + if verbosity >= Verbosity::TRACE { + println!("Getting data object"); + } + match yaml_content["data"].as_mapping() { + Some(data) => { + for (key, value) in data.iter() { + print_row(key, value); + } + } + None => { + return Err(OperateOnSecretsError::MissingDataSection()); + } + } + Ok(()) +} + +fn print_row(key: &Value, value: &Value) { + match common::decode_row(key, value) { + Ok((key,value)) => { + println!( + "{}: {}", + key.yellow(), + value.purple(), + ); + }, + Err(error) => { + // catch and continue - attempt to process as much as possible + println!("Error: {}", error); + } + } +} diff --git a/orctl/src/commands/secrets/encrypt.rs b/orctl/src/commands/secrets/encrypt.rs new file mode 100644 index 00000000..201e87f7 --- /dev/null +++ b/orctl/src/commands/secrets/encrypt.rs @@ -0,0 +1,121 @@ +use std::fs::File; +use std::io; +use std::io::Write; +use std::process::Command; +use base64::Engine; +use base64::prelude::BASE64_STANDARD; +use serde_yaml::Value; +use crate::commands::secrets::{common, OperateOnSecretsError}; +use crate::commands::secrets::common::{AGE_PUBLIC_KEY, get_env_value}; +use crate::config::verbosity::Verbosity; +use crate::models::deployment_environment::Environment; +use crate::models::secret_files::{SecretFile, SecretFiles}; + +pub(crate) fn put_secret(env: Environment, verbosity: Verbosity, file_type: &SecretFiles, key_to_find: &String, new_value: &String) -> Result<(), OperateOnSecretsError> { + let file = SecretFile::by_type(file_type); + if verbosity >= Verbosity::INFO { + println!("Secrets op:encrypt, file:{}, key:{}, value:{}", file.dec_name, key_to_find, new_value); + } + let yaml_content = common::get_yaml_contents_from_file(env.secrets_path, file.clone(), verbosity)?; + + if verbosity >= Verbosity::TRACE { + println!("Replacing value"); + } + let yaml_content = replace_key_value(yaml_content, key_to_find, new_value)?; + + let dec_file_name = format!("{0}{1}{2}", env.secrets_path, file.folder, file.dec_name); + let buffer = File::create(dec_file_name.clone()); + match buffer { + Ok(buffer) => { + + if verbosity >= Verbosity::TRACE { + println!("Generating new yaml content"); + } + let res = serde_yaml::to_writer(buffer, &yaml_content); + match res { + Ok(_) => { + if verbosity >= Verbosity::TRACE { + println!("Encrypting yaml content"); + } + let enc_file_name = format!("{0}{1}{2}", env.secrets_path, file.folder, file.enc_name); + let encrypted_contents = encrypt_file(dec_file_name, verbosity)?; + + let buffer = File::create(enc_file_name.clone()); + match buffer { + Ok(mut buffer) => { + if verbosity >= Verbosity::TRACE { + println!("Writing encrypted yaml to file: {}", enc_file_name); + } + let res = buffer.write_all(encrypted_contents.as_ref()); + match res { + Ok(_) => { + if verbosity >= Verbosity::TRACE { + println!("Success"); + } + }, + Err(error) => { + return Err(OperateOnSecretsError::FileError { error: error }); + } + } + }, + Err(error) => { + return Err(OperateOnSecretsError::FileError { error: error }); + } + } + }, + Err(error) => { + return Err(OperateOnSecretsError::WriteYaml { error: error }); + } + } + }, + Err(error) => { + return Err(OperateOnSecretsError::FileError{ error: error }); + } + } + + Ok(()) +} + +fn encrypt_file(dec_file_name: String, verbosity: Verbosity) -> Result { + let age_public_key_arg = format!("--age={}", get_env_value(AGE_PUBLIC_KEY)); + + if verbosity >= Verbosity::TRACE { + println!("encrypting file: {}", dec_file_name.clone()); + } + let output = Command::new("sops") + .arg("--encrypt") + .arg(age_public_key_arg) + .arg("--encrypted-regex") + .arg("^(data|stringData)$") + .arg(dec_file_name.clone()) + .envs(&common::age_env_vars()) + .output() + .expect("failed to execute"); + + if output.status.success() { + let file_contents = std::str::from_utf8(&output.stdout); + if file_contents.is_err() { + return Err(OperateOnSecretsError::FailedToConvertFileFromUtf8 { file: dec_file_name}); + } + + Ok(file_contents.unwrap().to_owned()) + } else { + io::stderr().write_all(&output.stderr).unwrap(); + return Err(OperateOnSecretsError::FailedToEncrypt { file: dec_file_name}); + } +} + +fn replace_key_value(mut yaml_content: Value, key_to_find: &String, new_value: &String) -> Result { + let new_value_base64 = BASE64_STANDARD.encode(new_value); + + *yaml_content + .get_mut("data") + .ok_or(Err::<&mut Value, OperateOnSecretsError>( + OperateOnSecretsError::MissingDataSection() + )).unwrap() + .get_mut(key_to_find) + .ok_or(Err::<&mut Value, OperateOnSecretsError>( + OperateOnSecretsError::MissingKeySection{ key: key_to_find.clone() }) + ).unwrap() = new_value_base64.as_str().into(); + Ok(yaml_content) +} diff --git a/orctl/src/commands/status.rs b/orctl/src/commands/status.rs new file mode 100644 index 00000000..3800da25 --- /dev/null +++ b/orctl/src/commands/status.rs @@ -0,0 +1,49 @@ +use std::process::Command; +use std::str::Utf8Error; +use crate::config::verbosity::Verbosity; +use crate::models::deployment_environment::Environment; + +pub(crate) fn get_status(env: Environment, verbosity: Verbosity, pod: &bool, svc: &bool) -> Result<(), Utf8Error> { + if verbosity >= Verbosity::INFO { + print!("Status of :"); + } + + let mut status_of = "".to_owned(); + if *pod { + if verbosity >= Verbosity::INFO { + print!(" pod"); + } + status_of = "pod".to_owned(); + } + + if *svc { + if verbosity >= Verbosity::INFO { + print!(" svc"); + } + if status_of.len() > 0 { + status_of = status_of.to_owned() + ",svc"; + } else { + status_of = "svc".to_owned(); + } + } + if verbosity >= Verbosity::INFO { + println!(""); + } + + let ssh_cmd_arg = format!("sudo kubectl -n terarium get {} -o wide", status_of); + if verbosity >= Verbosity::INFO { + println!("Status to be fetched {}", ssh_cmd_arg); + } + let output = Command::new("ssh") + .arg(env.ssh_cmd) + .arg(ssh_cmd_arg) + .output() + .expect("failed to execute"); + if output.status.success() { + let output = std::str::from_utf8(&output.stdout)?; + println!("{}", output.to_string()); + } else { + panic!("Error: {}", std::str::from_utf8(&output.stderr)?); + } + return Ok(()); +} \ No newline at end of file diff --git a/orctl/src/config/mod.rs b/orctl/src/config/mod.rs new file mode 100644 index 00000000..252590ca --- /dev/null +++ b/orctl/src/config/mod.rs @@ -0,0 +1 @@ +pub(crate) mod verbosity; \ No newline at end of file diff --git a/orctl/src/config/verbosity.rs b/orctl/src/config/verbosity.rs new file mode 100644 index 00000000..5d36151d --- /dev/null +++ b/orctl/src/config/verbosity.rs @@ -0,0 +1,20 @@ +use clap::ValueEnum; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub(crate) enum Verbosity { + NONE, + INFO, + TRACE, +} + +pub(crate) fn get_verbosity(debug: u8) -> Verbosity { + match debug { + 0 => Verbosity::NONE, + 1 => Verbosity::INFO, + 2 => Verbosity::TRACE, + _ => { + println!("Don't be crazy"); + Verbosity::TRACE + } + } +} diff --git a/orctl/src/main.rs b/orctl/src/main.rs new file mode 100644 index 00000000..660d2df2 --- /dev/null +++ b/orctl/src/main.rs @@ -0,0 +1,54 @@ +use std::error::Error; +use clap::Parser; +use dotenv::dotenv; + +use crate::commands::commands::Commands; +use crate::commands::status::get_status; +use crate::commands::secrets::operate_on_secrets; +use crate::config::verbosity::get_verbosity; +use crate::models::deployment_environment::get_deployment_environment; +use crate::models::deployment_environment::{Environment, DeploymentEnvironments}; + +mod models; +mod commands; +mod config; + +#[derive(Parser)] +#[command(version, name = "Orchestration Control", about = "Various useful tasks.")] +struct Cli { + /// Turn debugging information on + #[arg(short, long, action = clap::ArgAction::Count)] + verbose: u8, + + /// What environment to run against + #[arg(value_enum)] + env: DeploymentEnvironments, + + #[command(subcommand)] + command: Option, +} + +fn main() -> Result<(), Box> { + dotenv().ok(); + let cli = Cli::parse(); + + let verbosity = get_verbosity(cli.verbose); + let env = get_deployment_environment(cli.env); + + match &cli.command { + Some(Commands::Status { pod, svc }) => { + get_status(env, verbosity, pod, svc)? + }, + Some(Commands::Secrets { command }) => { + operate_on_secrets(command, env, verbosity)? + }, + // Some(Commands::Secrets { operation, file, key, value }) => { + // operate_on_secrets(env, env_vars, verbosity, operation, file, key, value)? + // }, + None => { + panic!("Missing Command."); + } + }; + Ok(()) +} + diff --git a/orctl/src/models/deployment_environment.rs b/orctl/src/models/deployment_environment.rs new file mode 100644 index 00000000..1b7330fb --- /dev/null +++ b/orctl/src/models/deployment_environment.rs @@ -0,0 +1,37 @@ +use clap::ValueEnum; + +pub(crate) struct Environment<'a> { + pub ssh_cmd: &'a str, + pub secrets_path: &'a str, +} + +const PRODUCTION: Environment<'static> = crate::Environment { + ssh_cmd: "uncharted-askem-prod-askem-prod-kube-manager-3", + secrets_path: "overlays/prod/overlays/askem-production/", +}; +const STAGING: Environment<'static> = crate::Environment { + ssh_cmd: "uncharted-askem-prod-askem-staging-kube-manager-3", + secrets_path: "overlays/prod/overlays/askem-staging/", +}; +const DEV: Environment<'static> = crate::Environment { + ssh_cmd: "askem-dev-kube-manager-3", + secrets_path: "overlays/prod/overlays/askem-dev/", +}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub(crate) enum DeploymentEnvironments { + /// Production + Production, + /// Staging + Staging, + /// Dev + Dev, +} + +pub(crate) fn get_deployment_environment(env: DeploymentEnvironments) -> Environment<'static> { + match env { + DeploymentEnvironments::Production => PRODUCTION, + DeploymentEnvironments::Staging => STAGING, + DeploymentEnvironments::Dev => DEV, + } +} diff --git a/orctl/src/models/mod.rs b/orctl/src/models/mod.rs new file mode 100644 index 00000000..4e4886da --- /dev/null +++ b/orctl/src/models/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod deployment_environment; +pub(crate) mod secret_files; diff --git a/orctl/src/models/secret_files.rs b/orctl/src/models/secret_files.rs new file mode 100644 index 00000000..f9c917f7 --- /dev/null +++ b/orctl/src/models/secret_files.rs @@ -0,0 +1,132 @@ +use clap::ValueEnum; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub(crate) enum SecretFiles { + /// DKG + Dkg, + /// BEAKER + Beaker, + /// ES + Es, + /// ADOBE + Adobe, + /// S3 + S3, + /// RDS + Rds, + /// LOGGING + Logging, + /// MQ + Mq, + /// CHATGPT + Chatgpt, + /// SPICEDB + Spicedb, + /// XDD + Xdd, + /// KEYCLOAK + Keycloak, + /// NEO4J + Neo4j, + /// CHECK-LATEST + CheckLatest +} + +#[derive(Debug, Clone, Copy)] +pub(crate) struct SecretFile<'a> { + pub(crate) enc_name: &'a str, + pub(crate) dec_name: &'a str, + pub(crate) folder: &'a str, +} + +impl<'a> SecretFile<'a> { + pub(crate) fn by_type(file: &SecretFiles) -> SecretFile { + match file { + SecretFiles::Dkg => DKG, + SecretFiles::Beaker => BEAKER, + SecretFiles::Es => ES, + SecretFiles::Adobe => ADOBE, + SecretFiles::S3 => S3, + SecretFiles::Rds => RDS, + SecretFiles::Logging => LOGGING, + SecretFiles::Mq => MQ, + SecretFiles::Chatgpt => CHATGPT, + SecretFiles::Spicedb => SPICEDB, + SecretFiles::Xdd => XDD, + SecretFiles::Keycloak => KEYCLOAK, + SecretFiles::Neo4j => NEO4J, + SecretFiles::CheckLatest => CHECK_LATEST, + } + } +} + +pub(crate) const DKG: SecretFile<'static> = SecretFile { + enc_name: "secrets-dkg.enc.yaml", + dec_name: "secrets-dkg.yaml", + folder: "secrets/", +}; +pub(crate) const BEAKER: SecretFile<'static> = SecretFile { + enc_name: "secrets-beaker-creds.enc.yaml", + dec_name: "secrets-beaker-creds.yaml", + folder: "secrets/", +}; +pub(crate) const ES: SecretFile<'static> = SecretFile { + enc_name: "secrets-es-creds.enc.yaml", + dec_name: "secrets-es-creds.yaml", + folder: "secrets/", +}; +pub(crate) const ADOBE: SecretFile<'static> = SecretFile { + enc_name: "secrets-adobe-api-key.enc.yaml", + dec_name: "secrets-adobe-api-key.yaml", + folder: "secrets/", +}; +pub(crate) const S3: SecretFile<'static> = SecretFile { + enc_name: "secrets-data-service-s3.enc.yaml", + dec_name: "secrets-data-service-s3.yaml", + folder: "secrets/", +}; +pub(crate) const RDS: SecretFile<'static> = SecretFile { + enc_name: "secrets-rds-creds.enc.yaml", + dec_name: "secrets-rds-creds.yaml", + folder: "secrets/", +}; +pub(crate) const LOGGING: SecretFile<'static> = SecretFile { + enc_name: "secrets-logging-creds.enc.yaml", + dec_name: "secrets-logging-creds.yaml", + folder: "secrets/", +}; +pub(crate) const MQ: SecretFile<'static> = SecretFile { + enc_name: "secrets-mq-creds.enc.yaml", + dec_name: "secrets-mq-creds.yaml", + folder: "secrets/", +}; +pub(crate) const CHATGPT: SecretFile<'static> = SecretFile { + enc_name: "secrets-chatgpt.enc.yaml", + dec_name: "secrets-chatgpt.yaml", + folder: "secrets/", +}; +pub(crate) const SPICEDB: SecretFile<'static> = SecretFile { + enc_name: "secrets-spicedb-shared.enc.yaml", + dec_name: "secrets-spicedb-shared.yaml", + folder: "secrets/", +}; +pub(crate) const XDD: SecretFile<'static> = SecretFile { + enc_name: "secrets-xdd-api-key.enc.yaml", + dec_name: "secrets-xdd-api-key.yaml", + folder: "secrets/", +}; +pub(crate) const KEYCLOAK: SecretFile<'static> = SecretFile { + enc_name: "secrets-keycloak-creds.enc.yaml", + dec_name: "secrets-keycloak-creds.yaml", + folder: "secrets/", +}; +pub(crate) const NEO4J: SecretFile<'static> = SecretFile { + enc_name: "secrets-neo4j-auth.enc.yaml", + dec_name: "secrets-neo4j-auth.yaml", + folder: "secrets/", +}; +pub(crate) const CHECK_LATEST: SecretFile<'static> = SecretFile { + enc_name: "secrets.enc.yaml", + dec_name: "secrets.yaml", + folder: "check-latest/" +};