Skip to main content

Provider

Trait Provider 

Source
pub trait Provider: Send + Sync {
Show 14 methods // Required methods fn convention_address( &self, project: &str, profile: &str, key: &str, ) -> Result<NativeAddress>; fn get(&self, addr: Address<'_>) -> Result<Option<SecretString>>; fn set(&self, addr: Address<'_>, value: &SecretString) -> Result<()>; fn name(&self) -> &'static str; fn uri(&self) -> String; // Provided methods fn supported_coords(&self) -> &'static [&'static str] { ... } fn resolve_coords<'a>( &self, addr: Address<'a>, ) -> Result<Cow<'a, NativeAddress>> { ... } fn check_writable(&self, addr: Address<'_>) -> Result<()> { ... } fn auth_scope_key(&self) -> Option<String> { ... } fn set_reason(&self, _reason: Option<String>) { ... } fn with_base_dir(&mut self, _base_dir: &Path) { ... } fn with_credentials(&mut self, _credentials: HashMap<String, SecretString>) { ... } fn reflect(&self) -> Result<HashMap<String, Secret>> { ... } fn get_many( &self, requests: &[(&str, Address<'_>)], ) -> Result<HashMap<String, SecretString>> { ... }
}
Expand description

Trait defining the interface for secret storage providers.

All secret storage backends must implement this trait to integrate with SecretSpec. The trait is designed to be flexible enough to support various storage mechanisms while maintaining a consistent interface.

§Thread Safety

Providers must be Send + Sync as they may be used across thread boundaries in multi-threaded applications.

§Profile Support

Providers should support profile-based secret isolation, allowing different values for the same key across environments (e.g., development, staging, production).

§Implementation Guidelines

  • Providers should handle their own error cases and return appropriate Result types
  • Storage paths should follow the pattern: {provider}/{project}/{profile}/{key}
  • Providers may choose to be read-only by overriding check_writable
  • Provider names should be lowercase and descriptive

Required Methods§

Source

fn convention_address( &self, project: &str, profile: &str, key: &str, ) -> Result<NativeAddress>

Compiles SecretSpec’s {project}/{profile}/{key} naming convention into this store’s native coordinates: the same address space a secret’s ref uses.

This is the single owner of the provider’s convention layout (format strings, path shapes, default vaults); the operation methods resolve every address through resolve_coords and never re-derive names. Pure naming, no I/O.

§Errors

Returns an error when the convention inputs cannot form a valid name in this store (e.g. empty components, length limits).

Source

fn get(&self, addr: Address<'_>) -> Result<Option<SecretString>>

Retrieves the secret named by addr.

See [Address] for the two naming schemes. A provider that cannot interpret a Native coordinate (e.g. a field on a store whose secrets have no sub-components) returns an error naming the coordinate rather than guessing.

§Returns
  • Ok(Some(value)) if the secret exists
  • Ok(None) if the secret doesn’t exist
  • Err if there was an error accessing the provider
§Example
let addr = Address::Convention { project: "myapp", profile: "production", key: "DATABASE_URL" };
match provider.get(addr)? {
    Some(url) => println!("Database URL: {}", url),
    None => println!("DATABASE_URL not found"),
}
Source

fn set(&self, addr: Address<'_>, value: &SecretString) -> Result<()>

Stores a secret value at addr.

§Returns
  • Ok(()) if the secret was successfully stored
  • Err if there was an error or the address is read-only
§Errors

This method should return an error whenever check_writable does, for the same address.

Source

fn name(&self) -> &'static str

Returns the name of this provider.

This should match the name registered with the provider macro.

Source

fn uri(&self) -> String

Returns the full URI representation of this provider.

This includes any configuration like vault names, paths, etc. For example: “onepassword://VaultName” or “dotenv://.env.production”

§Contract: the returned URI must be credential-free

The audit log records this URI and the fallback-chain warnings print it, so it must never contain a secret the user embedded in the source URI (e.g. a :password or service-account token). Reconstruct the URI from non-secret attribution only — account, profile, namespace, host, path — and drop any credential, which authentication resolves from the environment or a token field instead. This contract is enforced for every registered scheme by uri_never_echoes_a_userinfo_password in provider::tests.

Provided Methods§

Source

fn supported_coords(&self) -> &'static [&'static str]

The optional [NativeAddress] coordinates this store can honor, beyond the universally consumed item (e.g. ["field"]).

Declared as data rather than checked per operation: the default resolve_coords rejects every coordinate a provider does not name here, so a store whose secrets have no sub-components gets the correct behavior from the empty default without writing any validation.

Source

fn resolve_coords<'a>( &self, addr: Address<'a>, ) -> Result<Cow<'a, NativeAddress>>

Resolves any [Address] to this store’s native coordinates: a ref’s coordinates pass through as-is, a convention address is compiled via convention_address. Coordinates outside supported_coords are rejected, so every operation that resolves an address inherits the check.

Source

fn check_writable(&self, addr: Address<'_>) -> Result<()>

Reports whether this provider can write to addr, and why not when it cannot.

Callers use this to refuse a write before prompting for a value, so the error must be the same one set would return: state the policy here and have set call this method, rather than writing the rule twice.

By default, providers are assumed to support writing. Read-only providers (like environment variables) reject every address; providers that can write their own layout but not externally managed secrets reject only Native addresses, and say so — a generic “provider is read-only” would be untrue of the store as a whole.

§Example
provider.check_writable(addr)?;
provider.set(addr, &value)?;
Source

fn auth_scope_key(&self) -> Option<String>

Identifies the shared authentication state this instance’s preflight check probes, when that state outlives the instance.

Instances of the same provider returning equal keys share one probe result process-wide. This matters because a secret’s providers chain builds a fresh provider instance per (secret, URI) pair — without a scope key, N secrets would run N identical auth probes (each typically a CLI round-trip). The default None keeps the probe per-instance.

Source

fn set_reason(&self, _reason: Option<String>)

Records a human-readable reason for the secrets access happening in this session (e.g. “secretspec run: deploy”), set via Secrets::with_reason.

Providers that support audit logging use this; for example the Proton Pass provider forwards it to pass-cli agent sessions, which require a reason for every audited item operation. The default implementation ignores it.

Takes &self (relying on interior mutability) so it can be applied after the provider is wrapped in an Arc (as preflight-enabled providers are).

Source

fn with_base_dir(&mut self, _base_dir: &Path)

Rebases any relative filesystem paths the provider holds against base_dir, the directory containing the secretspec.toml that configured it.

File-backed providers (e.g. dotenv) take paths from the config or its provider aliases. Those paths must resolve relative to the project root, not the process’s current working directory — otherwise running from a subdirectory with --file ../secretspec.toml looks for the .env file in the wrong place. Secrets calls this once at construction, before the provider performs any I/O. The default implementation does nothing, which is correct for providers that hold no relative paths.

Source

fn with_credentials(&mut self, _credentials: HashMap<String, SecretString>)

Hands semantic credentials to the provider.

Called once inside the registration factory, on the concrete provider value before any Arc/Box wrapping. This must not be a post-construction call on a Box<dyn Provider>: like with_base_dir, a &mut self hook cannot be forwarded through the blanket impl Provider for Arc<T> (an Arc gives no &mut access to its inner value), so a preflight provider — wrapped as Box<Arc<P>> — would silently receive the default no-op. The default implementation ignores the values, which is correct for providers that need no credentials.

Source

fn reflect(&self) -> Result<HashMap<String, Secret>>

Discovers and returns all secrets available in this provider.

This method is used to introspect the provider and find all available secrets. It’s particularly useful for importing secrets from external sources.

§Returns

A HashMap where keys are secret names and values are Secret configurations. The default implementation returns an empty map, indicating the provider doesn’t support reflection.

§Example
let secrets = provider.reflect()?;
for (name, secret) in secrets {
    println!("Found secret: {} = {:?}", name, secret);
}
Source

fn get_many( &self, requests: &[(&str, Address<'_>)], ) -> Result<HashMap<String, SecretString>>

Retrieves multiple secrets in one batch operation.

Each request pairs a secret name (the key of the returned map) with the [Address] to fetch it from, so a batch mixes convention secrets and ref secrets freely. Secrets that don’t exist are omitted from the result.

§Contract

Requests naming identical addresses (several secrets sharing one ref) must be fetched once and share the value.

§Default Implementation

The default deduplicates identical addresses and fetches each unique address once, concurrently. Providers with a real batch surface (one listing, a bulk API) should override this to cut round-trips further.

Trait Implementations§

Source§

impl TryFrom<&Url> for Box<dyn Provider>

Source§

type Error = SecretSpecError

The type returned in the event of a conversion error.
Source§

fn try_from(url: &Url) -> Result<Self>

Performs the conversion.
Source§

impl TryFrom<&str> for Box<dyn Provider>

Source§

type Error = SecretSpecError

The type returned in the event of a conversion error.
Source§

fn try_from(s: &str) -> Result<Self>

Performs the conversion.
Source§

impl TryFrom<String> for Box<dyn Provider>

Source§

fn try_from(s: String) -> Result<Self>

Creates a provider instance from a URI string.

This function handles various URI formats and normalizes them before parsing. It supports both full URIs and shorthand notations.

§URI Formats
  • Full URI: scheme://authority/path (e.g., onepassword://Production)
§Special Cases
  • 1password: Will error suggesting to use onepassword instead
  • Bare provider names: Automatically converted to provider://
§Examples
use std::convert::TryFrom;

// Simple provider name
let provider = Box::<dyn Provider>::try_from("keyring".to_string())?;

// Full URI with configuration
let provider = Box::<dyn Provider>::try_from("onepassword://Production".to_string())?;

// Dotenv with path
let provider = Box::<dyn Provider>::try_from("dotenv:.env.production".to_string())?;
Source§

type Error = SecretSpecError

The type returned in the event of a conversion error.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl<T: Provider> Provider for Arc<T>

Source§

fn convention_address( &self, project: &str, profile: &str, key: &str, ) -> Result<NativeAddress>

Source§

fn supported_coords(&self) -> &'static [&'static str]

Source§

fn resolve_coords<'a>( &self, addr: Address<'a>, ) -> Result<Cow<'a, NativeAddress>>

Source§

fn get(&self, addr: Address<'_>) -> Result<Option<SecretString>>

Source§

fn set(&self, addr: Address<'_>, value: &SecretString) -> Result<()>

Source§

fn check_writable(&self, addr: Address<'_>) -> Result<()>

Source§

fn auth_scope_key(&self) -> Option<String>

Source§

fn name(&self) -> &'static str

Source§

fn uri(&self) -> String

Source§

fn set_reason(&self, reason: Option<String>)

Source§

fn reflect(&self) -> Result<HashMap<String, Secret>>

Source§

fn get_many( &self, requests: &[(&str, Address<'_>)], ) -> Result<HashMap<String, SecretString>>

Implementors§