Skip to content

fix(compose): forward INTERNAL_API_SECRET to prod mcp-server + CORS/SSH/LOG levers to prod backend (#722)#1256

Open
AndriiPasternak31 wants to merge 2 commits into
devfrom
feature/722-prod-compose-env-gaps
Open

fix(compose): forward INTERNAL_API_SECRET to prod mcp-server + CORS/SSH/LOG levers to prod backend (#722)#1256
AndriiPasternak31 wants to merge 2 commits into
devfrom
feature/722-prod-compose-env-gaps

Conversation

@AndriiPasternak31

Copy link
Copy Markdown
Contributor

Summary

Closes the two remaining prod packaging-gap findings from #722's /validate-config report. There is no env_file: in either compose, so a var forwarded in docker-compose.yml but absent from docker-compose.prod.yml is a dead lever in prod — the missing environment: entry never reaches the container.

3 of the 5 original findings were already fixed (GOOGLE_API_KEY, FRONTEND_URL dup, TRINITY_DATA_PATH); this PR addresses the 2 that remained, plus a zero-behavior-change frontend cleanup surfaced during review.

What changed

File / block Change
docker-compose.prod.ymlmcp-server + INTERNAL_API_SECRET=${INTERNAL_API_SECRET} (no default, matches backend/scheduler prod style)
docker-compose.prod.ymlbackend + EXTRA_CORS_ORIGINS, + SSH_HOST, + LOG_ARCHIVE_ENABLED / LOG_RETENTION_DAYS / LOG_CLEANUP_HOUR (mirror dev)
src/frontend/src/components/HostTelemetry.vue Drop dead import.meta.env.VITE_API_BASE ref → API_BASE = ''

Corrected failure mode (Finding 1)

The original "every audit 401s" framing was wrong. The prod mcp-server lacked INTERNAL_API_SECRET, so src/mcp-server/src/audit.ts postAudit hits if (!INTERNAL_SECRET) return; and never POSTsall MCP tool-call audit (SEC-001) is silently dropped in prod (no request, so no 401). Backend + scheduler already receive the secret in prod, so forwarding it to mcp-server makes both ends share the same value (routers/internal.py returns 403 only on a mismatch).

Design notes

  • LOG_ARCHIVE_PATH is intentionally omitted — the code default /data/archives (routers/logs.py, archive_storage.py) already lands in the TRINITY_DATA_PATH bind mount (/data), so no new volume is needed.
  • HostTelemetry: VITE_API_BASE was never set anywhere, so API_BASE was always ''; the single Axios client (api.js) uses baseURL: '' (relative, same-origin). The naive "point it at VITE_API_URL" fix would be a regression (VITE_API_URL build-defaults to http://localhost:8000). Not routed through api.js to preserve the 3s timeout / no 401-redirect / raw-fetch response shape (deferred as an Invariant-security: Fix token logging and add HTML reports to gitignore #7 follow-up).

Verification

  • docker compose -f docker-compose.prod.yml config and the +enterprise overlay render clean
  • ✅ JSON-resolution proof: all 6 vars resolve into the correct service blocks (no cross-block leak; LOG_ARCHIVE_PATH absent; backend/scheduler INTERNAL_API_SECRET untouched)
  • vite build passes
  • ⏳ Live sibling-stack functional audit-row proof (baseline no-row → post-fix source='mcp' row + 200) not run in this PR — the mechanism is proven at the compose layer (audit.ts/internal.py unchanged)

Deferred follow-ups (flagged, not dropped)

Fixes #722

🤖 Generated with Claude Code

AndriiPasternak31 and others added 2 commits June 17, 2026 23:46
…SH/LOG levers to prod backend (#722)

#722's /validate-config report flagged 5 config issues; 3 were already fixed
(GOOGLE_API_KEY, FRONTEND_URL dup, TRINITY_DATA_PATH). The 2 remaining are the
"prod packaging gap" class: a var forwarded in docker-compose.yml but absent
from docker-compose.prod.yml. There is no env_file: in either compose, so a
missing environment: entry = a dead lever in prod.

docker-compose.prod.yml:
- mcp-server: add INTERNAL_API_SECRET (SEC-001, no default — matches
  backend/scheduler prod style). Corrected failure mode: without it,
  src/mcp-server/src/audit.ts postAudit early-returns (`if (!INTERNAL_SECRET)
  return;`) and ALL MCP tool-call audit is silently dropped in prod — no
  request is sent (so not "every audit 401s"). Backend + scheduler already
  receive the secret in prod, so forwarding it to mcp-server makes both ends
  share the same value (internal.py returns 403 only on a *mismatch*).
- backend: add EXTRA_CORS_ORIGINS (config.py), SSH_HOST (ssh_service.py), and
  LOG_ARCHIVE_ENABLED/LOG_RETENTION_DAYS/LOG_CLEANUP_HOUR (log_archive_service.py).
  LOG_ARCHIVE_PATH is intentionally omitted — the code default /data/archives
  lands in the TRINITY_DATA_PATH bind mount (/data), so no new volume is needed.

src/frontend/src/components/HostTelemetry.vue:
- Drop the dead `import.meta.env.VITE_API_BASE` reference (the var is never set
  anywhere, so API_BASE was always ''); hardcode `API_BASE = ''` to match
  api.js `baseURL: ''` (relative, same-origin). Zero behavior change. The naive
  "point it at VITE_API_URL" fix would be a regression (VITE_API_URL
  build-defaults to http://localhost:8000).

Verification: `docker compose -f docker-compose.prod.yml config` and the
+enterprise overlay both render clean; the 6 added vars resolve into the correct
service blocks (no cross-block leak); `vite build` passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…archival runs (#722)

The PR forwarded LOG_ARCHIVE_ENABLED/LOG_RETENTION_DAYS/LOG_CLEANUP_HOUR to the
prod backend, but archival still no-opped: log_archive_service.py reads
LOG_DIR=/data/logs, and the prod backend mounted only the trinity-data bind
mount at /data, never Vector's trinity-logs volume (dev mounts it at
docker-compose.yml:145). Add the same read-only mount so the forwarded knobs
actually take effect — completing the #1039 packaging-gap fix one layer down.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AndriiPasternak31 AndriiPasternak31 requested a review from vybe June 17, 2026 23:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant