Skip to content

Headless & CI

kovra’s defaults assume a human at a Mac: the master key in the Keychain, and sensitive actions gated behind a bioProve. Unattended environments — CI runners, containers — have neither. kovra runs there too, in passphrase mode.

Set KOVRA_PASSPHRASE and kovra stops using the OS keyring entirely: it derives the 256-bit master key with Argon2id from your passphrase plus a stable, non-secret salt stored next to the vault (kdf.salt). Initialize the vault once to create the salt, then every later run derives the same key:

Terminal window
export KOVRA_PASSPHRASE="$CI_VAULT_PASSPHRASE" # from your CI secret store
kovra init

Keep the passphrase in your CI provider’s secret store — it is the only thing that unlocks the vault, so treat it like the master key it derives.

A bioProve needs a person at the Mac. kovra 0.12.1 ships for macOS, and there every approval is read and approved in kovra’s review window: the Touch ID sensor inside it, or a code and the macOS dialog with your login password when the Mac has no Touch ID (or it isn’t set up). In CI, over SSH, or anywhere without a graphical session, that window can’t be shown: with a paired phone, the request goes to kovra’s approval app on it (kovra Mobile, coming soon), where a person approves or denies it; with no paired phone, anything that needs an approval is refused, with a message saying so. The master key and the pairing are approved only at the Mac. kovra never falls back to an approval a script or an agent could give itself, and KOVRA_CONFIRMER doesn’t change that on a Mac (it only applies to development builds).

This has a deliberate consequence: high/prod actions can’t be automated — they require a person, at the Mac or on the paired phone, by design. So in CI:

  • low/medium secrets inject with no prompt — the everyday CI path: kovra run without high/prod values works unattended.
  • Anything that needs an approval — injecting a high/prod value, deleting or downgrading a critical secret — is refused, unless a person approves it on the paired phone. There’s no unattended bypass for kovra run; run it from the Mac’s desktop.

The Dashboard’s launch gate can be skipped for dev/CI/containers with --no-confirm (or KOVRA_UI_NO_CONFIRM=1).

jobs:
test:
runs-on: [self-hosted, macos]
env:
KOVRA_PASSPHRASE: ${ secrets.KOVRA_VAULT_PASSPHRASE }
steps:
- uses: actions/checkout@v4
- name: Run tests with injected secrets
run: kovra run --env dev -- npm test

kovra run --env dev resolves the committed .env.refs and injects the dev (non-high) values straight into npm test — nothing written to disk, argv, or the log.