██████╗ ██████╗ ████████╗ ██╗ ██████╗ ██████╗ ██╗ ██╗
██╔══██╗ ██╔═══██╗ ╚══██╔══╝ ██║ ██╔═══██╗ ██╔════╝ ██║ ██╔╝
██║ ██║ ██║ ██║ ██║ ██║ ██║ ██║ ██║ █████╔╝
██║ ██║ ██║ ██║ ██║ ██║ ██║ ██║ ██║ ██╔═██╗
██████╔╝ ╚██████╔╝ ██║ ███████╗ ╚██████╔╝ ╚██████╗ ██║ ██╗
╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝
Encrypt your .env. Share by key, not by password.
Description
DotLock is a local, file-based secrets manager for project environment variables. It stores secrets in a .lock/ vault next to your code and injects decrypted values only into child processes launched with dl run.
Use DotLock when you want:
- to keep
.envvalues encrypted in a repository; - to run local commands with decrypted variables without writing plaintext back to disk;
- to share project secrets with teammates through public keys instead of a shared password;
- to keep a lightweight audit log of unlocks, runs, key ratchets and dynamic provider resolutions.
DotLock is not a hosted production secret manager. For large production systems, prefer a dedicated service such as AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault or your platform's native secret store.
Status
DotLock is alpha software. The cryptographic building blocks are conservative, but the on-disk format and CLI surface may still change before 1.0. Keep backups of .lock/ and review changes before upgrading across 0.1.x releases.
Installation
From crates.io
The crate is named dotlock-bin; the installed binary is named dl.
From source
DotLock uses Rust edition 2024.
Quick Start
What happens:
dl initcreates.lock/vault.tomland.lock/secrets.lock.dl migrate .envimports variables from an existing.envfile.dl run npm startstartsnpm startwith decrypted secrets in the child process environment.
After migration, remove the plaintext .env only when you have verified the imported values:
Core Workflow
Initialize a project
What: dl init creates the project vault in the current directory.
How:
You will choose whether DotLock generates a strong master password or lets you type one. The vault metadata goes into .lock/vault.toml; encrypted secret records go into .lock/secrets.lock.
When: Run once per project before using any other project command.
Add or update a static secret
What: dl set NAME VALUE stores a secret value under a normalized environment variable name.
How:
Aliases:
Names must use letters, digits and underscores, and cannot start with a digit. DotLock normalizes names to uppercase.
--alg (short -a) selects the encryption algorithm for static secrets. The current supported value is xcha, which maps to XChaCha20-Poly1305.
When: Use this when adding a new secret or replacing an existing value.
Read a secret
What: dl get NAME decrypts one secret and prints it.
How:
|
When stdout is a terminal, DotLock renders a boxed display with the secret name and short id. When stdout is piped, it prints the raw value.
When: Use sparingly for copying or debugging a single value. Prefer dl run for normal command execution.
List secrets
What: dl list shows stored secret names and short ids without plaintext values.
How:
When: Use before get, unset, ACL changes or audits to confirm what is stored.
Remove a secret
What: dl unset NAME removes a secret and its access wrapping metadata.
How:
Other aliases: remove, u, d, del, delete.
When: Use when a variable is no longer needed or should no longer be available to dl run.
Run a command with secrets
What: dl run CMD [args...] decrypts accessible secrets and starts a child process with those values in its environment.
How:
The -- separator is important when the command has its own flags.
When: Use this as the normal way to consume secrets locally or in scripts.
Lock the session
What: dl lock deletes the cached project key for the current project.
How:
When: Use after a sensitive session, before handing off a machine, or at the end of CI/scripted workflows.
Import and Export .env Files
Import from .env
What: dl migrate [PATH] imports variables from a .env file into the encrypted vault.
How:
The parser accepts:
KEY=VALUE;export KEY=VALUE;- single-quoted values;
- double-quoted values with escapes such as
\n,\r,\t,\\and\"; - comments and blank lines.
When: Use when adopting DotLock in an existing project or bulk-loading variables.
Export to .env
What: dl export [PATH] writes missing static secrets into a .env file.
How:
Existing keys are never overwritten. Dynamic secrets are skipped because their values are resolved at runtime.
When: Use for tools that still require a .env file, or when bridging DotLock with legacy local workflows.
Team Sharing
DotLock supports shared access through a local RSA identity. The project owner keeps the master password; recipients unlock with their own private key.
Create a local identity
What: dl cert init creates a local RSA key pair.
How:
Aliases:
By default, the private key is passphrase-protected. --plain creates an unencrypted private key. --force replaces an existing identity.
When: Each developer or CI environment should do this once before requesting shared access.
Show or export the public key
What: dl cert show prints the local identity fingerprint and paths. dl cert export-pub [PATH] prints or writes the public key.
How:
Aliases: dl crt sh, dl crt x.
When: Use show to confirm which identity is active. Use export-pub when sending a public key to a vault owner.
Enable shared mode
What: dl share enable marks the vault as shared.
How:
When: Use before granting access to teammates or CI.
Grant access
What: dl share grant adds or updates a recipient.
How:
Aliases: dl shr gr.
Without --allow, the recipient gets full access. With --allow, the recipient can decrypt only the listed secrets.
When: Use when onboarding a developer, adding a CI identity, or changing a recipient's access scope.
Manage a recipient ACL
What: dl share allow lists, adds or removes per-secret access for a recipient.
How:
The recipient query can be the recipient id, label or public key fingerprint. Removing a secret from a recipient rotates that secret's SDK so the old recipient wrapping cannot decrypt future values.
When: Use for least-privilege access, especially for CI identities.
List or revoke recipients
What: dl share list shows recipients. dl share revoke QUERY removes a recipient and rotates project access material.
How:
Aliases: dl shr l, dl shr rev.
When: Use list before access reviews. Use revoke when someone leaves the project or an identity is compromised.
Rotation and Ratcheting
Rotate the master password
What: dl rotate master-password changes the password used to unlock the project key.
How:
When: Use when a password may have been exposed but the encrypted vault itself does not need a full project-key rotation.
Rotate key wrapping material
What: dl rotate kek rotates the key wrapping layer and rewraps secret SDKs and full-access recipient project keys.
How:
When: Use as hygiene after many writes, or let DotLock trigger it automatically with auto_ratchet_after_writes.
Rotate the project key
What: dl rotate project-key generates a new project key and rewrites encrypted secret records.
How:
When: Use after a suspected project-key exposure or after major access changes that justify a heavier rotation.
Dynamic Secret Providers
Dynamic secrets are resolved by external executables instead of storing a fixed plaintext value. Provider binaries must be named dotlock-provider-NAME and be available on PATH.
Discover providers
What: dl provider list lists provider binaries found on PATH. dl provider info NAME runs a provider's --describe command.
How:
When: Use before creating a dynamic secret, or when debugging provider installation.
Store a dynamic secret
What: dl set NAME --provider PROVIDER stores encrypted provider metadata instead of a static value.
How:
--config must be valid JSON. --bootstrap is a comma-separated list of existing static secrets that DotLock decrypts and passes to the provider at resolve time.
When: Use when the value should be minted or fetched just-in-time from another local provider, while DotLock still controls bootstrap material and runtime injection.
Provider protocol
Providers are executed as child processes:
dotlock-provider-NAME --describeprints human-readable provider information.dotlock-provider-NAME --resolvereads JSON on stdin and prints the resolved secret value on stdout.
The resolve input has this shape:
DotLock records the provider path and SHA-256 digest when the dynamic secret is created. Later resolutions verify the digest before running the provider. Provider stdout is limited to 64 KiB and stderr to 16 KiB.
Git Integration
Install the merge driver
What: dl git install-merge-driver configures Git to use DotLock's merge driver for .lock/secrets.lock and .lock/vault.toml.
How:
dl init also attempts to install the merge driver when the project is inside a Git work tree.
When: Use in repositories where multiple branches or teammates may edit the vault.
Auto-fetch before run
What: when enabled, dl run tries a short git pull --ff-only --no-rebase REMOTE BRANCH before unlocking.
How:
DOTLOCK_AUTO_FETCH=0
If pull fails, DotLock tries git fetch and then continues with the local vault.
When: Use when teams commit .lock/ changes frequently and want dl run to pick up fast-forward updates automatically.
Audit Log
DotLock keeps a local audit log outside the project by default. Entries are hash-chained. If a local plain identity is available, entries are signed; otherwise they are anonymous.
Show audit entries
What: dl audit show prints audit entries.
How:
Aliases: dl audit s, dl a show.
When: Use during local review, debugging or incident response.
Verify or rotate logs
What: dl audit verify checks the hash chain and signatures. dl audit rotate compresses the current log with gzip. dl audit path prints the current log path.
How:
--strict rejects anonymous entries. Logs rotate automatically when they reach 10 MiB or are older than 90 days.
When: Use verify before trusting audit history. Use rotate for manual cleanup or archival.
Configuration
Project configuration
Project configuration is stored in .lock/vault.toml.
Aliases: dl c show, dl c set, dl c unset.
| Key | Default | Accepted values | Effect |
|---|---|---|---|
auto_fetch_on_run |
false |
true, false, 1, 0, yes, no, on, off |
Enables Git auto-fetch before dl run |
auto_fetch_timeout_secs |
3 |
positive integer | Timeout for Git auto-fetch operations |
auto_fetch_remote |
origin |
non-empty string | Remote used by auto-fetch |
auto_ratchet_after_writes |
off | non-negative integer | Automatically rotates key wrapping after this many vault writes; 0 disables it |
dynamic_resolve_timeout_secs |
10 |
positive integer | Timeout for dynamic provider resolution |
Environment variables
| Variable | Default | Effect |
|---|---|---|
DOTLOCK_CACHE_TTL |
30 |
Cached project key lifetime in seconds, capped at 3600 |
DOTLOCK_CACHE_DIR |
$HOME/.lock on Unix, %LOCALAPPDATA%\dotlock on Windows |
Overrides the session cache root |
DOTLOCK_SHARED_CACHE |
off | Set to 1, true, TRUE, yes or YES to enable caching in shared mode |
DOTLOCK_IDENTITY_DIR |
$HOME/.lock/identity |
Overrides local identity storage |
DOTLOCK_AUDIT_DIR |
$HOME/.lock/audit on Unix, %LOCALAPPDATA%\dotlock\audit on Windows |
Overrides audit log storage |
DOTLOCK_AUTO_FETCH |
unset | Set to 0, false, no or off to disable auto-fetch for one command |
Command Reference
| Command | Aliases | Purpose |
|---|---|---|
dl init |
i |
Initialize .lock/ in the current project |
dl set [--alg xcha] NAME VALUE |
s, add |
Store or update a static secret |
dl set NAME --provider PROVIDER [--config JSON] [--bootstrap A,B] |
s, add |
Store a dynamic secret definition |
dl get NAME |
g |
Print a secret value |
dl unset NAME |
rm, remove, u, d, del, delete |
Remove a secret |
dl list |
l |
List stored secrets without plaintext |
dl run CMD [args...] |
r |
Run a command with decrypted secrets in its environment |
dl lock |
logout |
Drop the cached project key |
dl migrate [PATH] |
m, import |
Import variables from .env |
dl export [PATH] |
x |
Append missing static secrets to .env |
dl cert init [--force] [--plain] |
crt init, crt i |
Create a local RSA identity |
dl cert show |
crt show, crt sh |
Show local identity information |
dl cert export-pub [PATH] |
crt export-pub, crt x |
Print or write the public key |
dl share enable |
shr enable, shr en |
Enable shared mode |
dl share grant --pubkey FILE --label LABEL [--allow A,B] |
shr grant, shr gr |
Grant recipient access |
dl share allow QUERY --list |
none | List recipient ACL |
dl share allow QUERY --add A,B |
none | Add secrets to recipient ACL |
dl share allow QUERY --remove A,B |
none | Remove secrets from recipient ACL and rotate affected SDKs |
dl share revoke QUERY |
shr revoke, shr rev |
Revoke a recipient |
dl share list |
shr list, shr l |
List recipients |
dl rotate kek |
none | Rotate key wrapping material |
dl rotate master-password |
rotate mp |
Change master password |
dl rotate project-key |
rotate pk |
Rotate project key |
dl audit show [--verbose] [--since YYYY-MM-DD] [--action ACTION] |
a show, audit s |
Show audit entries |
dl audit verify [--strict] |
a verify, audit v |
Verify audit log |
dl audit path |
a path |
Print audit log path |
dl audit rotate |
a rotate |
Rotate and gzip current audit log |
dl git install-merge-driver |
none | Configure Git merge support |
dl config show |
c show |
Show project config |
dl config set KEY VALUE |
c set |
Set project config |
dl config unset KEY |
c unset |
Reset project config |
dl provider list |
p list |
List provider binaries on PATH |
dl provider info NAME |
p info |
Show provider description |
How It Works
Files on disk
Project vault:
.lock/
├── vault.toml
└── secrets.lock
Local user state:
~/.lock/
├── identity/
│ ├── identity.pem
│ ├── identity.pub.pem
│ └── identity.toml
├── run/sessions/<project>/
│ └── sessions.toml
└── audit/<project-uuid>/
└── audit.log
On Unix, private directories are created with 0700, secret/private files with 0600, and public key files with 0644. Writes use an atomic temp-file-and-rename flow.
Key hierarchy
master password
-> Argon2id derives master key
-> HKDF derives KEK
-> KEK wraps project key
-> project key wraps per-secret SDKs
-> SDK encrypts each secret value or dynamic provider metadata
Terms:
- Master password: typed or generated during
dl init. - Master key: derived from the password and salt; held briefly and zeroized.
- KEK: key-encryption key derived for wrapping the project key.
- Project key: random 32-byte key stored only in wrapped form.
- SDK: per-secret data key used to encrypt one secret's stored data.
This is why changing a master password is fast, while project-key and ACL rotations touch more vault metadata.
Integrity
Every write to secrets.lock updates an authenticated hash in vault.toml. On unlock, DotLock verifies the hash before decrypting secrets. If secrets.lock was modified outside DotLock, the command aborts with a tamper error.
Session cache
After successful unlock, DotLock may cache the project key for a short time. The default TTL is 30 seconds. Shared mode disables caching unless DOTLOCK_SHARED_CACHE is enabled.
Shared mode and ACLs
Full-access recipients receive wrapped access to the project key and per-secret SDKs. Limited recipients receive only wrapped SDKs for allowed secrets. Removing a secret from a recipient ACL rotates the affected SDKs.
Security Notes
dl getprints plaintext. Preferdl runwhen a command can consume secrets directly.- Do not commit plaintext
.envfiles after migrating to DotLock. - Commit
.lock/vault.tomland.lock/secrets.lockif your team shares the encrypted vault through Git. - Keep local identity private keys protected. Use
dl cert init --plainonly for controlled automation or ephemeral environments. - Dynamic providers are executable code. Install them from trusted sources and keep provider directories non-world-writable.
- Audit logs are local by default. They are useful for local accountability and debugging, not a centralized compliance system.
License
Dual-licensed under your choice of:
- MIT: LICENSE-MIT
- Apache 2.0: LICENSE-APACHE