diff --git a/frontend/src/workspaces/drafts.test.ts b/frontend/src/workspaces/drafts.test.ts index 3d00e05f..0648e0ab 100644 --- a/frontend/src/workspaces/drafts.test.ts +++ b/frontend/src/workspaces/drafts.test.ts @@ -10,6 +10,12 @@ test("workspace module exposes validation and in-memory coordination but no draf expect(workspaceModule).not.toHaveProperty("workspaceDeletionDrafts"); }); +test("canonical sanitizer accepts schema-v4 workspaces without an authored dwh block", () => { + const { dwh: _catalogOwnedDwh, ...workspace } = canonicalWorkspaceFixture("psd-clinical"); + + expect(workspaceModule.sanitizeCanonicalWorkspace(workspace)).toEqual(workspace); +}); + test("canonical sanitizer rejects unknown fields rather than persisting them", () => { expect(workspaceModule.sanitizeCanonicalWorkspace({ ...canonicalWorkspaceFixture("psd-clinical"), diff --git a/frontend/src/workspaces/drafts.ts b/frontend/src/workspaces/drafts.ts index 999e50a3..99601e30 100644 --- a/frontend/src/workspaces/drafts.ts +++ b/frontend/src/workspaces/drafts.ts @@ -375,26 +375,48 @@ function copyDiagnostics(value: unknown): CanonicalDiagnostics | undefined { export function sanitizeCanonicalWorkspace(value: unknown): CanonicalWorkspace | undefined { const source = exactRecord(value, ["workspace", "dwh", "diagnostics", "evidence"]); const metadata = exactRecord(source?.workspace, ["schema_version", "id", "name", "description", "language"]); - const dwh = exactRecord(source?.dwh, ["engine", "database", "schema", "port", "timeout_ms", "supported_transports"]); const diagnostics = source?.diagnostics === undefined ? undefined : copyDiagnostics(source.diagnostics); - if (!metadata || !dwh) return undefined; + if (!metadata) return undefined; const id = workspaceId(metadata.id); const evidence = id && source?.evidence !== undefined ? copyEvidence(source.evidence, id) : undefined; const name = text(metadata.name); const language = oneOf(metadata.language, ["en", "it"] as const); const description = metadata.description === undefined ? undefined : text(metadata.description); - const database = identifier(dwh.database); - const schema = identifier(dwh.schema); - const dwhPort = dwh.port === undefined ? undefined : positiveInteger(dwh.port, 65_535); - const dwhTimeout = dwh.timeout_ms === undefined ? undefined : positiveInteger(dwh.timeout_ms); - const dwhTransports = uniqueChoices(dwh.supported_transports, ["postgres_direct", "rest_api", "ssh_tunnel"] as const); if ( - metadata.schema_version !== 4 || !id || !name || !language || (metadata.description !== undefined && !description) - || dwh.engine !== "postgres" || !database || !schema || (dwh.port !== undefined && !dwhPort) || (dwh.timeout_ms !== undefined && !dwhTimeout) || !dwhTransports + metadata.schema_version !== 4 || !id || !name || !language + || (metadata.description !== undefined && !description) ) return undefined; if (source?.diagnostics !== undefined && !diagnostics) return undefined; if (source?.evidence !== undefined && !evidence) return undefined; - if (diagnostics?.dwh_rest && !dwhTransports.includes("rest_api")) return undefined; + + let dwh: CanonicalWorkspace["dwh"]; + if (source?.dwh !== undefined) { + const rawDwh = exactRecord( + source.dwh, + ["engine", "database", "schema", "port", "timeout_ms", "supported_transports"], + ); + if (!rawDwh) return undefined; + const database = identifier(rawDwh.database); + const schema = identifier(rawDwh.schema); + const port = rawDwh.port === undefined ? undefined : positiveInteger(rawDwh.port, 65_535); + const timeout = rawDwh.timeout_ms === undefined ? undefined : positiveInteger(rawDwh.timeout_ms); + const transports = uniqueChoices( + rawDwh.supported_transports, + ["postgres_direct", "rest_api", "ssh_tunnel"] as const, + ); + if ( + rawDwh.engine !== "postgres" || !database || !schema || !transports + || (rawDwh.port !== undefined && !port) + || (rawDwh.timeout_ms !== undefined && !timeout) + ) return undefined; + dwh = { + engine: "postgres", database, schema, + ...(port ? { port } : {}), + ...(timeout ? { timeout_ms: timeout } : {}), + supported_transports: transports, + }; + } + if (diagnostics?.dwh_rest && !dwh?.supported_transports.includes("rest_api")) return undefined; return { workspace: { schema_version: 4, @@ -403,12 +425,7 @@ export function sanitizeCanonicalWorkspace(value: unknown): CanonicalWorkspace | ...(description ? { description } : {}), language, }, - dwh: { - engine: "postgres", database, schema, - ...(dwhPort ? { port: dwhPort } : {}), - ...(dwhTimeout ? { timeout_ms: dwhTimeout } : {}), - supported_transports: dwhTransports, - }, + ...(dwh ? { dwh } : {}), ...(diagnostics ? { diagnostics } : {}), ...(evidence ? { evidence } : {}), };