EMPIRE SECURITY / ENV VAULT

Install

# Install from a checkout

Prerequisites: Python 3.11+, pipx and age on PATH. The optional commit hook also
requires gitleaks 8.30.1 (built-in rules). No Python runtime dependencies for the CLI.
From the repository root, one command installs it:

    pipx install .

For a Python-only isolated installation, from the checkout:

    python3 -m venv tools/cli && tools/cli/bin/python -m pip install --no-deps .

The pipx command is tested using a clean home, cache and venv under tools/.
Use `envvault --help` after installation. Offline operation requires no API access.

## First encrypted file

    umask 077
    age-keygen -o team.key
    age-keygen -y team.key > team.pub
    envvault init --recipient "$(cat team.pub)" --owner platform
    envvault encrypt .env -o app.age
    envvault run -i team.key app.age -- python app.py

Never commit team.key or plaintext .env files. Share only app.age and public keys.
The config holds names and rotation metadata: review whether those names are sensitive.

## Commands

    envvault add-recipient age1PUBLIC_RECIPIENT
    envvault rotate app.age -i team.key --recipient age1RETAINED_RECIPIENT --days 90
    envvault decrypt app.age -i team.key -o recovered.env
    envvault diff staging.age production.age -i team.key
    envvault inventory app.age -i team.key
    envvault hook-install

`decrypt` requires an explicit, new output path and writes mode 0600. `run` writes
no plaintext file; the child still has access to values and can print them.
`diff` compares names only and cannot tell whether shared names have different values.
`add-recipient` affects future encryptions; rotate each existing ciphertext to apply it.
`rotate` re-encrypts to exactly the supplied recipients, replacing the ciphertext.
It preserves upstream credential dates. Old ciphertext can still be decrypted by old keys.

After rotating a credential at its provider, send the replacement on stdin:

    envvault rotate app.age -i team.key --variable DATABASE_URL --owner platform --days 90

Supply the replacement through a secure pipe, not argv or shell history. The command
reads stdin to EOF. This records today's date for that variable. Reminder dates appear
in `inventory`; schedule that command in your own runner. New variables have unknown
rotation dates and are flagged until an actual upstream rotation is recorded.

The inventory also includes recipient_rotation with a due date after re-encryption.
Check both recipient_rotation.past_due and variables[].past_due in reminder jobs.
If your Git uses centrally managed hooks, hook-install refuses to replace the existing
hook. Ask the hook administrator to invoke `envvault check-staged` from the managed hook;
do not disable organization checks or override its global hooksPath.