feat(notsecrets): add multi-provider secret resolution system
Some checks failed
Public Repo Readiness / Check Public Repo Readiness (push) Has been cancelled

Add a config-driven, strongly-typed secret/env resolution system to
notsecrets with 11 provider backends. The system supports explicit
key bindings with typed SecretRef enums and a priority chain fallback.

Tier 1 providers (implemented): Env, 1Password, dotenvx, SOPS, GSM
Tier 2 providers (stubbed): nuenv, direnv, mise, Bitwarden, Vault, dotenvy

New types: Provider, ProviderConfig, SecretRef, SecretsConfig,
SecretsError, SecretSource, EnumerableSecretSource, SecretResolver

Config lives in notsecrets.toml with typed serde deserialization.
ISP split: EnumerableSecretSource for backends that support bulk
enumeration, SecretSource for single-key lookup only.

Includes conformance test suite, 33 new tests (161 workspace total).
notstrap EnvInjector migration deferred to follow-up.
This commit is contained in:
2026-06-06 09:49:05 -04:00
parent 65d1a2dc2e
commit 1359def673
27 changed files with 3079 additions and 39 deletions

View File

@@ -13,3 +13,42 @@ pub enum AgeError {
#[error("identity source failed ({name}): {source}")]
SourceError { name: String, source: anyhow::Error },
}
#[derive(Debug, thiserror::Error)]
pub enum SecretsError {
#[error("[{name}] {source}")]
SourceError { name: String, source: anyhow::Error },
#[error("no provider resolved key: {key}")]
NotFound { key: String },
#[error("config error: {0}")]
Config(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn secrets_error_display_source_error() {
let err = SecretsError::SourceError {
name: "op".to_string(),
source: anyhow::anyhow!("not found"),
};
assert!(err.to_string().contains("[op]"));
assert!(err.to_string().contains("not found"));
}
#[test]
fn secrets_error_display_not_found() {
let err = SecretsError::NotFound {
key: "DB_URL".to_string(),
};
assert!(err.to_string().contains("DB_URL"));
}
#[test]
fn secrets_error_display_config() {
let err = SecretsError::Config("bad toml".to_string());
assert!(err.to_string().contains("bad toml"));
}
}