systemprompt_config/bootstrap/
mod.rs1use std::marker::PhantomData;
8use std::path::Path;
9
10use crate::error::ConfigResult;
11
12mod manifest;
13mod profile;
14mod secrets;
15
16pub use manifest::{MANIFEST_SIGNING_SEED_BYTES, decode_seed, generate_seed, persist_seed};
17pub use profile::{ProfileBootstrap, ProfileBootstrapError};
18pub use secrets::{
19 JWT_SECRET_MIN_LENGTH, SecretsBootstrap, SecretsBootstrapError, build_loaded_secrets_message,
20 load_secrets_from_path, log_secrets_issue, log_secrets_skip, log_secrets_warn,
21};
22
23pub trait BootstrapState {}
24
25#[derive(Debug, Clone, Copy)]
26pub struct Uninitialized;
27impl BootstrapState for Uninitialized {}
28
29#[derive(Debug, Clone, Copy)]
30pub struct ProfileInitialized;
31impl BootstrapState for ProfileInitialized {}
32
33#[derive(Debug, Clone, Copy)]
34pub struct SecretsInitialized;
35impl BootstrapState for SecretsInitialized {}
36
37#[derive(Debug)]
38pub struct BootstrapSequence<S: BootstrapState> {
39 _state: PhantomData<S>,
40}
41
42impl Default for BootstrapSequence<Uninitialized> {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl BootstrapSequence<Uninitialized> {
49 #[must_use]
50 pub const fn new() -> Self {
51 Self {
52 _state: PhantomData,
53 }
54 }
55
56 pub fn with_profile(self, path: &Path) -> ConfigResult<BootstrapSequence<ProfileInitialized>> {
57 let Self { _state: _ } = self;
58 ProfileBootstrap::init_from_path(path)?;
59
60 Ok(BootstrapSequence {
61 _state: PhantomData,
62 })
63 }
64
65 #[must_use]
66 pub const fn skip_profile(self) -> Self {
67 self
68 }
69}
70
71impl BootstrapSequence<ProfileInitialized> {
72 pub fn with_secrets(self) -> ConfigResult<BootstrapSequence<SecretsInitialized>> {
73 let Self { _state: _ } = self;
74 SecretsBootstrap::init()?;
75
76 Ok(BootstrapSequence {
77 _state: PhantomData,
78 })
79 }
80
81 #[must_use]
82 pub const fn skip_secrets(self) -> Self {
83 self
84 }
85}
86
87impl BootstrapSequence<SecretsInitialized> {
88 #[must_use]
89 pub const fn complete(self) -> BootstrapComplete {
90 let Self { _state: _ } = self;
91 BootstrapComplete { _private: () }
92 }
93}
94
95#[derive(Debug, Clone, Copy)]
96pub struct BootstrapComplete {
97 _private: (),
98}
99
100pub mod presets {
101 use std::path::Path;
102
103 use super::{BootstrapSequence, ProfileInitialized, SecretsInitialized, Uninitialized};
104 use crate::error::ConfigResult;
105
106 pub fn profile_and_secrets(
107 profile_path: &Path,
108 ) -> ConfigResult<BootstrapSequence<SecretsInitialized>> {
109 BootstrapSequence::<Uninitialized>::new()
110 .with_profile(profile_path)?
111 .with_secrets()
112 }
113
114 pub fn profile_only(
115 profile_path: &Path,
116 ) -> ConfigResult<BootstrapSequence<ProfileInitialized>> {
117 BootstrapSequence::<Uninitialized>::new().with_profile(profile_path)
118 }
119}