Same two scoped changes as PR #15's rebase, now applied on a branch cut
from TODAY's main so the merge base is current (PR #15 became
unmergeable — its 09-03 merge base predated main's heavy hand-edits):
1. ai) case -> `python3 deploy/provision-stack.py ai` (one line). Retires
main's heredoc with its live drift: AI_LITELLM_POSTGRES_PASSWORD
printed twice (one copy from retired AI_LITELLM_DB_PASSWORD), stray
legacy AI_WEBUI_SECRET_KEY, and the WEB_UI/WEBUI shell-var mismatch
that renders an EMPTY OAuth client secret into ai.env.
2. env block ai section: normalized to exact template placeholder names,
added AI_MCPO_API_KEY (NEW Woodpecker secret required pre-merge),
pruned now-template-literal vars.
apk gains python3 py3-yaml. Everything else byte-matches current main.
Dollar-escape audit done per header lesson.
Carried over from secrets-provisioning-v2 (PR #15), content identical.
Whole-file template render (hard-fail naming missing vars), env + Docker
secrets shipped via ssh stdin only, sha256-checksum skip-if-unchanged,
never prints a value. Stacks absent from the manifest exit 0 so legacy
case-entries keep handling them.
Carried over from secrets-provisioning-v2 (PR #15) post-rebase. Key names
match exactly what current ai/ai.yaml references; MCPO_API_KEY stays
unprefixed (ai.yaml consumes it unprefixed for both mcpo services).
Placeholder names match the CI env vars declared in deploy.yml's
provision-secrets block, including the normalized
AI_OPEN_WEBUI_OAUTH_CLIENT_SECRET (fixing main's WEB_UI/WEBUI mismatch
that currently renders an EMPTY OAuth client secret into ai.env).
NEW Woodpecker secret required before merge: ai_mcpo_api_key.
Carried over from secrets-provisioning-v2 (PR #15), which became
unmergeable after heavy parallel hand-edits to main moved the merge base
too far. Content identical to v2.