chore(deploy): wire OPENAI_API_KEY + LLM_ENABLED into prod env for LLM chat
All checks were successful
CI / changes (push) Successful in 6s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 5s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
Deploy / changes (push) Successful in 5s
Deploy / build-worker (push) Successful in 28s
Deploy / build-backend (push) Successful in 30s
Deploy / build-frontend (push) Successful in 28s
Deploy / deploy (push) Successful in 1m1s

Forward OPENAI_API_KEY (Forgejo secret) and LLM_ENABLED (Forgejo actions
variable) into the SSH deploy and write them to backend/.env.runtime ONLY
when non-empty, so the LLM chat (#960/#957) stays dormant
(llm_enabled=False, openai_api_key=None) until BOTH are set in Forgejo.
Mirrors the OBJECTIVE_API_KEY wiring (env block + envs list + idempotent
.env.runtime grep-sed-or-printf), but guarded by [ -n ] so an unset
secret/var writes nothing. No literal key (refs only). Compose header
documents both as optional. .env.runtime is shared by backend+worker+beat.

Refs #960
This commit is contained in:
Light1YT 2026-06-09 13:51:41 +05:00
parent df9d54b532
commit 98ecdecb5b
2 changed files with 31 additions and 1 deletions

View file

@ -164,12 +164,18 @@ jobs:
GHCR_PAT: ${{ secrets.GHCR_PAT }} GHCR_PAT: ${{ secrets.GHCR_PAT }}
GLITCHTIP_BACKEND_DSN: ${{ secrets.GLITCHTIP_BACKEND_DSN }} GLITCHTIP_BACKEND_DSN: ${{ secrets.GLITCHTIP_BACKEND_DSN }}
OBJECTIVE_API_KEY: ${{ secrets.OBJECTIVE_API_KEY }} OBJECTIVE_API_KEY: ${{ secrets.OBJECTIVE_API_KEY }}
# LLM chat (#960/#957): оба UNSET по умолчанию → feature dormant
# (settings.llm_enabled=False, settings.openai_api_key=None).
# OPENAI_API_KEY — sensitive → secret. LLM_ENABLED — non-sensitive
# boolean toggle → actions variable (vars.*).
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ENABLED: ${{ vars.LLM_ENABLED }}
with: with:
host: ${{ secrets.DEPLOY_HOST }} host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }} username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }} key: ${{ secrets.DEPLOY_SSH_KEY }}
port: ${{ secrets.DEPLOY_PORT }} port: ${{ secrets.DEPLOY_PORT }}
envs: IMAGE_TAG,SENTRY_RELEASE_VAL,GHCR_PAT,GLITCHTIP_BACKEND_DSN,OBJECTIVE_API_KEY envs: IMAGE_TAG,SENTRY_RELEASE_VAL,GHCR_PAT,GLITCHTIP_BACKEND_DSN,OBJECTIVE_API_KEY,OPENAI_API_KEY,LLM_ENABLED
script: | script: |
set -euo pipefail set -euo pipefail
cd /opt/gendesign cd /opt/gendesign
@ -208,6 +214,25 @@ jobs:
else else
printf 'OBJECTIVE_API_KEY=%s\n' "$OBJECTIVE_API_KEY" >> backend/.env.runtime printf 'OBJECTIVE_API_KEY=%s\n' "$OBJECTIVE_API_KEY" >> backend/.env.runtime
fi fi
# LLM chat (#960/#957) — OpenAI key + enable toggle. В ОТЛИЧИЕ от
# OBJECTIVE_API_KEY пишем ТОЛЬКО при non-empty value: если Forgejo
# secret/var UNSET — ничего не пишем, app держит safe defaults
# (settings.llm_enabled=False, settings.openai_api_key=None) → feature
# dormant, без мусорной пустой строки `OPENAI_API_KEY=` в .env.runtime.
if [ -n "${OPENAI_API_KEY:-}" ]; then
if grep -q '^OPENAI_API_KEY=' backend/.env.runtime; then
sed -i "s|^OPENAI_API_KEY=.*|OPENAI_API_KEY=$OPENAI_API_KEY|" backend/.env.runtime
else
printf 'OPENAI_API_KEY=%s\n' "$OPENAI_API_KEY" >> backend/.env.runtime
fi
fi
if [ -n "${LLM_ENABLED:-}" ]; then
if grep -q '^LLM_ENABLED=' backend/.env.runtime; then
sed -i "s|^LLM_ENABLED=.*|LLM_ENABLED=$LLM_ENABLED|" backend/.env.runtime
else
printf 'LLM_ENABLED=%s\n' "$LLM_ENABLED" >> backend/.env.runtime
fi
fi
chmod 600 backend/.env.runtime chmod 600 backend/.env.runtime
# External network для Caddy + obsidian-stack share # External network для Caddy + obsidian-stack share

View file

@ -6,6 +6,11 @@
# POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD # POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD
# IMAGE_TAG (defaults to "latest") # IMAGE_TAG (defaults to "latest")
# #
# Optional (LLM chat #960/#957 — dormant until BOTH set; written to
# backend/.env.runtime by deploy.yml from Forgejo secret/var only when non-empty):
# OPENAI_API_KEY — Forgejo Actions secret (sensitive); unset → openai_api_key=None
# LLM_ENABLED — Forgejo Actions variable (bool, "true"); unset → llm_enabled=False
#
# In production the browser talks to Caddy on :80/:443. # In production the browser talks to Caddy on :80/:443.
# Caddy proxies /api/* and /health straight to backend, the rest to frontend. # Caddy proxies /api/* and /health straight to backend, the rest to frontend.
# So the frontend uses same-origin relative URLs — no NEXT_PUBLIC_API_BASE_URL needed. # So the frontend uses same-origin relative URLs — no NEXT_PUBLIC_API_BASE_URL needed.