feat(secrets): sync the app secrets from Infisical #505
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/BUNYIP-504-sync-secrets-infisical"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
compose.yml mounts every application secret from a file under ./secrets/ and the api reads it through the {NAME}_FILE convention (BUNYIP-38), but nothing populated those files from a secrets manager: deployed hosts kept them in sops and dev boxes generated throwaways. Infisical was already in use for the E2E account password only.
scripts/sync-secrets.nu renders the ./secrets/* files from the Infisical folder /bunyip/app. It syncs rather than fetches at runtime, so the containers keep reading /run/secrets/*, no secret re-enters the process environment, and a bunyip-api restart never depends on Infisical being reachable. No Rust changes.
Behaviour: authenticates with a machine identity via Universal Auth (INFISICAL_CLIENT_ID / INFISICAL_CLIENT_SECRET, or a pre-set INFISICAL_TOKEN that short-circuits the login) and fails naming the missing variable; reads one key per mapped secret with the
infisical secrets get ... --plainform already documented in docs/e2e.md; aborts before any write when a mapped key is absent, or empty where the table forbids empty, so a silent empty file can never turn RLS or a feature off; writes atomically at mode 0400 via a temp file in the same directory, skipping values that already match so a re-run leaves mtimes alone; prints no secret value in any mode; leaves ./secrets/oidc/*.pem alone.The mapping rule is that the Infisical key is the {NAME} of the compose {NAME}_FILE entry, and it is not hand-maintained on both sides:
sync-secrets.nu --self-testre-derives the table from the compose.yml secrets block and the service environment, exercises the write rules (0400, atomic, no-op re-run, no value printed, missing/empty key rejected), and runs as a check.yml step, so a new compose secret or a loosened write rule fails CI.Nushell reserves
envas a variable name, so the script's flag is --environment;just sync-secretsaccepts --env and --dry-run and translates.init-secrets.nu is unchanged as the dev-box path and gains a header pointer to the sibling script. Docs: new docs/secrets-infisical.md (machine identity setup, folder layout, mapping table, rotation flow and the reencrypt-secrets interaction for APP_ENCRYPTION_KEY), plus the compose.yml quick start, README self-host, docs/getting-started.md prerequisites, CLAUDE.md conventions, and the docs/e2e.md paragraph that described the wiring as a future item.
#BUNYIP-504
compose.yml mounts every application secret from a file under ./secrets/ and the api reads it through the {NAME}_FILE convention (BUNYIP-38), but nothing populated those files from a secrets manager: deployed hosts kept them in sops and dev boxes generated throwaways. Infisical was already in use for the E2E account password only. scripts/sync-secrets.nu renders the ./secrets/* files from the Infisical folder /bunyip/app. It syncs rather than fetches at runtime, so the containers keep reading /run/secrets/*, no secret re-enters the process environment, and a bunyip-api restart never depends on Infisical being reachable. No Rust changes. Behaviour: authenticates with a machine identity via Universal Auth (INFISICAL_CLIENT_ID / INFISICAL_CLIENT_SECRET, or a pre-set INFISICAL_TOKEN that short-circuits the login) and fails naming the missing variable; reads one key per mapped secret with the `infisical secrets get ... --plain` form already documented in docs/e2e.md; aborts before any write when a mapped key is absent, or empty where the table forbids empty, so a silent empty file can never turn RLS or a feature off; writes atomically at mode 0400 via a temp file in the same directory, skipping values that already match so a re-run leaves mtimes alone; prints no secret value in any mode; leaves ./secrets/oidc/*.pem alone. The mapping rule is that the Infisical key is the {NAME} of the compose {NAME}_FILE entry, and it is not hand-maintained on both sides: `sync-secrets.nu --self-test` re-derives the table from the compose.yml secrets block and the service environment, exercises the write rules (0400, atomic, no-op re-run, no value printed, missing/empty key rejected), and runs as a check.yml step, so a new compose secret or a loosened write rule fails CI. Nushell reserves `env` as a variable name, so the script's flag is --environment; `just sync-secrets` accepts --env and --dry-run and translates. init-secrets.nu is unchanged as the dev-box path and gains a header pointer to the sibling script. Docs: new docs/secrets-infisical.md (machine identity setup, folder layout, mapping table, rotation flow and the reencrypt-secrets interaction for APP_ENCRYPTION_KEY), plus the compose.yml quick start, README self-host, docs/getting-started.md prerequisites, CLAUDE.md conventions, and the docs/e2e.md paragraph that described the wiring as a future item. #BUNYIP-504