thermograph/.forgejo/workflows/secrets-guard.yml
Emi Griffith 7b2db07722 CI: port the split repos' workflows to per-domain path-filtered monorepo pipelines
One root workflow set replaces the four repos' copies (deleted -- root-only
is where Forgejo reads them, and dead copies are a trap): per-domain
build-push with explicit image paths (emi/thermograph/backend|frontend; the
old github.repository-derived path collides in a monorepo), path-filtered
per-domain beta/prod/dev deploys, a domain-input reusable build check, a
single always-reporting PR gate (path-filtered required checks deadlock
auto-merge), a new infra-sync pipeline (host checkout + secrets render on
infra/** pushes), and ports of secrets-guard / ops-cron /
observability-validate to monorepo paths.
2026-07-22 22:11:33 -07:00

41 lines
1.4 KiB
YAML

name: secrets-guard
# Fail the build if any infra/deploy/secrets/*.yaml is committed UNENCRYPTED.
# SOPS stores a `sops:` metadata block and wraps every value in ENC[...]; a
# plaintext leak has neither. This is the backstop against the classic
# "committed the decrypted file by accident" incident. .sops.yaml (the
# plaintext config) and README.md are not *.yaml under infra/deploy/secrets/,
# so they're correctly ignored.
#
# Deliberately NOT path-filtered: it's a ~1s grep, and a backstop that only
# runs when you expect it to isn't a backstop.
on:
pull_request:
push:
branches: [dev, main, release]
jobs:
encrypted:
runs-on: docker
steps:
- uses: actions/checkout@v4
- name: Assert infra/deploy/secrets/*.yaml are SOPS-encrypted
run: |
set -euo pipefail
shopt -s nullglob
files=(infra/deploy/secrets/*.yaml)
if [ ${#files[@]} -eq 0 ]; then
echo "no infra/deploy/secrets/*.yaml yet — nothing to check"
exit 0
fi
fail=0
for f in "${files[@]}"; do
if grep -q '^sops:' "$f" && grep -q 'ENC\[AES256_GCM' "$f"; then
echo "ok: $f is SOPS-encrypted"
else
echo "::error file=$f::NOT SOPS-encrypted — refusing to accept a plaintext secrets file"
fail=1
fi
done
exit $fail