Skip to content

feat(secrets): drive backup-repo PAT through SOPS + bridge it to Hermes env#61

Merged
AlienWalker1995 merged 1 commit into
mainfrom
chore/sops-backup-pat
Jun 30, 2026
Merged

feat(secrets): drive backup-repo PAT through SOPS + bridge it to Hermes env#61
AlienWalker1995 merged 1 commit into
mainfrom
chore/sops-backup-pat

Conversation

@AlienWalker1995

Copy link
Copy Markdown
Owner

Problem

The last plaintext secret in the stack was GITHUB_PAT in .env (and embedded in the ordo-hermes-backup remote URL), used to push to the backup repo. Two issues:

  1. It violated "all secrets in SOPS" — plaintext in .env + in a git remote URL.
  2. Hermes couldn't use SOPS tokens it needs. Hermes expects tokens as env vars; SOPS secrets are deliberately kept out of its container, so when a token is "only in SOPS" Hermes concludes it has no access.

(The backup PAT is a different, classic token from the fine-grained SOPS github_pat, which has no access to the backup repo — so the backup push genuinely needs its own token.)

Fix — SOPS everywhere, surfaced via the entrypoint bridge

Bring the backup PAT under SOPS and deliver it to Hermes the way it expects (an env var), using the established Docker-secret → entrypoint-bridge pattern (same as DISCORD_BOT_TOKEN):

  • secrets/github_backup_pat.sops — encrypted classic PAT (committed encrypted; safe).
  • scripts/secrets/decrypt.sh — decrypts it to runtime/secrets/github_backup_pat.
  • docker-compose.yml — mounts it on hermes-gateway (/run/secrets/github_backup_pat) + GITHUB_BACKUP_PAT_FILE.
  • hermes/entrypoint.sh — bridges GITHUB_BACKUP_PAT_FILEGITHUB_BACKUP_PAT env var.
  • Backup remote → clean URL; a credential helper reads the SOPS-decrypted token (host + in-container). Plaintext GITHUB_PAT removed from .env.
  • Docs (secrets runbook, secrets/README, Hermes SOUL): all secrets are SOPS-driven and reach apps as bridged env vars — never plaintext in .env, never in a URL; if a token isn't in your env it must be wired (SOPS+mount+bridge), not pasted.

No secret values committed — only the encrypted .sops blob and path references.

Validation

  • Host git push to the backup repo works via the SOPS credential helper (throwaway-branch push/delete, no embedded token).
  • Bridge present in the rebuilt hermes image; all preconditions met in the live container (secret mounted + non-empty + _FILE env wired) — identical to the proven DISCORD_BOT_TOKEN bridge.
  • docker compose config validates; no plaintext secret in the staged diff.

Follow-up (operator action — can't be done headlessly)

The migrated classic PAT was previously exposed (plaintext in .env / remote URL), so rotate it: revoke the old token on GitHub, create a new one with Contents:write on ordo-hermes-backup, then sops re-encrypt secrets/github_backup_pat.sops + make decrypt-secrets. Because everything is now SOPS-driven, that rotation is a clean drop-in.

🤖 Generated with Claude Code

…Hermes' env

The only plaintext secret left in the stack was GITHUB_PAT in `.env` (and embedded
in the ordo-hermes-backup remote URL), used to push to the backup repo. It was a
different token from the SOPS `github_pat` (fine-grained) and the fine-grained one
has no access to the backup repo, so the backup push genuinely needs its own token.

Bring it under SOPS like everything else, and surface it to Hermes the way Hermes
expects — as an env var — via the established Docker-secret → entrypoint bridge:

- secrets/github_backup_pat.sops — encrypted classic PAT (age recipient).
- scripts/secrets/decrypt.sh — decrypt it to runtime/secrets/github_backup_pat.
- docker-compose.yml — mount it on hermes-gateway (/run/secrets/github_backup_pat)
  + GITHUB_BACKUP_PAT_FILE env.
- hermes/entrypoint.sh — bridge GITHUB_BACKUP_PAT_FILE -> GITHUB_BACKUP_PAT env var
  (same pattern as DISCORD_BOT_TOKEN), so Hermes finds the token in its environment
  instead of concluding "no access" when it's only in SOPS.
- docs (secrets runbook, secrets/README, Hermes SOUL): all secrets are SOPS-driven
  and reach apps as bridged env vars; never plaintext in .env, never in a URL.

The backup remote is now a clean URL authenticated by a credential helper that
reads the SOPS-decrypted token (works on host and in-container). The plaintext
GITHUB_PAT is removed from `.env`. No secret values are committed (only the
encrypted .sops blob and path references).

Validated: host `git push` to the backup works via the SOPS helper; the bridge is
present in the rebuilt hermes image with all preconditions met (secret mounted,
non-empty, _FILE env wired) — identical to the proven discord bridge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AlienWalker1995 AlienWalker1995 merged commit 6fc7caf into main Jun 30, 2026
5 checks passed
@AlienWalker1995 AlienWalker1995 deleted the chore/sops-backup-pat branch June 30, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant