Skip to content

Repository files navigation

envctl

A Nushell-native configuration compiler and execution engine for environment and secrets management.

What it does

  • Generates .env from declarative templates with {{ token }} substitution
  • Manages secrets: generates, rotates, and delivers them to file or other backends
  • Manages PKI certificate chains (Root CA → Intermediate → Leaf) via openssl
  • Validates all config against TOML schemas before writing anything
  • Tracks versions in .envctl.lock (commit this) and an audit log in .envctl/state.ndjson (gitignore the .envctl/ directory)

Requirements

  • Nushell >= 0.94
  • openssl >= 3.0 (for secrets and certificates)
  • git (for the git provider)

Install

http gethttps://raw.githubusercontent.com/arttet/envctl/main/install.nu|into string|nu-c$in

After installation, restart your Nushell session — all envctl commands are available globally.

Default install paths:

OSPath
Linux / macOS~/.local/share/envctl
Windows%LOCALAPPDATA%\envctl

The installer writes an autoload hook to $nu.vendor-autoload-dirs — no manual source needed.

More options (from a cloned repo):

nuinstall.nu--prefix~/.envctl# custom install directorynuinstall.nu--dry-run# preview without writing anythingnuinstall.nu--uninstall# remove files and autoload hook

Quick start

Initialize project (creates .envctl.toml and setup gitignore)

envctlinit

First-time setup: generate everything at once

envctlgenerate

Generate .env from .env.example

envctlenvfilegenerate

Generate all missing secrets

envctlsecretsgenerate

Generate PKI certificates (if [certs] is configured)

envctlcertsgenerate

Check health

envctlhealth

Config format

Create .envctl.toml in your project root:

schema = "v1"
[providers]
enabled = ["git", "password"]
[generators]
GIT_ROOT_DIR = "{{ provider:git.top-level-dir }}"
[envfile]
file = ".env"pattern = ".env.example"
[secrets]
base_dir = "."
[secrets.DB_PASSWORD_FILE]
value_source = "{{ provider:password.generate-password }}"targets = ["file"]
[secrets.DB_PASSWORD_FILE.options.file]
path = "{{ GIT_ROOT_DIR }}/secrets/db_password"

Then commit .envctl.toml and .envctl.lock. Add .envctl/ and .env to .gitignore.

Token grammar

TokenExampleResolves to
{{ IDENT }}{{ GIT_ROOT_DIR }}Value from resolved generators
{{ secret:IDENT }}{{ secret:DB_PASS_FILE }}Contents of file at path stored in IDENT
{{ provider:NAME.FN }}{{ provider:git.top-level-dir }}Calls fn from provider manifest

Commands

envctlenvfilegenerate [--stage] [--dry-run] [--quiet] [--config]
envctlenvfilediffenvctlsecretsgenerate [--stage] [--dry-run]
envctlsecretsrotate--keyNAMEenvctlsecretsrotate-allenvctlcertsgenerate [--nameNAME] [--dry-run]
envctlcertsrotate--nameNAMEenvctlcertsrotate-allenvctlcertsstatusenvctlhealth [--profileenvfile|secrets|certs]
envctlpluginslist

Profiles

ProfileWhat runs
envfileParse generators + render .env
secretsGenerate missing secrets via providers, write via backends
certsGenerate PKI certificate chains
allenvfile + secrets + certs

Environment variables

VariableDefaultEffect
ENVCTL_CONFIG.envctl.tomlOverride config path
ENVCTL_STAGEdevOverride stage
ENVCTL_DRY_RUNfalseEnable dry-run (no writes)
ENVCTL_QUIETfalseSuppress non-error output

Built-in providers

ProviderTokenConfig
git{{ provider:git.top-level-dir }}none (override with ENVCTL_GIT_ROOT)
password{{ provider:password.generate-password }}length, charset, tool
compose{{ provider:compose.collect-files }}base_dir, base_files, services
certs(used internally by envctl certs)tool, key_bits, organization, country

Built-in backends

BackendWrites to
fileLocal filesystem path

Development

justfmt# Format codejustlint# Run linterjusttest# Run testsjustrunenvctlhealth# Run any command

Running tests

nurun_tests.nu# All testsnurun_tests.nu--unit# Unit tests onlynurun_tests.nu--filetests/unit/grammar_test.nu

Architecture

See Architecture for the execution flow and layer responsibilities.

License

MIT — see LICENSE.

Releases

Used by

Contributors

Languages