From 98ecdecb5bfff2853df8f1f3e84a4943f65e912d Mon Sep 17 00:00:00 2001 From: Light1YT Date: Tue, 9 Jun 2026 13:51:41 +0500 Subject: [PATCH] chore(deploy): wire OPENAI_API_KEY + LLM_ENABLED into prod env for LLM chat 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 --- .forgejo/workflows/deploy.yml | 27 ++++++++++++++++++++++++++- docker-compose.prod.yml | 5 +++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml index f08b3336..0c883480 100644 --- a/.forgejo/workflows/deploy.yml +++ b/.forgejo/workflows/deploy.yml @@ -164,12 +164,18 @@ jobs: GHCR_PAT: ${{ secrets.GHCR_PAT }} GLITCHTIP_BACKEND_DSN: ${{ secrets.GLITCHTIP_BACKEND_DSN }} 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: host: ${{ secrets.DEPLOY_HOST }} username: ${{ secrets.DEPLOY_USER }} key: ${{ secrets.DEPLOY_SSH_KEY }} 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: | set -euo pipefail cd /opt/gendesign @@ -208,6 +214,25 @@ jobs: else printf 'OBJECTIVE_API_KEY=%s\n' "$OBJECTIVE_API_KEY" >> backend/.env.runtime 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 # External network для Caddy + obsidian-stack share diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 7753f281..87fc3bd3 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -6,6 +6,11 @@ # POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD # 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. # 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. -- 2.45.3