use std::marker::PhantomData;
use std::path::Path;
use anyhow::{Context, Result};
mod manifest;
mod profile;
mod secrets;
pub use manifest::{MANIFEST_SIGNING_SEED_BYTES, decode_seed, generate_seed, persist_seed};
pub use profile::{ProfileBootstrap, ProfileBootstrapError};
pub use secrets::{
JWT_SECRET_MIN_LENGTH, SecretsBootstrap, SecretsBootstrapError, build_loaded_secrets_message,
load_secrets_from_path, log_secrets_issue, log_secrets_skip, log_secrets_warn,
};
pub trait BootstrapState {}
#[derive(Debug, Clone, Copy)]
pub struct Uninitialized;
impl BootstrapState for Uninitialized {}
#[derive(Debug, Clone, Copy)]
pub struct ProfileInitialized;
impl BootstrapState for ProfileInitialized {}
#[derive(Debug, Clone, Copy)]
pub struct SecretsInitialized;
impl BootstrapState for SecretsInitialized {}
#[derive(Debug)]
pub struct BootstrapSequence<S: BootstrapState> {
_state: PhantomData<S>,
}
impl Default for BootstrapSequence<Uninitialized> {
fn default() -> Self {
Self::new()
}
}
impl BootstrapSequence<Uninitialized> {
#[must_use]
pub const fn new() -> Self {
Self {
_state: PhantomData,
}
}
pub fn with_profile(self, path: &Path) -> Result<BootstrapSequence<ProfileInitialized>> {
let Self { _state: _ } = self;
ProfileBootstrap::init_from_path(path)
.with_context(|| format!("Profile initialization failed from: {}", path.display()))?;
Ok(BootstrapSequence {
_state: PhantomData,
})
}
#[must_use]
pub const fn skip_profile(self) -> Self {
self
}
}
impl BootstrapSequence<ProfileInitialized> {
pub fn with_secrets(self) -> Result<BootstrapSequence<SecretsInitialized>> {
let Self { _state: _ } = self;
SecretsBootstrap::init().context("Secrets initialization failed")?;
Ok(BootstrapSequence {
_state: PhantomData,
})
}
#[must_use]
pub const fn skip_secrets(self) -> Self {
self
}
}
impl BootstrapSequence<SecretsInitialized> {
#[must_use]
pub const fn complete(self) -> BootstrapComplete {
let Self { _state: _ } = self;
BootstrapComplete { _private: () }
}
}
#[derive(Debug, Clone, Copy)]
pub struct BootstrapComplete {
_private: (),
}
pub mod presets {
use std::path::Path;
use anyhow::Result;
use super::{BootstrapSequence, ProfileInitialized, SecretsInitialized, Uninitialized};
pub fn profile_and_secrets(
profile_path: &Path,
) -> Result<BootstrapSequence<SecretsInitialized>> {
BootstrapSequence::<Uninitialized>::new()
.with_profile(profile_path)?
.with_secrets()
}
pub fn profile_only(profile_path: &Path) -> Result<BootstrapSequence<ProfileInitialized>> {
BootstrapSequence::<Uninitialized>::new().with_profile(profile_path)
}
}