EMPIRE SECURITY / ENV VAULT

Ci

# GitHub Actions and Forgejo Actions

The same job body works in .github/workflows/envvault.yml or .forgejo/workflows/envvault.yml.
Use a trusted runner with Python 3.11, age and gitleaks installed. Pin third-party actions
to reviewed commit hashes in your organization's runner configuration. This example uses
no third-party action; the runner must supply a checked-out repository first.

    name: private-environment
    on: [workflow_dispatch]
    jobs:
      run:
        runs-on: self-hosted
        permissions:
          contents: read
        steps:
          - name: Run trusted app with local environment
            env:
              ENVVAULT_IDENTITY: ${{ secrets.ENVVAULT_IDENTITY }}
            shell: bash
            run: |
              set +x
              umask 077
              key="$RUNNER_TEMP/envvault-job.key"
              trap 'rm -f "$key"' EXIT
              printf '%s\n' "$ENVVAULT_IDENTITY" > "$key"
              python cli.py run -i "$key" app.age -- python app.py

Do not enable this job for untrusted pull requests. The identity is a plaintext key file
in the runner's restricted temp directory; trap removes it after the command. Secret
values from app.age are never written to a plaintext file by Env Vault.

For a commit-range check in CI, stage the changed dotenv files in an isolated checkout
and run `python cli.py check-staged`. Do not run `git add` against a developer's index.

## Rotation reminder

Schedule `envvault inventory app.age -i ci.key` on your trusted runner. Store only its
JSON output in the evidence artifacts. Alert when any variables[].past_due is true.
A weekday cron example is `0 9 * * 1-5`; scheduling is your runner's responsibility.

## Coolify env import

The authorized SaaS terminal already owns /root/scripts/coolify_env_setter.py. Run it
through an adapter with `envvault run -i ci.key app.age -- python your_import.py`.
Inside the adapter, read os.environ into memory and call the fleet setter's public
function. Do not print values, use shell tracing or dump the environment. See
scripts/coolify_import.py: it maps chosen names to setter.set_env without an API call
unless explicitly run by the deploy terminal. Local tests inject a fake setter only.
The host setter is the only integration path; this build never invokes it against Coolify.