Skip to content
This repository was archived by the owner on Feb 6, 2026. It is now read-only.

Commit c652fb0

Browse files
committed
WIP: claude refactor
Signed-off-by: Nick Gerace <nick@systeminit.com>
1 parent 7e12d61 commit c652fb0

File tree

12 files changed

+219
-177
lines changed

12 files changed

+219
-177
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/innit-server/BUCK

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ rust_library(
1111
"//lib/si-std:si-std",
1212
"//lib/si-tls:si-tls",
1313
"//lib/telemetry-rs:telemetry",
14+
"//third-party/rust:async-trait",
15+
"//third-party/rust:aws-sdk-ssm",
1416
"//third-party/rust:axum",
1517
"//third-party/rust:dashmap",
1618
"//third-party/rust:derive_builder",

lib/innit-server/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ rust-version.workspace = true
99
publish.workspace = true
1010

1111
[dependencies]
12+
async-trait = { workspace = true }
13+
aws-sdk-ssm = { workspace = true }
1214
axum = { workspace = true }
1315
buck2-resources = { path = "../../lib/buck2-resources" }
1416
dashmap = { workspace = true }

lib/innit-server/src/app_state.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use axum::extract::FromRef;
2-
use si_data_ssm::ParameterStorageBackend;
32
use tokio_util::sync::CancellationToken;
43

5-
use crate::parameter_cache::ParameterCache;
4+
use crate::{
5+
parameter_cache::ParameterCache,
6+
parameter_storage::ParameterStorageBackend,
7+
};
68

79
#[remain::sorted]
810
#[derive(Debug, Eq, PartialEq)]

lib/innit-server/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod app_state;
33
mod config;
44
mod middleware;
55
mod parameter_cache;
6+
mod parameter_storage;
67
mod routes;
78
mod server;
89

@@ -15,5 +16,11 @@ pub use self::{
1516
StandardConfigFile,
1617
detect_and_configure_development,
1718
},
19+
parameter_storage::{
20+
EnvParameterStorage,
21+
ParameterStorage,
22+
ParameterStorageBackend,
23+
ParameterStorageError,
24+
},
1825
server::Server,
1926
};
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
use aws_sdk_ssm::types::{Parameter, ParameterType};
2+
use si_data_ssm::{ParameterStoreClient, ParameterStoreClientError};
3+
use telemetry::prelude::*;
4+
use thiserror::Error;
5+
6+
#[remain::sorted]
7+
#[derive(Debug, Error)]
8+
pub enum ParameterStorageError {
9+
#[error("Parameter path invalid, must start with /: {0}")]
10+
InvalidPath(String),
11+
#[error("Parameter not found: {0}")]
12+
ParameterNotFound(String),
13+
#[error("Parameter store client error: {0}")]
14+
ParameterStoreClient(#[from] ParameterStoreClientError),
15+
#[error("Parameter path not found: {0}")]
16+
PathNotFound(String),
17+
#[error("Write operations not supported in environment variable mode")]
18+
WriteNotSupported,
19+
}
20+
21+
pub type ParameterStorageResult<T> = Result<T, ParameterStorageError>;
22+
23+
/// Trait for abstracting parameter storage backends
24+
#[async_trait::async_trait]
25+
pub trait ParameterStorage: std::fmt::Debug + Send + Sync {
26+
/// Gets a specific parameter by name
27+
async fn get_parameter(&self, name: String) -> ParameterStorageResult<Parameter>;
28+
29+
/// Gets all parameters under a path
30+
async fn parameters_by_path(&self, path: String) -> ParameterStorageResult<Vec<Parameter>>;
31+
32+
/// Creates or updates a string parameter
33+
async fn create_string_parameter(
34+
&self,
35+
name: String,
36+
value: String,
37+
) -> ParameterStorageResult<()>;
38+
}
39+
40+
/// Environment variable-based parameter storage
41+
#[derive(Debug, Clone)]
42+
pub struct EnvParameterStorage;
43+
44+
impl EnvParameterStorage {
45+
/// Creates a new environment parameter storage
46+
pub fn new() -> Self {
47+
Self
48+
}
49+
50+
/// Converts a parameter path to an environment variable name
51+
/// Example: `/si/prod/database/password` -> `SI_PROD_DATABASE_PASSWORD`
52+
fn path_to_env_var(path: &str) -> String {
53+
path.trim_start_matches('/')
54+
.replace('/', "_")
55+
.to_uppercase()
56+
}
57+
58+
/// Checks if an environment variable key matches a path prefix
59+
fn env_var_matches_path(env_key: &str, path: &str) -> bool {
60+
let normalized = Self::path_to_env_var(path);
61+
// Match exact or with underscore separator to avoid false matches
62+
// e.g., SI_PROD matches SI_PROD_DB but not SI_PRODUCTION
63+
env_key == normalized || env_key.starts_with(&format!("{}_", normalized))
64+
}
65+
66+
/// Converts an environment variable name back to a parameter path
67+
/// Example: `SI_PROD_DATABASE_PASSWORD` -> `/si/prod/database/password`
68+
fn env_var_to_path(env_var: &str) -> String {
69+
format!("/{}", env_var.replace('_', "/").to_lowercase())
70+
}
71+
}
72+
73+
/// Implementation of ParameterStorage for EnvParameterStorage (environment variable backend)
74+
#[async_trait::async_trait]
75+
impl ParameterStorage for EnvParameterStorage {
76+
async fn get_parameter(&self, name: String) -> ParameterStorageResult<Parameter> {
77+
let env_var = Self::path_to_env_var(&name);
78+
79+
#[allow(clippy::disallowed_methods)]
80+
let value = std::env::var(&env_var)
81+
.map_err(|_| ParameterStorageError::ParameterNotFound(name.clone()))?;
82+
83+
Ok(Parameter::builder()
84+
.name(name)
85+
.value(value)
86+
.r#type(ParameterType::String)
87+
.build())
88+
}
89+
90+
async fn parameters_by_path(&self, path: String) -> ParameterStorageResult<Vec<Parameter>> {
91+
if !path.starts_with("/") {
92+
return Err(ParameterStorageError::InvalidPath(path));
93+
}
94+
95+
let mut parameters = Vec::new();
96+
97+
#[allow(clippy::disallowed_methods)]
98+
for (key, value) in std::env::vars() {
99+
if Self::env_var_matches_path(&key, &path) {
100+
let param_name = Self::env_var_to_path(&key);
101+
parameters.push(
102+
Parameter::builder()
103+
.name(param_name)
104+
.value(value)
105+
.r#type(ParameterType::String)
106+
.build(),
107+
);
108+
}
109+
}
110+
111+
if parameters.is_empty() {
112+
return Err(ParameterStorageError::PathNotFound(path));
113+
}
114+
115+
Ok(parameters)
116+
}
117+
118+
async fn create_string_parameter(
119+
&self,
120+
_name: String,
121+
_value: String,
122+
) -> ParameterStorageResult<()> {
123+
Err(ParameterStorageError::WriteNotSupported)
124+
}
125+
}
126+
127+
/// Implementation of ParameterStorage for ParameterStoreClient (AWS SSM backend)
128+
#[async_trait::async_trait]
129+
impl ParameterStorage for ParameterStoreClient {
130+
async fn get_parameter(&self, name: String) -> ParameterStorageResult<Parameter> {
131+
self.get_parameter(name).await.map_err(Into::into)
132+
}
133+
134+
async fn parameters_by_path(&self, path: String) -> ParameterStorageResult<Vec<Parameter>> {
135+
self.parameters_by_path(path).await.map_err(Into::into)
136+
}
137+
138+
async fn create_string_parameter(
139+
&self,
140+
name: String,
141+
value: String,
142+
) -> ParameterStorageResult<()> {
143+
self.create_string_parameter(name, value)
144+
.await
145+
.map_err(Into::into)
146+
}
147+
}
148+
149+
/// Enum wrapper for different parameter storage backends
150+
#[remain::sorted]
151+
#[derive(Debug, Clone)]
152+
pub enum ParameterStorageBackend {
153+
/// Environment variable backend
154+
Env(EnvParameterStorage),
155+
/// AWS SSM Parameter Store backend
156+
Ssm(ParameterStoreClient),
157+
}
158+
159+
/// Implementation of ParameterStorage for ParameterStorageBackend (delegates to inner backend)
160+
#[async_trait::async_trait]
161+
impl ParameterStorage for ParameterStorageBackend {
162+
async fn get_parameter(&self, name: String) -> ParameterStorageResult<Parameter> {
163+
match self {
164+
Self::Env(storage) => storage.get_parameter(name).await,
165+
Self::Ssm(client) => <ParameterStoreClient as ParameterStorage>::get_parameter(client, name).await,
166+
}
167+
}
168+
169+
async fn parameters_by_path(&self, path: String) -> ParameterStorageResult<Vec<Parameter>> {
170+
match self {
171+
Self::Env(storage) => storage.parameters_by_path(path).await,
172+
Self::Ssm(client) => <ParameterStoreClient as ParameterStorage>::parameters_by_path(client, path).await,
173+
}
174+
}
175+
176+
async fn create_string_parameter(
177+
&self,
178+
name: String,
179+
value: String,
180+
) -> ParameterStorageResult<()> {
181+
match self {
182+
Self::Env(storage) => storage.create_string_parameter(name, value).await,
183+
Self::Ssm(client) => <ParameterStoreClient as ParameterStorage>::create_string_parameter(client, name, value).await,
184+
}
185+
}
186+
}

lib/innit-server/src/routes.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use serde_json::{
1616
Value,
1717
json,
1818
};
19-
use si_data_ssm::ParameterStoreClientError;
2019
use thiserror::Error;
2120

2221
mod clear_cache;
@@ -28,7 +27,10 @@ use super::{
2827
app_state::AppState,
2928
server::ServerError,
3029
};
31-
use crate::api_error::ApiError;
30+
use crate::{
31+
api_error::ApiError,
32+
parameter_storage::ParameterStorageError,
33+
};
3234

3335
pub fn public_routes(state: AppState) -> Router {
3436
Router::new()
@@ -59,8 +61,8 @@ async fn system_status_route() -> Json<Value> {
5961
#[remain::sorted]
6062
#[derive(Debug, Error)]
6163
pub enum AppError {
62-
#[error("parameter store client error: {0}")]
63-
ParameterStoreClient(#[from] ParameterStoreClientError),
64+
#[error("parameter storage error: {0}")]
65+
ParameterStorage(#[from] ParameterStorageError),
6466
#[error("server error: {0}")]
6567
Server(#[from] ServerError),
6668
}

lib/innit-server/src/routes/create_parameter.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ use innit_core::{
1010
CreateParameterResponse,
1111
Parameter,
1212
};
13-
use si_data_ssm::ParameterStorage;
1413
use telemetry::tracing::info;
1514

1615
use super::AppError;
17-
use crate::app_state::AppState;
16+
use crate::{
17+
app_state::AppState,
18+
parameter_storage::ParameterStorage,
19+
};
1820

1921
pub async fn create_parameter_route(
2022
Path(name): Path<String>,

lib/innit-server/src/routes/get_parameter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ use innit_core::{
66
GetParameterResponse,
77
Parameter,
88
};
9-
use si_data_ssm::ParameterStorage;
109
use telemetry::tracing::info;
1110

1211
use super::AppError;
1312
use crate::{
1413
app_state::AppState,
14+
parameter_storage::ParameterStorage,
1515
routes::Json,
1616
};
1717

lib/innit-server/src/routes/list_parameters.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ use innit_core::{
66
ListParametersResponse,
77
Parameter,
88
};
9-
use si_data_ssm::ParameterStorage;
109
use telemetry::tracing::info;
1110

1211
use super::AppError;
1312
use crate::{
1413
app_state::AppState,
14+
parameter_storage::ParameterStorage,
1515
routes::Json,
1616
};
1717

0 commit comments

Comments
 (0)