import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { parse } from "yaml"; import { expect, test } from "vitest"; import * as workspaceSchema from "../src/workspaces/schema.js"; import { parseWorkspaceYaml, serializeWorkspaceYaml, validateWorkspaceDescriptor, } from "../src/workspaces/schema.js"; export const validYaml = `workspace: schema_version: 3 id: psd-clinical name: Policlinico San Donato description: Clinical data warehouse workspace language: it dwh: engine: postgres database: postgres schema: datawarehouse port: 5432 timeout_ms: 5000 supported_transports: - postgres_direct - rest_api - ssh_tunnel semantic_index: vector_store: engine: qdrant collection: psd-clinical dimensions: 1024 distance: cosine embedding: provider: ollama_internal model: qwen3-embedding:0.6b dimensions: 1024 llm_policy: default: zai/glm-5.2 allowed: - zai/glm-5.2 - openai/gpt-5 `; test("rejects a workspace whose embedding dimensions differ from its collection", () => { expect(() => parseWorkspaceYaml(validYaml.replace("dimensions: 1024", "dimensions: 1536"))) .toThrow(/dimensions/i); }); test("rejects an LLM default outside its allowlist", () => { expect(() => parseWorkspaceYaml(validYaml.replace("- zai/glm-5.2", "- openai/gpt-5"))) .toThrow(/allowlist/i); }); test("rejects unknown keys and invalid immutable IDs", () => { expect(() => parseWorkspaceYaml(validYaml.replace(" language: it", " language: it\n label: PSD"))) .toThrow(/unrecognized key/i); expect(() => parseWorkspaceYaml(validYaml.replace("id: psd-clinical", "id: PSD"))) .toThrow(/id/i); }); test("rejects executable or otherwise custom YAML tags in canonical descriptors", () => { expect(() => parseWorkspaceYaml(validYaml.replace( "name: Policlinico San Donato", "name: !command echo-never-execute", ))).toThrow(/tag|yaml/i); }); test("accepts optional connection ports and timeouts but rejects unsafe values", () => { expect(parseWorkspaceYaml(validYaml).dwh.port).toBe(5432); expect(() => parseWorkspaceYaml(validYaml.replace("port: 5432", "port: 0"))) .toThrow(/port/i); expect(() => parseWorkspaceYaml(validYaml.replace("port: 5432", "port: 65536"))) .toThrow(/port/i); expect(() => parseWorkspaceYaml(validYaml.replace("timeout_ms: 5000", "timeout_ms: 0"))) .toThrow(/timeout/i); expect(() => parseWorkspaceYaml(validYaml.replace("dimensions: 1024", "dimensions: 2048"))) .toThrow(/1024|dimensions/i); }); test("accepts only the schema v3 internal qdrant semantic shape", () => { expect(parseWorkspaceYaml(validYaml)).toMatchObject({ workspace: { schema_version: 3, id: "psd-clinical" }, semantic_index: { vector_store: { engine: "qdrant", collection: "psd-clinical", dimensions: 1024, distance: "cosine", }, embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024, }, }, }); }); test("committed example descriptors parse as exact schema v3 workspaces", () => { const example = readFileSync(resolve(process.cwd(), "../deploy/workspaces/example.yaml"), "utf8"); const psdExample = readFileSync(resolve(process.cwd(), "../deploy/workspaces/psd.yaml.example"), "utf8"); expect(() => parseWorkspaceYaml(example)).not.toThrow(); expect(() => parseWorkspaceYaml(psdExample)).not.toThrow(); expect(parseWorkspaceYaml(example)).toMatchObject({ workspace: { schema_version: 3 }, semantic_index: { vector_store: { engine: "qdrant", distance: "cosine", dimensions: 1024 }, embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024 }, }, }); expect(parseWorkspaceYaml(psdExample)).toMatchObject({ workspace: { schema_version: 3 }, semantic_index: { vector_store: { engine: "qdrant", distance: "cosine", dimensions: 1024 }, embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024 }, }, }); }); test("rejects pgvector semantic stores in schema v3", () => { expect(() => parseWorkspaceYaml(validYaml.replace("engine: qdrant", "engine: pgvector"))) .toThrow(/qdrant|pgvector/i); }); test("rejects supported_transports inside schema v3 semantic identity", () => { const withTransport = validYaml.replace( " distance: cosine\n", " distance: cosine\n supported_transports:\n - rest_api\n", ); expect(() => parseWorkspaceYaml(withTransport)).toThrow(/unrecognized key|supported_transports/i); }); test("rejects external embedding providers in schema v3", () => { expect(() => parseWorkspaceYaml(validYaml.replace("provider: ollama_internal", "provider: openai_compatible"))) .toThrow(/ollama_internal|provider/i); }); test("rejects non-cosine distance in schema v3", () => { expect(() => parseWorkspaceYaml(validYaml.replace("distance: cosine", "distance: l2"))) .toThrow(/cosine|distance/i); }); test("rejects unknown fields in schema v3 semantic identity", () => { const withUnknownField = validYaml.replace( " collection: psd-clinical\n", " collection: psd-clinical\n namespace: psd\n", ); expect(() => parseWorkspaceYaml(withUnknownField)).toThrow(/unrecognized key/i); }); test("rejects legacy semantic connector fields and diagnostics in schema v3", () => { expect(() => parseWorkspaceYaml(validYaml.replace( " collection: psd-clinical\n", " collection: psd-clinical\n database: postgres\n", ))).toThrow(/unrecognized key|database/i); expect(() => parseWorkspaceYaml(validYaml.replace( "llm_policy:\n", "diagnostics:\n vector_rest:\n metadata:\n method: GET\n path: /metadata\n auth: bearer\n response:\n collection: collection\n dimensions: dimensions\n distance: distance\nllm_policy:\n", ))).toThrow(/unrecognized key|vector_rest/i); }); test.each([ ["v1", `workspace: schema_version: 1 id: psd-clinical name: Policlinico San Donato language: it dwh: engine: postgres database: postgres schema: datawarehouse supported_transports: - postgres_direct semantic_index: vector_store: engine: pgvector collection: clinical_documents dimensions: 1024 distance: cosine supported_transports: - pgvector_direct embedding: provider: ollama_compatible model: nomic-embed-text-v2-moe dimensions: 1024 llm_policy: allowed: - zai/glm-5.2 `], ["v2", `workspace: schema_version: 2 id: psd-clinical name: Policlinico San Donato language: it dwh: engine: postgres database: postgres schema: datawarehouse supported_transports: - postgres_direct semantic_index: vector_store: engine: pgvector database: postgres schema: vectors collection: clinical_documents dimensions: 1024 distance: cosine supported_transports: - pgvector_direct embedding: provider: ollama_compatible model: nomic-embed-text-v2-moe dimensions: 1024 llm_policy: allowed: - zai/glm-5.2 `], ])("rejects schema %s descriptors at parser and object-validator boundaries", (_version, yaml) => { expect(() => parseWorkspaceYaml(yaml)).toThrow(/schema_version|invalid literal|3/i); expect(() => validateWorkspaceDescriptor(parse(yaml))).toThrow(/schema_version|invalid literal|3/i); }); test("does not expose the redundant canonical validator or v1 migration", () => { const legacyExports = workspaceSchema as Record; expect(legacyExports.validateCanonicalWorkspace).toBeUndefined(); expect(legacyExports.migrateWorkspaceV1ToV2).toBeUndefined(); }); test("constructs diagnostic URLs only when the resolved URL remains on the service origin", () => { const resolveDiagnosticUrl = (workspaceSchema as { resolveDiagnosticUrl?: unknown }).resolveDiagnosticUrl; expect(resolveDiagnosticUrl).toBeTypeOf("function"); expect((resolveDiagnosticUrl as (baseUrl: string, path: string) => URL)("https://service.example/base", "/rpc/ping")) .toMatchObject({ href: "https://service.example/base/rpc/ping" }); expect(() => (resolveDiagnosticUrl as (baseUrl: string, path: string) => URL)( "https://service.example/base", "//diagnostic.invalid/rpc", )).toThrow(/origin/i); }); test("rejects REST diagnostic declarations without their matching connector transport", () => { const diagnostics = `diagnostics: dwh_rest: method: POST path: /rpc/ping auth: bearer response: database: database schema: schema llm_policy: `; const declared = validYaml.replace("llm_policy:\n", diagnostics); expect(() => parseWorkspaceYaml(declared.replace(" - rest_api\n", ""))).toThrow(/dwh_rest/i); }); test("serializes canonical YAML that parses back to the same workspace", () => { const workspace = parseWorkspaceYaml(validYaml); const serialized = serializeWorkspaceYaml(workspace); expect(serializeWorkspaceYaml(parseWorkspaceYaml(serialized))).toBe(serialized); expect(parseWorkspaceYaml(serialized)).toEqual(workspace); }); function validWorkspaceObject(): Record { return parseWorkspaceYaml(validYaml) as Record; } function withEvidence(source: Record, policy?: Record): Record { const workspace = structuredClone(validWorkspaceObject()); workspace.evidence = policy === undefined ? { source } : { source, policy }; return workspace; } function expectSafeEvidenceError(workspace: unknown, path: RegExp, canary?: string): void { let message = ""; try { validateWorkspaceDescriptor(workspace); } catch (error) { message = error instanceof Error ? error.message : String(error); } expect(message.replace(/\s+/g, " ")).toMatch(path); if (canary !== undefined) expect(message).not.toContain(canary); } const explicitPolicy = { max_chunk_chars: 8_000, retain_published_generations: 5 }; const validEvidenceSources = [ { name: "filesystem with explicit values", source: { type: "filesystem", uri: "psd-clinical/evidence", patterns: ["documents/**/*.pdf", "notes/*.md"], max_bytes: 12_000_000, }, }, { name: "HTTP without authentication", source: { type: "http", uris: ["https://evidence.example/manifest.json", "http://evidence.example/files/list.txt"], authentication: "none", connect_timeout_ms: 2_000, read_timeout_ms: 20_000, max_bytes: 12_000_000, max_redirects: 2, allow_private_hosts: false, max_cache_bytes: 24_000_000, }, }, { name: "HTTP signed URL manifest", source: { type: "http", uris: ["https://evidence.example/signed-urls.txt"], authentication: "signed_urls_file", connect_timeout_ms: 2_000, read_timeout_ms: 20_000, max_bytes: 12_000_000, max_redirects: 2, allow_private_hosts: true, max_cache_bytes: 24_000_000, }, }, { name: "S3 with ambient credentials", source: { type: "s3", uri: "s3://clinical-evidence/published/", region: "eu-west-1", credentials: "ambient", trusted_endpoint: false, allow_private_endpoint: false, allow_insecure_endpoint: false, max_bytes: 12_000_000, max_objects: 2_000, max_pages: 20, page_size: 100, }, }, { name: "S3 with static-file credentials and a trusted endpoint", source: { type: "s3", uri: "s3://clinical-evidence/published/", endpoint_url: "https://objects.example", region: "eu-west-1", credentials: "static_files", trusted_endpoint: true, allow_private_endpoint: false, allow_insecure_endpoint: false, max_bytes: 12_000_000, max_objects: 2_000, max_pages: 20, page_size: 100, }, }, ] as const; test.each(validEvidenceSources)("accepts evidence source: $name", ({ source }) => { expect(validateWorkspaceDescriptor(withEvidence(source, explicitPolicy))).toMatchObject({ evidence: { source, policy: explicitPolicy }, }); }); test("applies filesystem and policy defaults to the canonical descriptor", () => { const parsed = validateWorkspaceDescriptor(withEvidence({ type: "filesystem", uri: "psd-clinical/evidence", })); expect(parsed).toMatchObject({ evidence: { source: { type: "filesystem", uri: "psd-clinical/evidence", patterns: ["**/*.md"], max_bytes: 10 * 1024 * 1024, }, policy: { max_chunk_chars: 4_000, retain_published_generations: 3 }, }, }); }); test("defaults schema-versioned filesystem Evidence to curated documents only", () => { const parsed = validateWorkspaceDescriptor({ ...withEvidence({ type: "filesystem", uri: "psd-clinical/evidence", }), evidence: { schema_version: 2, source: { type: "filesystem", uri: "psd-clinical/evidence" }, }, }); expect(parsed.evidence).toMatchObject({ schema_version: 2, source: { patterns: ["curated/**/*.md"] }, }); }); test("rejects a schema-versioned Evidence layout that mixes source and curated runtime patterns", () => { expectSafeEvidenceError({ ...withEvidence({ type: "filesystem", uri: "psd-clinical/evidence", }), evidence: { schema_version: 2, source: { type: "filesystem", uri: "psd-clinical/evidence", patterns: ["source/**/*.md", "curated/**/*.md"], }, }, }, /source.*curated|curated.*source/i); }); test("rejects a schema-versioned Evidence layout that acquires source documents at runtime", () => { expectSafeEvidenceError({ ...withEvidence({ type: "filesystem", uri: "psd-clinical/evidence", }), evidence: { schema_version: 2, source: { type: "filesystem", uri: "psd-clinical/evidence", patterns: ["source/**/*.md"], }, }, }, /curated/i); }); test("keeps evidence optional on schema v3", () => { expect(validateWorkspaceDescriptor(validWorkspaceObject())).not.toHaveProperty("evidence"); }); test("serializes defaulted evidence canonically and parses it without loss", () => { const canonical = validateWorkspaceDescriptor(withEvidence({ type: "filesystem", uri: "psd-clinical/evidence", })); if (canonical.workspace.schema_version !== 3) throw new Error("expected schema v3"); expect(parseWorkspaceYaml(serializeWorkspaceYaml(canonical))).toEqual(canonical); }); const invalidFilesystemPaths = [ "/psd-clinical/evidence", "../psd-clinical/evidence", "./psd-clinical/evidence", "/psd-clinical/evidence", "psd-clinical/evidence/..", "\\psd-clinical\\evidence", "psd-clinical/evidence\u0000", "other-workspace/evidence", "psd-clinical", "psd-clinical/evidence/nested", ]; test.each(invalidFilesystemPaths)("rejects unsafe or noncanonical filesystem URI %#", (uri) => { expectSafeEvidenceError(withEvidence({ type: "filesystem", uri }), /evidence.*source.*uri/i); }); const invalidPatterns = ["", "/absolute", "../escape", ".", "folder/./file", "folder//file", "folder/../file", "a\\b", "a\u0007b"]; test.each(invalidPatterns)("rejects unsafe evidence glob %#", (pattern) => { expectSafeEvidenceError(withEvidence({ type: "filesystem", uri: "psd-clinical/evidence", patterns: [pattern], }), /evidence.*source.*patterns/i); }); test("rejects empty and duplicate filesystem patterns", () => { const source = { type: "filesystem", uri: "psd-clinical/evidence" }; expectSafeEvidenceError(withEvidence({ ...source, patterns: [] }), /patterns/i); expectSafeEvidenceError(withEvidence({ ...source, patterns: ["**/*.pdf", "**/*.pdf"] }), /patterns/i); }); test.each(["ftp", "git", "unknown"])("rejects unsupported evidence discriminator %s", (type) => { expectSafeEvidenceError(withEvidence({ type, uri: "psd-clinical/evidence" }), /evidence.*source.*type/i); }); test("rejects unknown evidence keys", () => { expectSafeEvidenceError({ ...withEvidence({ type: "filesystem", uri: "psd-clinical/evidence", }), evidence: { source: { type: "filesystem", uri: "psd-clinical/evidence", mystery: true }, policy: explicitPolicy, mystery: true, } }, /unrecognized|mystery/i); }); const credentialFields = [ "password", "api_key", "access_key", "secret_key", "session_token", "signed_url", "headers", "ca_contents", ]; test.each(credentialFields)("rejects credential-shaped evidence field %s without leaking it", (field) => { const canary = `CANARY-${field}-DO-NOT-LEAK`; expectSafeEvidenceError(withEvidence({ type: "filesystem", uri: "psd-clinical/evidence", [field]: canary, }), /evidence.*source/i, canary); }); const invalidHttpUris = [ "https://user:CANARY-HTTP@example.com/manifest", "https://example.com/manifest?token=CANARY-HTTP", "https://example.com/manifest#CANARY-HTTP", "ftp://example.com/manifest/CANARY-HTTP", "\nhttps://example.com/CANARY-HTTP", ]; test.each(invalidHttpUris)("rejects unsafe HTTP descriptor URI %# without leaking it", (uri) => { expectSafeEvidenceError(withEvidence({ type: "http", uris: [uri] }), /evidence.*source.*uris.*0/i, "CANARY-HTTP"); }); test("rejects empty and canonically duplicate HTTP manifests", () => { expectSafeEvidenceError(withEvidence({ type: "http", uris: [] }), /uris/i); expectSafeEvidenceError(withEvidence({ type: "http", uris: ["https://EXAMPLE.com:443/manifest", "https://example.com/manifest"], }), /uris/i); }); const invalidHttpBounds = [ ["connect_timeout_ms", 0], ["read_timeout_ms", 0], ["max_bytes", 0], ["max_redirects", -1], ["max_cache_bytes", 0], ["connect_timeout_ms", Number.MAX_SAFE_INTEGER + 1], ] as const; test.each(invalidHttpBounds)("rejects invalid HTTP bound %s=%s", (field, value) => { expectSafeEvidenceError(withEvidence({ type: "http", uris: ["https://example.com/manifest"], [field]: value, }), new RegExp(field, "i")); }); const invalidS3Uris = [ "https://bucket/prefix", "s3:///prefix", "s3://user:CANARY-S3@bucket/prefix", "s3://bucket/prefix?token=CANARY-S3", "s3://bucket/prefix#CANARY-S3", "s3://bucket:123/CANARY-S3", "s3://bucket/%2e%2e/CANARY-S3", "s3://127.0.0.1/CANARY-S3", "s3://UPPERCASE/CANARY-S3", ]; test.each(invalidS3Uris)("rejects invalid S3 URI %# without leaking it", (uri) => { expectSafeEvidenceError(withEvidence({ type: "s3", uri }), /evidence.*source.*uri/i, "CANARY-S3"); }); const invalidS3Endpoints = [ { endpoint_url: "ftp://objects.example", trusted_endpoint: true }, { endpoint_url: "https://user:CANARY-S3@objects.example", trusted_endpoint: true }, { endpoint_url: "https://objects.example/path", trusted_endpoint: true }, { endpoint_url: "https://objects.example?token=CANARY-S3", trusted_endpoint: true }, { endpoint_url: "https://objects.example#CANARY-S3", trusted_endpoint: true }, { endpoint_url: "https://objects.example", trusted_endpoint: false }, { endpoint_url: "http://objects.example", trusted_endpoint: true, allow_insecure_endpoint: false }, { endpoint_url: "HTTP://objects.example", trusted_endpoint: true, allow_insecure_endpoint: false }, { trusted_endpoint: true }, { allow_private_endpoint: true }, { allow_insecure_endpoint: true }, ]; test.each(invalidS3Endpoints)("rejects unsafe or inconsistent S3 endpoint %#", (endpoint) => { expectSafeEvidenceError(withEvidence({ type: "s3", uri: "s3://bucket/prefix", ...endpoint }), /evidence.*source/i, "CANARY-S3"); }); const invalidS3Bounds = [ ["max_bytes", 0], ["max_objects", 0], ["max_pages", 0], ["page_size", 0], ["max_objects", Number.MAX_SAFE_INTEGER + 1], ] as const; test.each(invalidS3Bounds)("rejects invalid S3 bound %s=%s", (field, value) => { expectSafeEvidenceError(withEvidence({ type: "s3", uri: "s3://bucket/prefix", [field]: value, }), new RegExp(field, "i")); }); test.each([ ["max_chunk_chars", 0], ["max_chunk_chars", Number.MAX_SAFE_INTEGER + 1], ["retain_published_generations", 0], ["retain_published_generations", Number.MAX_SAFE_INTEGER + 1], ] as const)("rejects invalid evidence policy bound %s=%s", (field, value) => { expectSafeEvidenceError(withEvidence({ type: "filesystem", uri: "psd-clinical/evidence", }, { ...explicitPolicy, [field]: value }), new RegExp(field, "i")); });