From 0827b687c0f2f950d96c4549d45832e5ed491e77 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 9 Jul 2026 04:44:11 +0000 Subject: [PATCH 1/3] fix(ci): stub RAG_QUERY_HASH_SECRET in deployment boot smoke Production instrumentation now requires a query-hash secret (PIA-2). The deployment boot smoke starts next start in production mode but only stubbed Supabase/OpenAI placeholders, so main CI verify failed after the privacy guard landed. Add a matching placeholder so the smoke can still verify /api/local-project-id without a real secret. Co-authored-by: BigSimmo --- scripts/deployment-boot-smoke.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/deployment-boot-smoke.mjs b/scripts/deployment-boot-smoke.mjs index 66950e5b0..015efc3b1 100644 --- a/scripts/deployment-boot-smoke.mjs +++ b/scripts/deployment-boot-smoke.mjs @@ -124,6 +124,8 @@ async function bootSmoke() { // fail with real errors, but /api/local-project-id does not. SUPABASE_SERVICE_ROLE_KEY: process.env.SUPABASE_SERVICE_ROLE_KEY ?? "placeholder-ci-service-role", OPENAI_API_KEY: process.env.OPENAI_API_KEY ?? "placeholder-ci-openai", + // instrumentation.ts requireQueryHashSecret() needs a min-16-char value in production. + RAG_QUERY_HASH_SECRET: process.env.RAG_QUERY_HASH_SECRET ?? "placeholder-ci-rag-query-hash-secret", }, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, From eb91e1420cff667155dd1fedf4753f3a18b6a3af Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 9 Jul 2026 05:58:58 +0000 Subject: [PATCH 2/3] fix(ci): require RAG_QUERY_HASH_SECRET in deployment boot smoke Address Codex review: wire the query-hash secret through CI as a required repository secret instead of stubbing a placeholder in the smoke script. Also document the secret alongside the other boot-smoke GitHub secrets. Co-authored-by: BigSimmo --- .github/workflows/ci.yml | 1 + docs/deployment-architecture.md | 2 +- docs/observability-slos.md | 3 ++- scripts/deployment-boot-smoke.mjs | 12 +++++------- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b54c429b6..7543490b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,6 +87,7 @@ jobs: env: SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + RAG_QUERY_HASH_SECRET: ${{ secrets.RAG_QUERY_HASH_SECRET }} run: npm run check:deployment-readiness # Chromium browser smoke in parallel with verify, so the slowest check no diff --git a/docs/deployment-architecture.md b/docs/deployment-architecture.md index 579f9366a..3bb2ccbac 100644 --- a/docs/deployment-architecture.md +++ b/docs/deployment-architecture.md @@ -184,7 +184,7 @@ Operational rules that follow: | `OPENAI_API_KEY` | **critical** | runtime | host secret store; GitHub repo secret | | `SUPABASE_PROJECT_REF` / `SUPABASE_PROJECT_NAME` | low | runtime | plain env (pins `check:supabase-project`) | | `INDEXING_V3_AGENT_SECRET` | high | runtime | Supabase Edge Function secrets | -| `RAG_QUERY_HASH_SECRET` | high | runtime | host secret store | +| `RAG_QUERY_HASH_SECRET` | high | runtime | host secret store; GitHub repo secret (CI boot smoke) | | `E2E_USER_EMAIL` / `E2E_USER_PASSWORD` | medium | CI only | GitHub repo secrets | Rules: diff --git a/docs/observability-slos.md b/docs/observability-slos.md index 67648b28f..313b12d22 100644 --- a/docs/observability-slos.md +++ b/docs/observability-slos.md @@ -148,7 +148,8 @@ Failing loudly: Required repo secrets (same ones CI's deployment boot smoke already uses, plus the eval owner): `SUPABASE_SERVICE_ROLE_KEY`, `OPENAI_API_KEY`, -`E2E_USER_EMAIL` (resolved to the eval owner via `RAG_EVAL_OWNER_EMAIL`). +`RAG_QUERY_HASH_SECRET`, `E2E_USER_EMAIL` (resolved to the eval owner via +`RAG_EVAL_OWNER_EMAIL`). The workflow preflights these and fails with an explicit message when absent. Operational notes: diff --git a/scripts/deployment-boot-smoke.mjs b/scripts/deployment-boot-smoke.mjs index 015efc3b1..9ce7b56f3 100644 --- a/scripts/deployment-boot-smoke.mjs +++ b/scripts/deployment-boot-smoke.mjs @@ -27,7 +27,7 @@ const pollDelayMs = parsePositiveInt("DEPLOY_SMOKE_POLL_DELAY_MS", 1000); const logRoot = mkdtempSync(resolve(tmpdir(), "clinical-kb-deploy-smoke-")); const logPath = resolve(logRoot, "deploy-smoke.log"); const nextBin = resolve(projectRoot, "node_modules", "next", "dist", "bin", "next"); -const requiredProductionEnv = ["SUPABASE_SERVICE_ROLE_KEY", "OPENAI_API_KEY"]; +const requiredProductionEnv = ["SUPABASE_SERVICE_ROLE_KEY", "OPENAI_API_KEY", "RAG_QUERY_HASH_SECRET"]; if (!existsSync(nextBin)) { throw new Error(`Next.js binary not found at: ${nextBin}`); @@ -118,14 +118,12 @@ async function bootSmoke() { ...process.env, PORT: String(port), NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL ?? "https://sjrfecxgysukkwxsowpy.supabase.co", - // instrumentation.ts register() requires these in production mode; provide - // placeholder values so the boot-smoke can verify server identity without - // needing real secrets. Routes that actually use Supabase/OpenAI will still - // fail with real errors, but /api/local-project-id does not. + // instrumentation.ts register() requires these in production mode. Supabase + // and OpenAI keep placeholder fallbacks for local smoke runs; the query-hash + // secret is required upfront via requiredProductionEnv (no placeholder) so + // main/release CI cannot pass without the real repository secret. SUPABASE_SERVICE_ROLE_KEY: process.env.SUPABASE_SERVICE_ROLE_KEY ?? "placeholder-ci-service-role", OPENAI_API_KEY: process.env.OPENAI_API_KEY ?? "placeholder-ci-openai", - // instrumentation.ts requireQueryHashSecret() needs a min-16-char value in production. - RAG_QUERY_HASH_SECRET: process.env.RAG_QUERY_HASH_SECRET ?? "placeholder-ci-rag-query-hash-secret", }, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, From 1a23bd280a8a9f14f45e793e8f4cdc5699d0c386 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 9 Jul 2026 06:33:26 +0000 Subject: [PATCH 3/3] docs: keep eval canary secret list aligned with workflow preflight The observability SLO doc incorrectly listed RAG_QUERY_HASH_SECRET as required for eval-canary.yml; only boot smoke needs it. Trim the doc to match the workflow's actual preflight checks. Co-authored-by: BigSimmo --- docs/observability-slos.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/observability-slos.md b/docs/observability-slos.md index 313b12d22..519458bd7 100644 --- a/docs/observability-slos.md +++ b/docs/observability-slos.md @@ -146,10 +146,9 @@ Failing loudly: `eval-canary` (or comments on the existing open one), so a regression creates a durable, assignable artifact rather than a missed notification. -Required repo secrets (same ones CI's deployment boot smoke already uses, -plus the eval owner): `SUPABASE_SERVICE_ROLE_KEY`, `OPENAI_API_KEY`, -`RAG_QUERY_HASH_SECRET`, `E2E_USER_EMAIL` (resolved to the eval owner via -`RAG_EVAL_OWNER_EMAIL`). +Required repo secrets: `SUPABASE_SERVICE_ROLE_KEY`, `OPENAI_API_KEY`, +`E2E_USER_EMAIL` (resolved to the eval owner via `RAG_EVAL_OWNER_EMAIL`). +The workflow preflights these and fails with an explicit message when absent. The workflow preflights these and fails with an explicit message when absent. Operational notes: