diff --git a/.superpowers/sdd/2026-08-08-internal-qdrant-ollama/task-3-report.md b/.superpowers/sdd/2026-08-08-internal-qdrant-ollama/task-3-report.md index fcf1d055..82bb1f00 100644 --- a/.superpowers/sdd/2026-08-08-internal-qdrant-ollama/task-3-report.md +++ b/.superpowers/sdd/2026-08-08-internal-qdrant-ollama/task-3-report.md @@ -90,3 +90,43 @@ Reason: the new typed internal semantic runtime config had to flow from backend ## Concerns - Host validation currently permits both `http` and `https` on the allowed internal hosts. That keeps the configuration flexible, but if the installation contract intended `http` only, that restriction is not enforced here. + +## Fix round 1/5 + +Scope: + +- moved schema-v3 internal embeddings under `resources.embeddings` +- enforced `http`-only internal semantic URLs + +RED evidence: + +`cd backend && npx vitest run test/workspace-runtime-renderer.test.ts test/config.test.ts` + +Observed failures on `bc8afe0`: + +- `workspace-runtime-renderer.test.ts` + - schema-v3 output omitted `resources.embeddings` + - schema-v3 still exposed top-level `embeddings` +- `config.test.ts` + - `https://qdrant:6333` was accepted + +GREEN evidence: + +`cd backend && npx vitest run test/workspace-runtime-renderer.test.ts test/config.test.ts` + +Result: + +- 2 test files passed +- 16 tests passed + +Typecheck: + +`cd backend && npx tsc --noEmit -p .` + +Result: + +- passed + +Updated concerns: + +- none for this round beyond future tightening if exact-port rejection is later requested explicitly. diff --git a/backend/src/config.ts b/backend/src/config.ts index 1cb1d12f..ee7193d7 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -125,7 +125,7 @@ function internalServiceUrl( throw new Error(`${label} configuration is invalid`); } if ( - (parsed.protocol !== "http:" && parsed.protocol !== "https:") + parsed.protocol !== "http:" || parsed.username.length > 0 || parsed.password.length > 0 || parsed.pathname !== "/" diff --git a/backend/src/workspaces/runtime-renderer.ts b/backend/src/workspaces/runtime-renderer.ts index bf4a0397..9c7a32a2 100644 --- a/backend/src/workspaces/runtime-renderer.ts +++ b/backend/src/workspaces/runtime-renderer.ts @@ -140,18 +140,18 @@ export function renderRuntimeConfig( ...(installation.profile === undefined ? {} : { profile: installation.profile }), language: descriptor.workspace.language, database, - embeddings: { - provider: "ollama_internal", - base_url: semanticRuntime.internalEmbeddingUrl, - model: semanticRuntime.internalEmbeddingModel, - dimensions: semanticRuntime.internalEmbeddingDimensions, - }, resources: { vector: { engine: "qdrant", base_url: semanticRuntime.internalQdrantUrl, collection: descriptor.semantic_index.vector_store.collection, }, + embeddings: { + provider: "ollama_internal", + base_url: semanticRuntime.internalEmbeddingUrl, + model: semanticRuntime.internalEmbeddingModel, + dimensions: semanticRuntime.internalEmbeddingDimensions, + }, }, roots: paths, paths, diff --git a/backend/test/config.test.ts b/backend/test/config.test.ts index a61577ab..52f4488d 100644 --- a/backend/test/config.test.ts +++ b/backend/test/config.test.ts @@ -58,6 +58,10 @@ test("loadConfig accepts only the allowed internal semantic runtime hosts", () = .toThrow(/internal.*qdrant|host validation|invalid/i); expect(() => loadConfig({ THT_INTERNAL_EMBEDDING_URL: "http://example.com:11434" })) .toThrow(/internal.*embedding|host validation|invalid/i); + expect(() => loadConfig({ THT_INTERNAL_QDRANT_URL: "https://qdrant:6333" })) + .toThrow(/internal.*qdrant|invalid/i); + expect(() => loadConfig({ THT_INTERNAL_EMBEDDING_URL: "https://embedding:11434" })) + .toThrow(/internal.*embedding|invalid/i); }); test("loadConfig enables the legacy workspace request only through explicit local mode", () => { diff --git a/backend/test/workspace-runtime-renderer.test.ts b/backend/test/workspace-runtime-renderer.test.ts index 47446838..166bf2b6 100644 --- a/backend/test/workspace-runtime-renderer.test.ts +++ b/backend/test/workspace-runtime-renderer.test.ts @@ -193,13 +193,14 @@ test("fails closed for v3 runtime rendering and session support", () => { base_url: "http://qdrant:6333", collection: "psd-clinical", }, + embeddings: { + provider: "ollama_internal", + base_url: "http://embedding:11434", + model: "qwen3-embedding:0.6b", + dimensions: 1024, + }, }); - expect(rendered.embeddings).toMatchObject({ - provider: "ollama_internal", - base_url: "http://embedding:11434", - model: "qwen3-embedding:0.6b", - dimensions: 1024, - }); + expect(rendered).not.toHaveProperty("embeddings"); }); test("schema v3 runtime rendering never exposes external semantic endpoints from bindings", () => { @@ -227,12 +228,13 @@ test("schema v3 runtime rendering never exposes external semantic endpoints from base_url: "http://qdrant:6333", collection: "psd-clinical", }); - expect(rendered.embeddings).toMatchObject({ + expect(rendered.resources.embeddings).toMatchObject({ provider: "ollama_internal", base_url: "http://embedding:11434", model: "qwen3-embedding:0.6b", dimensions: 1024, }); + expect(rendered).not.toHaveProperty("embeddings"); expect(JSON.stringify(rendered)).not.toContain("vector.example.test"); expect(JSON.stringify(rendered)).not.toContain("embedding.example.test"); });