239 lines
7.6 KiB
TypeScript
239 lines
7.6 KiB
TypeScript
import { expect, test } from "vitest";
|
|
import * as workspaceSchema from "../src/workspaces/schema.js";
|
|
import {
|
|
parseWorkspaceYaml,
|
|
serializeWorkspaceYaml,
|
|
validateCanonicalWorkspace,
|
|
type WorkspaceDescriptor,
|
|
} 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("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("keeps v1 and v2 descriptors parseable but non-operational", () => {
|
|
const v1Yaml = `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
|
|
`;
|
|
const v2Yaml = `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
|
|
`;
|
|
|
|
const v1 = parseWorkspaceYaml(v1Yaml);
|
|
const v2 = parseWorkspaceYaml(v2Yaml);
|
|
const isOperationalWorkspace = (workspaceSchema as { isOperationalWorkspace?: unknown }).isOperationalWorkspace;
|
|
|
|
expect(v1.workspace.schema_version).toBe(1);
|
|
expect(v2.workspace.schema_version).toBe(2);
|
|
expect(validateCanonicalWorkspace(parseWorkspaceYaml(validYaml))).toMatchObject({
|
|
workspace: { schema_version: 3 },
|
|
});
|
|
expect(() => validateCanonicalWorkspace(v1)).toThrow(/schema version 3|migration/i);
|
|
expect(() => validateCanonicalWorkspace(v2)).toThrow(/schema version 3|migration/i);
|
|
expect(isOperationalWorkspace).toBeTypeOf("function");
|
|
expect((isOperationalWorkspace as (workspace: WorkspaceDescriptor) => boolean)(v1)).toBe(false);
|
|
expect((isOperationalWorkspace as (workspace: WorkspaceDescriptor) => boolean)(v2)).toBe(false);
|
|
});
|
|
|
|
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/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);
|
|
});
|