From f48b5606df2f4cd0001160aead15a45247b85fe4 Mon Sep 17 00:00:00 2001 From: Suriyakumarvijayanayagam Date: Fri, 28 Aug 2026 17:12:34 +0530 Subject: [PATCH] Make the local-db overlay actually start, and pass the model credential through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The overlay had never been run against a fresh volume. Two faults, the first hiding the second: - postgres:16-alpine ships libssl but not the openssl CLI, so the first-boot certificate generation exited 127 in a restart loop. It failed invisibly: the 2>/dev/null on the openssl line swallowed sh's "not found" as well, so `docker logs` was completely empty. openssl is now installed on the boot that generates the certificate, inside the same guard, so a restart still needs no network. - the certificate was written into /var/lib/postgresql/data BEFORE initdb ran, and initdb refuses to initialise a directory that is not empty. That made a fresh volume unstartable regardless of the first fault. The certificate now lives in its own volume, which keeps it persistent — the reason it was put in the data directory — without touching the cluster's. Separately, docker-compose.yml did not pass ANTHROPIC_API_KEY to the api container, so a compose deployment could never register the agent run routes: POST /agents/{id}/runs answered 404 and /version reported two endpoints fewer. The model and embedder variables are now passed through, all defaulting to empty so a deployment without them behaves exactly as it did. Verified on a fresh volume: 56/56 verify-deploy checks against the resulting stack, including a live agent run and 34 chunks embedded through Ollama. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PJvibeSc1JYXjatankqM1g --- infrastructure/docker-compose.local-db.yml | 20 ++++++++++++++++---- infrastructure/docker-compose.yml | 17 +++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/infrastructure/docker-compose.local-db.yml b/infrastructure/docker-compose.local-db.yml index 5cd97fb..c97114a 100644 --- a/infrastructure/docker-compose.local-db.yml +++ b/infrastructure/docker-compose.local-db.yml @@ -48,12 +48,21 @@ services: - -c - | set -e - CERT=/var/lib/postgresql/data/server.crt - KEY=/var/lib/postgresql/data/server.key + # NOT in /var/lib/postgresql/data: initdb refuses to initialise a + # directory that is not empty, so writing the certificate there first + # means a fresh volume can never come up at all. Its own volume keeps + # the certificate persistent without touching the cluster's. + CERT=/var/lib/postgresql/certs/server.crt + KEY=/var/lib/postgresql/certs/server.key if [ ! -f "$$CERT" ]; then - mkdir -p /var/lib/postgresql/data + mkdir -p /var/lib/postgresql/certs + # postgres:16-alpine ships libssl but not the openssl CLI, so this + # has to be installed before it can be called. Inside the if, so it + # only happens on the boot that actually generates the certificate + # and a restart does not need the network. + command -v openssl >/dev/null || apk add --no-cache openssl openssl req -new -x509 -days 3650 -nodes -text \ - -out "$$CERT" -keyout "$$KEY" -subj "/CN=postgres" 2>/dev/null + -out "$$CERT" -keyout "$$KEY" -subj "/CN=postgres" chmod 0600 "$$KEY" chown postgres:postgres "$$CERT" "$$KEY" fi @@ -61,6 +70,7 @@ services: -c ssl=on -c ssl_cert_file="$$CERT" -c ssl_key_file="$$KEY" volumes: - postgres-data:/var/lib/postgresql/data + - postgres-certs:/var/lib/postgresql/certs healthcheck: # -U and -d so this reports on the application's database, not on # whatever `postgres` happens to be reachable. @@ -99,3 +109,5 @@ services: volumes: postgres-data: driver: local + postgres-certs: + driver: local diff --git a/infrastructure/docker-compose.yml b/infrastructure/docker-compose.yml index 4bfd0b1..ff6c948 100644 --- a/infrastructure/docker-compose.yml +++ b/infrastructure/docker-compose.yml @@ -88,6 +88,23 @@ services: <<: *database-env APP_ENV: ${APP_ENV:-production} LOG_LEVEL: ${LOG_LEVEL:-info} + # The agent run routes are not registered without this, so a deployment + # without it answers 404 on /agents/{id}/runs and reports three fewer + # endpoints on /version. Empty by default: absent is a working API + # without Owliver, which is a legitimate way to run this. + ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-} + MODEL_FAST: ${MODEL_FAST:-} + MODEL_BALANCED: ${MODEL_BALANCED:-} + MODEL_DEEP: ${MODEL_DEEP:-} + # voyage | ollama | lexical. Unset means ingest stores chunks that are + # keyword-searchable only — see the ingest output. + EMBED_PROVIDER: ${EMBED_PROVIDER:-} + EMBED_MODEL: ${EMBED_MODEL:-} + EMBED_DIMENSIONS: ${EMBED_DIMENSIONS:-} + # Ollama runs on the HOST, so "localhost" here would be this container. + # host.docker.internal is what reaches the host from inside it. + EMBED_BASE_URL: ${EMBED_BASE_URL:-} + VOYAGE_API_KEY: ${VOYAGE_API_KEY:-} # 0.0.0.0 so the published port actually reaches the process. The binary # defaults to 127.0.0.1, which inside a container means "nobody". HTTP_HOST: 0.0.0.0