fix(gtea): UPGRADE_SECRET_PREP hook — pre-insert lfs_jwt_secret with correct 43-char format
Some checks failed
continuous-integration/drone/push Build is failing

Blocker 4 fix: abra `secret generate --all` uses .env.sample for length hints; the
lfs-plain-gitea PR has SECRET_LFS_JWT_SECRET_VERSION=v1 COMMENTED OUT, so abra produces
a wrong-length secret. gitea requires exactly 43 chars (32 bytes base64 URL-safe); wrong
length → gitea fatals trying to save the JWT secret to the read-only Docker Config
app.ini → health check fails → swarm rolls back.

Fix: new UPGRADE_SECRET_PREP hook (meta.py) called before `abra secret generate --all`
in the upgrade path. abra's `--all` is idempotent (skips existing secrets), so the
correctly pre-inserted secret survives. gitea's recipe_meta.py implements the hook using
`docker secret create` directly to guarantee correct format regardless of .env.sample.

Also consumes machine-docs/BUILDER-INBOX.md (Adversary Blocker 4 digest).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
autonomic-bot
2026-06-15 21:46:28 +00:00
parent 1efab2e1e6
commit d832b353e4
7 changed files with 72 additions and 111 deletions

View File

@ -167,6 +167,17 @@ def env_get(domain: str, key: str) -> str | None:
return val
def secret_insert(domain: str, name: str, version: str, data: str, timeout: int = 60) -> None:
"""Insert a secret with an explicit value. Use when abra `generate --all` would use wrong
length/format (e.g. .env.sample has the spec commented out). check=False: silently no-ops if
the secret already exists (Docker Swarm secrets are immutable; caller must remove first)."""
_run(
["app", "secret", "insert", domain, name, version, data, "-n"],
timeout=timeout,
check=False,
)
def secret_generate(domain: str, timeout: int = 300) -> None:
# -m avoids the TTY/table (ioctl) path; output (which contains the generated values) is
# captured by _run and never logged. -C -o keep the recipe at the PR checkout (without -o it

View File

@ -261,6 +261,10 @@ def perform_upgrade(
print(f" upgrade-env: {k}={v}", flush=True)
abra.env_set(domain, k, v)
if upgrade_env:
# UPGRADE_SECRET_PREP: run before --all so any recipe-specific secrets are pre-inserted
# with the correct format/length. abra `generate --all` is idempotent (skips existing
# secrets), so a correctly pre-inserted secret survives the subsequent --all call.
meta_mod.upgrade_secret_prep(meta, meta_mod.hook_ctx(domain, meta, op="upgrade"))
# UPGRADE_EXTRA_ENV may introduce new SECRET_* vars (e.g. lfs_jwt_secret for the LFS overlay
# landing in a PR). Generate any missing secrets now — abra secret generate is idempotent
# (skips secrets that already exist) — before the chaos redeploy references them.

View File

@ -131,6 +131,13 @@ KEYS: tuple[Key, ...] = (
"Callable `(page, ctx)` driving Playwright to a safe, credential-free post-login view for the results-card screenshot (default: landing page).",
hook_params=("page", "ctx"),
),
Key(
"UPGRADE_SECRET_PREP",
"hook",
None,
"Callable `(ctx)` invoked after UPGRADE_EXTRA_ENV env_set but before `abra secret generate --all` in the upgrade path. Use to pre-insert secrets that `generate --all` would produce with wrong format (e.g. when the .env.sample spec is commented out).",
hook_params=("ctx",),
),
# (CHAOS_BASE_DEPLOY, OIDC_AT_INSTALL and SKIP_GENERIC were deleted in restructure P2:
# compose.ccci.yml is first-class + auto-chaos; install-time deps wiring is the only mode;
# the generic floor is suppressible only via the dev-only CCCI_SKIP_GENERIC* env form.)
@ -318,3 +325,10 @@ def extra_env(meta, ctx: HookCtx) -> dict[str, str]:
def upgrade_extra_env(meta, ctx: HookCtx) -> dict[str, str]:
"""Resolve UPGRADE_EXTRA_ENV (dict or callable(ctx)->dict) to the concrete env map."""
return _env_map(meta.UPGRADE_EXTRA_ENV, ctx)
def upgrade_secret_prep(meta, ctx: HookCtx) -> None:
"""Run UPGRADE_SECRET_PREP(ctx) if defined. Called before `abra secret generate --all` in the
upgrade path so recipes can pre-insert secrets with the correct format/length."""
if callable(meta.UPGRADE_SECRET_PREP):
meta.UPGRADE_SECRET_PREP(ctx)