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.
- Create FileStore trait in crates/notfiles/src/ports.rs capturing all file I/O
operations (read, write, rename, remove, metadata, symlink, etc.)
- Create FileStoreImpl adapter in crates/notfiles/src/adapters/fs.rs wrapping std::fs
- Update linker.rs State::load/save and link_package/unlink_package to accept
FileStore parameter for dependency injection
- Create IdentitySource port in crates/notsecrets/src/ports.rs
- Move IdentitySource trait from sources/mod.rs to ports.rs, maintain backward
compatibility via re-export
- Update all source implementations to import from ports
- Update lib.rs in both crates to re-export ports
- Pass FileStoreImpl through call chain in main.rs and lib.rs public API
Maintains 100% backward compatible public API; FileStore dependency is internal.
- Replace AgeKeySource+retrieve() with IdentitySource+load() returning Box<dyn Identity>
- Rewrite bitwarden/file/prompt sources to implement new trait
- Add resolve_identities() public API with partial-success semantics
- Delete _legacy.rs and remove legacy re-exports from lib.rs
- Update integration tests to use new API
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>