When commiting changes related to Rust, make sure to update /CHANGELOG.md with one entry (can be multi-line). Don't create new release subsections; add the entry under the existing unreleased section. Keep entries user facing: leave out development and testing notes.
The documentation site is published from main, which may be ahead of the
latest SecretSpec release. Any unreleased provider, CLI command, configuration
field, or syntax must be labeled with its target version at each point of use.
Do not rely on an Unreleased changelog entry or a notice on one concept page:
users often land directly on provider and reference pages.
For an upcoming provider or feature:
- Add what version the provider was added in (to be released version)
- Mark entries in provider lists, tables, sidebars, selector examples, landing
pages, README files, and generated documentation summaries with the minimum
version, for example
(0.15+).
SecretSpec is a declarative secrets manager for development workflows written in Rust. It provides a CLI tool and Rust library for managing environment variables and secrets across different environments using multiple storage backends (keyring, dotenv, environment variables, OnePassword, LastPass).
# Enter development environment
devenv shell
# Run tests
cargo test --all
# Run a single test
cargo test test_name
# Run the CLI
cargo run -- <command>
cargo run -- init --from .env
cargo run -- check
cargo run -- set DATABASE_URL
cargo run -- run -- npm start
# Format code / Run linter
pre-commit run -aThe project is organized as a Rust workspace with two crates:
-
secretspec (src/): Main CLI and library
bin/secretspec.rs: CLI entry point that calls the main CLI modulecli/mod.rs: CLI command definitions (init, config, set/get, check, run, import)lib.rs: Core library withSecretsstruct, validation logic, and CRUD operationsconfig.rs: Core configuration types (Config, Secret), TOML parsing, and inheritance logicprovider/: Storage backend implementations with trait-based plugin architecture
-
secretspec-derive: Proc macro for type-safe code generation
- Reads
secretspec.tomlat compile time - Generates strongly-typed structs from configuration
- Supports both union types (safe for any profile) and profile-specific types
- Validates secret names produce valid Rust identifiers
- Reads
The provider system uses a trait-based architecture defined in src/provider/mod.rs. When implementing new providers:
- Create module in
src/provider/your_provider.rs - Implement the
Providertrait with methods:get(),set(),check_writable(),name(),description() - Use the
#[provider]macro for automatic registration - Handle profile-aware storage paths (e.g.,
secretspec/{project}/{profile}/{key})
Providers support URI-based configuration (e.g., keyring://, onepassword://vault, dotenv://.env.production). The provider system handles URI parsing and provider instantiation directly within each provider module.
When adding a new provider, update every location below — provider names appear in several listings that drift out of sync if any are missed:
docs/src/content/docs/providers/<provider>.md- Create the provider's doc page and add a version compatibility notice if it is unreleaseddocs/astro.config.ts- Add to sidebar navigation under "Providers" and to the providers sentence in thestarlightLlmsTxtdescription blockdocs/src/content/docs/concepts/providers.md- Add a row to the "Available Providers" tabledocs/src/content/docs/reference/providers.md- Add a provider section and a row in the "Security Considerations" tabledocs/src/pages/index.astro- Add to theproviderMetadataarray (top of file) and to thesecretspec config initmini-terminal in the herodocs/src/content/docs/quick-start.mdx- Update thesecretspec config initexample output to include the new providerREADME.md(symlink tosecretspec/README.md) - Add to the "Providers" bullet list and to thesecretspec config initexample output
If the provider is unreleased, add its target version (for example (0.15+))
in every listing above. See
docs/src/content/docs/development/adding-providers.md for the full release
visibility checklist.
- CLI flag (
--profile) - Environment variable (
SECRETSPEC_PROFILE) - User config default
- Falls back to "default" profile
- Per-secret providers (with fallback chain): specified in
secretspec.tomlasproviders: [alias1, alias2, ...]- Aliases resolved against the project
[providers]table insecretspec.tomlfirst, then the[defaults.providers]table in~/.config/secretspec/config.toml - Project-level aliases win on conflict
- Tries each provider in order until secret is found
- Aliases resolved against the project
- CLI flag (
--provider) - Environment variable (
SECRETSPEC_PROVIDER) - User config default provider
- Falls back to keyring provider
Secrets can specify their own providers using the providers field to override global defaults:
[profiles.production]
DATABASE_URL = { description = "Production DB", providers = ["prod_vault", "keyring"] }
API_KEY = { description = "API Key", providers = ["shared"] }
GITHUB_TOKEN = { description = "GitHub token from env", providers = ["env"] }Provider aliases can be checked into the project in secretspec.toml so every team member and CI runner sees them automatically:
[providers]
prod_vault = "onepassword://Production"
shared = "onepassword://Shared"
keyring = "keyring://"
env = "env://"They can also be defined per-user in ~/.config/secretspec/config.toml (project entries win on conflict):
[defaults]
provider = "keyring"
[defaults.providers]
prod_vault = "onepassword://Production"
shared = "onepassword://Shared"
keyring = "keyring://"
env = "env://"Manage the user-level map via CLI (project-level aliases are hand-edited in secretspec.toml):
# Add provider alias to user config
secretspec config provider add prod_vault "onepassword://Production"
# List user-level aliases
secretspec config provider list
# Remove a user-level alias
secretspec config provider remove prod_vault- Check active profile for secret
- Fall back to "default" profile
- Apply defaults if configured
- Validate required secrets are present
Projects can extend other configurations via extends = ["../shared/common"]. The system loads configs recursively and merges them with proper precedence.
- Unit tests are located alongside the code
- Integration tests in
secretspec-derive/tests/andtests/integration/ - UI tests using
trybuildfor macro error testing - Run specific test:
cargo test test_name - Test CI runs on Ubuntu and macOS using devenv
Provider tests are located in secretspec/src/provider/tests.rs and test all provider implementations generically.
# Run provider tests
cargo test --package secretspec provider::tests
# Test specific providers using SECRETSPEC_TEST_PROVIDERS env var
SECRETSPEC_TEST_PROVIDERS=keyring,dotenv cargo test --package secretspec provider::tests::integration_tests
# Run with output visible
SECRETSPEC_TEST_PROVIDERS=dotenv cargo test --package secretspec provider::tests -- --nocaptureThe integration tests cover:
- Basic get/set operations
- Multiple secrets handling
- Special characters and Unicode
- Profile-specific storage
- Error handling for edge cases
Note: Some providers (like env) are read-only and will skip write tests.
The docs site is an Astro Starlight site deployed to https://secretspec.dev/.
docs/astro.config.ts- Sidebar navigation and site configdocs/src/pages/index.astro- Home page (custom landing layout, not in the content collection)docs/src/content/docs/- All other content pages (markdown/mdx)quick-start.mdx- Getting started guideconcepts/- Declarative config, profiles, providers overviewproviders/- Individual provider docs (one.mdper registered provider; see Adding Provider Documentation when adding a new one)sdk/- Rust SDK docsreference/- Configuration, CLI, providers reference, adding providers guide
- New doc page: Create the
.mdfile and add it to the sidebar indocs/astro.config.ts - New CLI command: Update
docs/src/content/docs/reference/cli.md - New config option: Update
docs/src/content/docs/reference/configuration.md - New provider: See Adding Provider Documentation above
- New concept: Create
docs/src/content/docs/concepts/<name>.mdand add to sidebar
For every unreleased item above, put the target-version notice on the specific page or section where the item is documented. A notice elsewhere is not sufficient.
secretspec.toml: Project secrets configurationsecretspec/src/provider/mod.rs: Provider trait definition and documentationsecretspec/src/cli/mod.rs: CLI command definitionssecretspec/src/bin/secretspec.rs: CLI entry pointsecretspec/src/lib.rs: Core SecretSpec implementationsecretspec-derive/src/lib.rs: Code generation macro implementationsecretspec/src/provider/tests.rs: Generic provider test suite