si vault (Encrypted Dotenv Credentials)
si vault manages credentials in dotenv files with values encrypted inline using age recipients. Vault commands operate on a single default env file (vault.file in settings) unless --file is provided.
Goals:
- encrypted at rest (git-friendly, PR-reviewable)
- minimal git noise (encrypted values are not rewritten unless you explicitly re-encrypt)
- Docker-friendly runtime injection (decrypt on host, inject into
docker execenv for that exec only) - local-only audit trail (no secret values logged)
Model (Recommended Default)
- One encrypted dotenv file on disk (default:
~/.si/vault/.env). - Use
--fileto operate on a different file.
Quickstart
From your host repo (or any local workspace):- Ensure you have a device identity (this stores a private age identity in your OS secure store by default):
- Bootstrap the default env file:
--file:
- Set a secret (prefer
--stdinto avoid shell history):
- Format the file to the canonical style (optional but recommended):
- Run a local process with secrets injected:
&&, etc), you can run a shell explicitly:
- Inject secrets into an existing container process (
docker execenv injection for that exec only):
Dyads + Codex Containers
Dyad and Codex containers are built from the same unified image (aureuma/si:local) which includes /usr/local/bin/si.
That means you can run read-only vault commands (like si vault status) from inside a dyad container via si dyad exec.
For secret injection, prefer running from the host:
Prevent Plaintext Commits (Git Hooks)
si vault hooks install installs a best-effort local pre-commit hook in the current git repo to block committing dotenv files that contain plaintext values.
You can also manage hooks explicitly:
si vault check --staged --all.
Notes:
- Git hooks are local-only and can be bypassed with
git commit --no-verify. - For stronger enforcement, add a CI check in the vault repo that fails if any
.env*file contains plaintext values.
Multiple Dotenv Files
By default, vault commands operate on the configuredvault.file. To operate on a different dotenv file, pass --file explicitly:
- If your implicit default file points to a different git repo than your current workspace,
si vaultprints a warning. - Set
SI_VAULT_STRICT_TARGET_SCOPE=1to enforce fail-fast behavior for this mismatch. - Use
--file, runsi vault use --file <path>, or setSI_VAULT_ALLOW_CROSS_REPO=1to suppress cross-repo scope warnings.
Formatting
si vault fmt enforces a canonical header and key/value style:
- header block:
# si-vault:v2- one or more
# si-vault:recipient age1...lines - one blank line after header
- version is shared with the current encrypted value prefix (
encrypted:si:v2:)
- sections:
- section headers like
# [stripe]are preserved as-authored (not lowercased/rewritten) - divider comment lines (e.g.
# ---------...) are preserved as-authored
- section headers like
- keys:
KEY=value(no spaces around=)
--format to run fmt after the minimal edit.
Decrypting To Plaintext
By default,si vault decrypt decrypts values in-place in the same file on disk (similar to dotenvx decrypt).
This is intentionally dangerous: it writes plaintext secrets to disk. Prefer runtime injection (si vault run)
when possible, and re-encrypt immediately after editing.
To preview the decrypted file without modifying it:
Trust Model (TOFU)
si vault uses trust-on-first-use (similar to ssh known_hosts) to prevent silent recipient drift:
- local trust store:
~/.si/vault/trust.json - keyed by
(host repo root, env file) - stores the recipients fingerprint
si vault trust statusshows stored vs current fingerprint.si vault trust acceptrecords the current fingerprint.si vault trust forgetremoves the trust entry.
Key Storage
Device identities are age X25519 private keys. Resolution order:SI_VAULT_IDENTITY(orSI_VAULT_PRIVATE_KEY) (CI/ephemeral)SI_VAULT_IDENTITY_FILE- OS secure store (Keychain on macOS, Secret Service on Linux) (
vault.key_backend = "keyring"or"keychain") - file backend (
vault.key_backend = "file",vault.key_file = "~/.si/vault/keys/age.key")
~/.si/settings.toml under [vault].
Key file security:
- when using file backend,
sirequires the key file to be0600and not a symlink - override (not recommended):
SI_VAULT_ALLOW_INSECURE_KEY_FILE=1 - vault dotenv writes also refuse symlink targets by default
- override (not recommended):
SI_VAULT_ALLOW_SYMLINK_ENV_FILE=1
Audit Log
Default audit log:~/.si/logs/vault.log(JSONL)
init,set,unset,encrypt,reveal,run,docker_exec
Security Notes (MVP)
--revealprints a secret to stdout. Use sparingly.- Prefer
--stdinforsetto avoid shell history. si vault runandsi vault docker execrefuse to proceed if plaintext keys exist unless you pass--allow-plaintext.- dotenv keys are validated for safe env export (no whitespace,
=, or control characters). docker execenv injection is per-exec; values are still transmitted to the Docker daemon. Treat remote Docker as highly privileged.si vault docker execrefuses insecureDOCKER_HOSTby default; override with--allow-insecure-docker-hostonly if you understand the risk.
