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

@@ -5,6 +5,8 @@ use tempfile::TempDir;
use notcore::{HookPhase, HookSpec};
use notfiles::{LinkOptions, link};
use nothooks::{HookResult, HookRunner};
use notsecrets::config::{Provider, SecretsConfig};
use notsecrets::resolver::SecretResolver;
use notsecrets::sources::IdentitySource;
use notsecrets::{FileSource, resolve_identities};
@@ -46,6 +48,24 @@ fn test_nothooks_notsecrets_independent() {
);
}
#[test]
fn secret_resolver_resolves_env_var_cross_crate() {
use std::collections::HashMap;
unsafe { std::env::set_var("NOTFILES_CROSS_CRATE_TEST", "works") };
let config = SecretsConfig {
providers: vec![Provider::Env],
provider: HashMap::new(),
secrets: HashMap::new(),
};
let resolver = SecretResolver::from_config(config).unwrap();
let val = resolver.resolve("NOTFILES_CROSS_CRATE_TEST").unwrap();
assert_eq!(val, Some("works".to_string()));
unsafe { std::env::remove_var("NOTFILES_CROSS_CRATE_TEST") };
}
/// Test that notfiles ignores .notfiles-state.toml and .nothooks-state.toml
/// by default — they must not be symlinked into the target directory and must
/// not appear in the returned State.