From 42d31e38e4eb70eee29ecd63b6f76f371bfd9573 Mon Sep 17 00:00:00 2001 From: Bot Date: Wed, 2 Sep 2026 00:02:36 -0700 Subject: [PATCH] git stack: switch provision-secrets to Pattern B .env rewrite (test phase) + add git to bootstrap-tier guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context: git hosts the source of truth for every other stack's compose files, so in a disaster-recovery scenario it must be restorable from a flat git.yaml + git.env backup alone, with zero dependency on a running Swarm's Docker secret store (native Docker secrets can't be resolved until Swarm already exists, which is the circular dependency git.yaml would otherwise create). Path 2 (documented decision): Pattern B for git specifically, same mechanism the ai stack already uses. provision-secrets / git) case: - Previously created native Docker secrets (git_db_password, git_runner_token, git_mcp_access_token) via create-secrets.sh — leftover from an earlier, abandoned Pattern C attempt. - Now rewrites only the secret-bearing lines (GITEA__database__PASSWD, GITEA_RUNNER_REGISTRATION_TOKEN, GITEA_MCP_ACCESS_TOKEN) via grep -v + printf, mirroring the ai) case exactly. Also strips the legacy GITEA_ACCESS_TOKEN key name so the test file converges on the git.env.example-documented key. - TEST PHASE: target is git.env.pipelinetest, NOT git.env. The real git.env is never opened for writing by this step. First run seeds the test file from the real git.env (to carry over all non-secret lines), then only the 3 secret lines are refreshed on every push. - Real cutover (pointing git.yaml/stack-deploy at the generated file, then retiring git.env.pipelinetest) is a deliberate follow-up step after manually diffing the rendered output. deploy / bootstrap-tier guard: - Added git to the traefik|woodpecker|postgresql|secrets guard list. git.yaml changes now sync to the host but require a manual `stack-deploy.sh git` run, same as the other foundational stacks — prevents an auto-deploy of a bad git.yaml change from taking down Gitea before a human can look at it (Gitea itself is what every other pipeline needs to trigger a fix). --- .woodpecker/deploy.yml | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/.woodpecker/deploy.yml b/.woodpecker/deploy.yml index 424ff74..1f0163a 100644 --- a/.woodpecker/deploy.yml +++ b/.woodpecker/deploy.yml @@ -221,10 +221,36 @@ steps: ssh -o StrictHostKeyChecking=no root@$${SWARM_MANAGER_IP} "source /tmp/cs.sh create_or_update_secret 'gamma_auth_token' '$${GAMMA_AUTH_TOKEN}'";; git) - ssh -o StrictHostKeyChecking=no root@$${SWARM_MANAGER_IP} "source /tmp/cs.sh - create_or_update_secret 'git_db_password' '$${GIT_DB_PASSWORD}' - create_or_update_secret 'git_runner_token' '$${GIT_RUNNER_TOKEN}' - create_or_update_secret 'git_mcp_access_token' '$${GIT_MCP_ACCESS_TOKEN}'";; + # PATTERN B, DELIBERATE (see decision notes) — git hosts the source + # of truth for every other stack's compose files, so it must be + # restorable from a flat git.yaml + git.env backup alone, with zero + # dependency on a running Swarm's Docker secret store. Native Docker + # secrets (Pattern C) can't satisfy that: they only exist inside an + # already-running Swarm, which is exactly the circular dependency + # this stack can't have. Mirrors the ai) case's grep -v + printf + # rewrite-in-place approach, never sed (values may contain slash, + # dollar sign, ampersand). + # + # TEST PHASE: target is git.env.pipelinetest, NOT the real git.env. + # The real file is never opened for writing by this step. First run + # seeds the test file from the real git.env (carries over all + # non-secret lines untouched); every push after that only refreshes + # the 3 secret lines below. Also strips the legacy GITEA_ACCESS_TOKEN + # key name so the test file converges on the git.env.example- + # documented GITEA_MCP_ACCESS_TOKEN key. Cutover to the real file — + # and pointing git.yaml/stack-deploy at it — is a deliberate, + # separate follow-up after manually diffing this render. + ssh -o StrictHostKeyChecking=no root@$${SWARM_MANAGER_IP} "FILE=/volume1/docker/compose-files/git.env.pipelinetest + TMP=\$FILE.tmp.\$\$ + [ -f \$FILE ] || cp /volume1/docker/compose-files/git.env \$FILE + grep -vE '^(GITEA__database__PASSWD|GITEA_RUNNER_REGISTRATION_TOKEN|GITEA_MCP_ACCESS_TOKEN|GITEA_ACCESS_TOKEN)=' \$FILE > \$TMP 2>/dev/null || touch \$TMP + { cat \$TMP + printf 'GITEA__database__PASSWD=%s\n' '$${GIT_DB_PASSWORD}' + printf 'GITEA_RUNNER_REGISTRATION_TOKEN=%s\n' '$${GIT_RUNNER_TOKEN}' + printf 'GITEA_MCP_ACCESS_TOKEN=%s\n' '$${GIT_MCP_ACCESS_TOKEN}' + } > \$FILE + rm -f \$TMP + echo ' [OK] git.env.pipelinetest updated - real git.env untouched'";; homeassistant) ssh -o StrictHostKeyChecking=no root@$${SWARM_MANAGER_IP} "source /tmp/cs.sh create_or_update_secret 'homeassistant_frigate_rtsp_password' '$${HOMEASSISTANT_FRIGATE_RTSP_PASSWORD}' @@ -352,7 +378,7 @@ steps: # Bootstrap-tier guard: file synced to host, deploy is MANUAL case "$STACK" in - traefik|woodpecker|postgresql|secrets) + traefik|woodpecker|postgresql|secrets|git) echo " [BOOTSTRAP] $STACK: file synced. Deploy is MANUAL." echo " Run: bash /volume1/docker/compose-files/deploy/stack-deploy.sh $STACK" continue ;;