firma_secret_provider (root module)
Module: firma_secret_provider
Section titled “Module: firma_secret_provider”Contents
Section titled “Contents”Modules
broker- Out-of-sandbox broker transport for the secret shim.endpointgateway- Wire types and client transport for the secret-gateway control channelnon_empty- Non-empty wrapper types.spec- Secret-provider integration specs: how to classify provider commands andstore- In-memory secret dictionary for thefirma runsecret broker.
Module: broker
Section titled “Module: broker”Out-of-sandbox broker transport for the secret shim.
The shim binary connects to the broker over a Unix domain socket (Unix) or TCP loopback (Windows) and sends a newline-terminated JSON request. The broker dispatches each request to its handler, which applies config matching and authorization to decide whether the real CLI runs out of the sandbox; when it does, the handler intercepts the output, and the broker writes back a newline-terminated JSON response containing base64-encoded, stream-tagged output chunks in observed capture order.
Protocol (one round-trip per connection):
shim → {"bin":"bws","args":["secret","get","abc"]}\nbroker → {"type":"executed","output":[{"stream":"stdout","data":"<base64>"}],"status":{"type":"exited","code":0}}\nbroker → {"type":"rejected","error":"<reason>"}\nLayout mirrors the secret gateway’s: shared wire types live here,
[client] is the shim-side connector, and [server] is the broker-side
listener.
Size caps: process output is base64-encoded onto the wire, so a configured
response cap of N bytes admits at most roughly 3N/4 bytes of total raw
output. JSON framing and per-chunk stream metadata reduce the usable payload,
especially when output is split into many small chunks. The [client] and
[server] defaults are aligned so both sides agree on the largest request
and response lines; tune them together.
Module: endpoint
Section titled “Module: endpoint”Module: gateway
Section titled “Module: gateway”Wire types and client transport for the secret-gateway control channel between firma-sidecar’s HTTP MITM intercept and firma-run’s broker.
The broker owns the persistent secret store; the Sidecar mints
placeholders locally (see [crate::SecretPlaceholder]) so it can
substitute them synchronously into the response body it forwards, then
reports the mapping to the broker via [PushRequest]. Later, when the
Sidecar needs to inject the real value into an outbound request, it looks
placeholders back up via [ResolveRequest]. [Str] borrows from the
request buffer where possible to avoid copying secret material.
This module defines the wire types themselves; [client] implements the
transport that speaks the protocol over a [firma_config_schema::gateway::GatewayConfig]-tuned
connection to a [crate::endpoint::client::ClientEndpoint], and [server]
implements the broker-side listener that serves the same protocol from the
shared [crate::store::SecretStore].
Module: non_empty
Section titled “Module: non_empty”Non-empty wrapper types.
[NonEmptyStr] and [NonEmptyVec] push “at least one element/character”
invariants into the type system, so callers and [serde] deserialization
can’t construct an empty value and downstream matching logic never has to
re-check for it.
Module: spec
Section titled “Module: spec”Secret-provider integration specs: how to classify provider commands and extract secrets from provider output. Callers own placeholder minting and persistence for extracted values.
A provider is either a CLI vault tool (stdout intercepted by firma-run’s
broker via a stdio shim) or an HTTP vault (response bodies intercepted by
firma-sidecar’s MITM path). The two shapes are deliberately distinct
enum variants rather than one struct with optional fields, so a config
mixing CLI-only and HTTP-only attributes (e.g. an HTTP entry carrying a
binary_name) cannot be represented.
Module: store
Section titled “Module: store”In-memory secret dictionary for the firma run secret broker.
The broker keeps real secret values out of the agent: each value is stored
under an opaque placeholder token and the agent only ever sees the token.
This module owns the dictionary — placeholder ↔ secret value, populated
by intercept and consulted for rehydration ([SecretStore::resolve]).
The streaming rewrite and the out-of-sandbox broker transport live in other
modules; this one is deliberately transport-free so it can be unit-tested in
isolation. See docs/architecture/secrets-interception.md.