Operator correction: "sop, wg, and any other tool requirement is supposed to be
baked into the devcontainer."
My previous commit discovered that `wg` existed only on the host, `sops` only in
the container, and `qrencode` on neither -- and fixed it the wrong way, by
splitting every step of the key procedure across the boundary and telling the
operator to `dnf install qrencode` on their workstation. That breaks CLAUDE.md §5
and the devcontainer README's "Don't install the toolchain on the host", produces
a procedure that cannot be reproduced in CI, and is miserable to follow.
wireguard-tools + qrencode are now distro packages in the Containerfile. Both are
in Fedora 44's repos (wireguard-tools 1.0.20260223 -- the same upstream version as
the image this component runs -- and qrencode 4.1.1), unpinned like every other
dnf package there: the pinned thing is the Fedora base, and neither is a gate tool
whose version changes what green means.
Three things got SIMPLER rather than merely relocated, which is the tell that the
rule was right:
* Step 2 is one pipeline in one shell -- `sops set ... "$(wg genkey)"` writes the
key straight into the already-encrypted document. No staged copy in .cache, no
`*.key`-suffix warning, no sha256 comparison to prove the right bytes landed.
* new-peer.sh derives the server public key from wg-server-key.sops.yaml itself
(`sops -d --extract | wg pubkey`), so there is no local key copy to keep in
step with the encrypted one, and no magic host path it must live at.
* `.cache/` is gitignored at the repo root (mirroring infra/ansible/.gitignore),
giving the container a persistent non-committable scratch dir. new-peer.sh
writes profiles to .cache/wg-peers/ -- necessary because the repo bind-mount is
the container's only persistent read-write mount, so a profile in /tmp there is
gone before it can reach a desktop. Its blanket "refuse to write inside the
checkout" guard is now a `git check-ignore` test of the real property.
Verified by execution, not reasoning: the image rebuilds; wg/qrencode/sops all
resolve in it; `sops -d | wg pubkey` runs in one shell; new-peer.sh refuses the
REPLACE-ME placeholder with an actionable message; and a full run with a throwaway
server key renders a correct profile at 0600 under a 0700 gitignored dir, prints
the QR, and refuses a non-ignored destination inside the repo.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
55 lines
1.7 KiB
Plaintext
55 lines
1.7 KiB
Plaintext
# OS / editor
|
|
.DS_Store
|
|
*.swp
|
|
*~
|
|
.idea/
|
|
.vscode/
|
|
|
|
# Secrets — SOPS-encrypted only; never commit plaintext (spec docs/07)
|
|
*.dec.yaml
|
|
*.decrypted.*
|
|
*.key
|
|
age.key
|
|
*.kubeconfig
|
|
kubeconfig
|
|
|
|
# IaC state / local runtime
|
|
.terraform/
|
|
*.tfstate
|
|
*.tfstate.*
|
|
.terraform.lock.hcl
|
|
*.tfvars
|
|
!*.example.tfvars
|
|
# tofu apply/plan run logs (tee'd locally; never commit)
|
|
apply.log
|
|
plan.log
|
|
|
|
# Test / build artifacts
|
|
/results/
|
|
/reports/
|
|
*.junit.xml
|
|
coverage/
|
|
|
|
# RETIRED plaintext Tofu secret files. Superseded by the COMMITTED, SOPS/age-encrypted
|
|
# infra/tofu/secrets.sops.env + the wrapper infra/tofu/tf.sh (see REMOTE-STATE.md). These
|
|
# lines are KEPT as a safety net so any leftover plaintext copy on an operator's machine can
|
|
# NEVER be committed; delete the local files once you've migrated to the encrypted flow.
|
|
infra/tofu/backend.hcl
|
|
infra/tofu/.r2.env
|
|
|
|
# Operator scratch, writable from inside the dev container (the repo is its only persistent
|
|
# read-write mount). Holds things that must never be committed: a staged copy of the SOPS age or
|
|
# WireGuard key, rendered VPN client profiles (infra/vpn-ingress/new-peer.sh writes here by
|
|
# default). `infra/ansible/.gitignore` already does this for its own .cache/; this is the same
|
|
# convention at the root. Do NOT rely on `*.key` alone to protect a staged key — that only covers
|
|
# one filename shape, which is why this rule exists.
|
|
.cache/
|
|
|
|
# Claude Code local scratch: agent worktrees + session state. Nothing here is tracked;
|
|
# ignoring it keeps `git add -A` from staging embedded worktree repos and keeps the lint
|
|
# stage (which scans untracked files) from tripping on .claude/worktrees/.
|
|
.claude/
|
|
|
|
# Vendored ansible collections (installed by ansible-galaxy for node re-provision; not tracked or linted)
|
|
infra/ansible/collections/
|