sync-env-file
Generate a local .env from chezmoi templates and Azure Key Vault secrets.
Why it exists
Local development often needs a .env file with a mix of committed defaults and secrets from a vault. Teams usually solve this with one-off shell scripts that are hard to reuse across projects.
sync-env-file provides a small, generic CLI that:
- Keeps templates under version control via chezmoi
- Pulls secrets from Azure Key Vault at render time
- Writes a single repo-root
.envwith one command
No bespoke scripts, no copy-pasted vault logic.
Installation
Recommended: uvx (no project dependency)
Run in any project directory without adding sync-env-file to pyproject.toml or running uv sync:
uvx sync-env-file init
uvx sync-env-file
uvx installs the CLI in an isolated environment for that invocation. Your project stays free of this package as a dependency.
Requires uv. uvx manages an isolated Python environment (3.9+); your project does not need this package as a dependency.
Other install options
From PyPI (global or user install):
pip install sync-env-file
As a project dependency with uv:
uv add sync-env-file
Requires Python 3.9+, chezmoi, and the Azure CLI (external tools — not installed by the package or uvx).
Quick start
With uvx (no project dependency):
uvx sync-env-file init
# Edit .chezmoi/chezmoi.toml and .chezmoi/private_dot_env.tmpl
az login
uvx sync-env-file
If installed via pip or uv add, omit the uvx prefix:
sync-env-file init
# Edit .chezmoi/chezmoi.toml and .chezmoi/private_dot_env.tmpl
az login
sync-env-file
API overview
| Command | Description |
|---|---|
sync-env-file |
Same as sync-env-file sync |
sync-env-file sync |
Render .env from .chezmoi/ templates (requires az login) |
sync-env-file init |
Scaffold .chezmoi/chezmoi.toml, private_dot_env.tmpl, and .gitignore entries |
sync-env-file init --force |
Overwrite existing scaffold files |
Exit codes: 0 on success, non-zero on tool errors (missing chezmoi/az, no active Azure account, chezmoi apply failure).
Configuration
After init, edit two files under .chezmoi/:
chezmoi.toml
Sets the default Key Vault name:
[azureKeyVault]
defaultVault = "your-vault-name"
sync-env-file passes --config, --source, and --destination to chezmoi so paths stay repo-relative.
private_dot_env.tmpl
Defines the rendered .env content. Use chezmoi's azureKeyVault template function for secrets:
APP_BASE_URL=https://api.example.com
APP_API_KEY={{ azureKeyVault "example-api-key" | quote }}
See examples/minimal-consumer/.chezmoi/private_dot_env.tmpl for additional patterns (connection strings, optional passthrough variables).
Extended example
See examples/minimal-consumer/ for a full PyPI-first consumer project (not shipped in the wheel).
Limitations
- Requires chezmoi and Azure CLI installed and on
PATH - Secrets are fetched from Azure Key Vault only (no AWS/GCP vaults)
- Renders a single target file: repo-root
.env - Requires an active Azure account with RBAC read access to the configured vault
- Does not manage chezmoi installation, vault provisioning, or secret rotation
Roadmap
- Initial public release on PyPI
- Optional support for additional secret backends (if demand exists)
- Richer scaffold templates for common connection-string patterns
Development
uv sync
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy .
Releasing to PyPI
PyPI publication uses GitHub OIDC Trusted Publishing. The repository must not contain a PyPI token, password, credential-bearing URL, or writable deploy key. The semantic-version workflow is advisory only: it prints the proposed version and never commits, tags, or publishes.
The release workflow is deliberately split into two manual invocations so the exact wheel and sdist can be reviewed before the job receives OIDC permission:
- Merge the version change to
main, then create an immutablevX.Y.Ztag on that reviewed commit. The tag must matchproject.versioninpyproject.toml. - Run Release (PyPI) from
mainwith the tag and leaveartifact_run_idempty. This runs tests, builds one wheel and one sdist, checks their contents, smoke-tests the wheel, and uploads them withrelease-manifest.json. It cannot request a PyPI OIDC token. - Review that workflow run and manifest. Approval for publication must name the PyPI owner, package, version, tag and commit, both artifact hashes, the workflow, and the build run ID.
- Run the same workflow again from
main, with the same tag and the approved build run ID inartifact_run_id. The publish job downloads that exact artifact, rechecks its manifest and hashes, verifies that the tag still points to a commit onmain, and publishes with OIDC. It never rebuilds the distributions.
The Trusted Publisher tuple is repository Cledar/sync-env-file, workflow
release.yaml, with no GitHub environment while this private repository is on
a plan that does not provide environments. If repository visibility or the
organization plan changes, add a protected pypi environment and update the
PyPI publisher tuple in the same reviewed change before the next release.
Build artifacts expire after 14 days. If an upload partially fails, stop and inspect PyPI before retrying. Published files cannot be overwritten; yank a bad release and publish a reviewed higher version instead of reusing its version.
How to contribute
See CONTRIBUTING.md for issue reporting, development setup, and pull request guidelines.
Maintainers
- @arog-lahcim — primary maintainer
License
Apache License 2.0 — see LICENSE.
Metadata
Release files for sync-env-file 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sync_env_file-0.1.0.tar.gz | 10.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sync_env_file-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.4 kB
Release files / sync_env_file-0.1.0.tar.gz
| Download URL | sync_env_file-0.1.0.tar.gz |
|---|---|
| Size | 10.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a71d18c317e0e616caddca3c5b85f1334e26a3d5e86782bf52346d96542d8d9d
|
|
BLAKE2b-256 checksum How to use checksums |
a658b6907e654f3d7232028170e24c4f538adcad2b297c8f2a2148a1547fe788
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.11 {"installer":{"name":"uv","version":"0.12.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sync_env_file-0.1.0-py3-none-any.whl
| Download URL | sync_env_file-0.1.0-py3-none-any.whl |
|---|---|
| Size | 13.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c0f7a0af23aa649ba3acdcff01ba4e226ffbd3c1b39b9cc2609d4416f4b89bcf
|
|
BLAKE2b-256 checksum How to use checksums |
798cb3e829eb51b4a15463e4c7e92c09e7940ba4e25f85d2ba84069d5fa1b745
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.11 {"installer":{"name":"uv","version":"0.12.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|