feat(secrets): drive backup-repo PAT through SOPS + bridge it to Hermes env#61
Merged
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The last plaintext secret in the stack was
GITHUB_PATin.env(and embedded in theordo-hermes-backupremote URL), used to push to the backup repo. Two issues:.env+ in a git remote URL.(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 toruntime/secrets/github_backup_pat.docker-compose.yml— mounts it onhermes-gateway(/run/secrets/github_backup_pat) +GITHUB_BACKUP_PAT_FILE.hermes/entrypoint.sh— bridgesGITHUB_BACKUP_PAT_FILE→GITHUB_BACKUP_PATenv var.GITHUB_PATremoved from.env.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
.sopsblob and path references.Validation
git pushto the backup repo works via the SOPS credential helper (throwaway-branch push/delete, no embedded token)._FILEenv wired) — identical to the provenDISCORD_BOT_TOKENbridge.docker compose configvalidates; 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 withContents:writeonordo-hermes-backup, thensopsre-encryptsecrets/github_backup_pat.sops+make decrypt-secrets. Because everything is now SOPS-driven, that rotation is a clean drop-in.🤖 Generated with Claude Code